導(dǎo)語(yǔ) | 云函數(shù)SCF是騰訊云為企業(yè)和開(kāi)發(fā)者們提供的無(wú)服務(wù)器執(zhí)行環(huán)境,幫助大家在無(wú)需購(gòu)買(mǎi)和管理服務(wù)器的情況下運(yùn)行代碼。但是SCF在使用過(guò)程中經(jīng)常會(huì)受到開(kāi)發(fā)語(yǔ)言方面的限制,造成拓展性和成本上的問(wèn)題。本文就將為大家介紹使用Custom Runtime來(lái)解鎖SCF語(yǔ)言限制,希望與大家一同交流。文章作者:臧琳,騰訊云Serverless 研發(fā)工程師。
一、背景
SCF作為騰訊云FaaS核心產(chǎn)品,支持javascript、python、php、java、go等多語(yǔ)言函數(shù)。但是,在用戶(hù)實(shí)際使用過(guò)程中,我們發(fā)現(xiàn)了一些問(wèn)題:
1.尋求更多語(yǔ)言支持
我們時(shí)常會(huì)收到來(lái)自?xún)?nèi)外的各種關(guān)于編程語(yǔ)言的咨詢(xún),比如SCF是否支持dotnet、rust、deno甚至C等多種語(yǔ)言環(huán)境。
2.關(guān)于現(xiàn)有語(yǔ)言的功能拓展
比如php想要安裝更多的插件,就需要在執(zhí)行環(huán)境中使用phpize來(lái)安裝(因?yàn)椴糠植寮赡芎蚾s library等底層庫(kù)相關(guān)),但是云函數(shù)因?yàn)榘踩仍?,限制了相關(guān)權(quán)限。
3.關(guān)于Runtime的拓展性
舉個(gè)例子,現(xiàn)有SCF java的語(yǔ)言環(huán)境是java8,如果用戶(hù)想要在SCF中使用JDK11或者更新的JDK15,有沒(méi)有辦法解決呢?
4.使用成本
目前,用戶(hù)如果想要在自己的業(yè)務(wù)代碼中嵌入SCF,需要了解SCF各個(gè)語(yǔ)言提供的入口函數(shù)及編程方法。雖然我們已經(jīng)盡量將使用方法和接口設(shè)計(jì)得簡(jiǎn)單,但對(duì)于一些用戶(hù)來(lái)說(shuō),仍然要處理編程語(yǔ)言上的接口依賴(lài),以及學(xué)習(xí)如何正確使用這些接口A(yíng)PI。
5.維護(hù)成本
簡(jiǎn)單來(lái)說(shuō),如果復(fù)用現(xiàn)有方案,給SCF提供多語(yǔ)言支持其實(shí)是可行的,但是需要給每一種語(yǔ)言編寫(xiě)一套使用SCF的API。這不僅僅需要SCF研發(fā)同學(xué)懂得各種語(yǔ)言,還需要他們了解各個(gè)語(yǔ)言的安全特性,使用特性等,維護(hù)成本很高。
那么,有沒(méi)有一種方法能夠讓我們只需要維護(hù)一套統(tǒng)一的API,就能讓用戶(hù)從各種編程語(yǔ)言中解耦,還能解決上述列舉的各項(xiàng)問(wèn)題呢?答案就在于使用——Custom Runtime。
二、Custom Runtime簡(jiǎn)介
Custom Runtime(以下簡(jiǎn)稱(chēng)CR)使用方法較為簡(jiǎn)單:CR會(huì)暴露一套HTTP API提供給用戶(hù)環(huán)境,而用戶(hù)只需要到特定端口上發(fā)送/接收HTTP請(qǐng)求,即可以獲得SCF下發(fā)的各種event,并返回處理結(jié)果。具體的文檔可以參考:Custom Runtime說(shuō)明[1]。
總體來(lái)說(shuō),要使用Custom Runtime,用戶(hù)需要做好以下準(zhǔn)備:
1.bootstrap可執(zhí)行程序
此執(zhí)行程序可以是任何形式的Linux可執(zhí)行文件,比如C語(yǔ)言編譯出的二進(jìn)制文件,或者是一個(gè)簡(jiǎn)單的shell腳本。
2.用戶(hù)的事件處理函數(shù)
也就是通過(guò)CR約定的HTTP API實(shí)現(xiàn)event的獲得和處理,以及結(jié)果返回。
3.用戶(hù)語(yǔ)言Runtime(可選)
針對(duì)解釋型語(yǔ)言,或者是需要Runtime來(lái)運(yùn)行的語(yǔ)言,比如js、python、dotnet等,需要用戶(hù)提供自己的Runtime,并在bootstrap中提供相應(yīng)的啟動(dòng)Runtime的命令。
騰訊云官網(wǎng)上也提供了利用CR實(shí)現(xiàn)shell云函數(shù)的示例[2],有興趣的小伙伴可以看看。
三、Custom Runtime具體模型及用法示例
Custom Runtime函數(shù)的內(nèi)部處理流程如下所示:
目前Custom Runtime的實(shí)現(xiàn)在SCF側(cè)是一個(gè)HTTP Server。用戶(hù)側(cè)代碼作為HTTP Client通過(guò)約定的API給SCF發(fā)請(qǐng)求來(lái)獲得事件及相關(guān)信息,并發(fā)送HTTP請(qǐng)求返回處理結(jié)果給SCF服務(wù)。
HTTP Server端口號(hào)和URL,通過(guò)兩個(gè)環(huán)境變量傳遞到云函數(shù)環(huán)境中:
SCF_RUNTIME_API:SCF_RUNTIME_API_PORT
HTTP API定義如下圖所示:
1.冷啟動(dòng)階段(函數(shù)部署階段)
冷啟動(dòng)階段主要是部署用戶(hù)代碼,完成用戶(hù)初始化,這個(gè)階段SCF會(huì)在用戶(hù)提供的程序包(zip包)中尋找bootstrap可執(zhí)行程序,然后拉起該程序。bootstrap由用戶(hù)實(shí)現(xiàn),內(nèi)部啟動(dòng)用戶(hù)代碼等工作。
用戶(hù)函數(shù)在冷啟動(dòng)階段需要完成代碼初始化工作,并通知SCF,初始化工作完成。即發(fā)POST到SCF_RUNTIME_API:SCF_RUNTIME_API_PORT/runtime/init/ready.
SCF服務(wù)側(cè)接收用戶(hù)ready的請(qǐng)求,初始化工作結(jié)束,通知上層服務(wù)。函數(shù)進(jìn)入調(diào)用流程(即event此時(shí)可以下發(fā)到函數(shù)側(cè))。
2.熱啟動(dòng)階段(調(diào)用階段)
函數(shù)通過(guò)GET SCF_RUNTIME_API:SCF_RUNTIME_API_PORT/runtime/invocation/next獲得event及相關(guān)ctx信息。
SCF在函數(shù)拉取event之后,等待用戶(hù)函數(shù)返回。
函數(shù)處理event之后,如正常返回,通過(guò)POST SCF_RUNTIME_API:SCF_RUNTIME_API_PORT/runtime/invocation/response傳遞返回信息給SCF服務(wù)。
如函數(shù)調(diào)用出現(xiàn)異常(此處指業(yè)務(wù)代碼需要返回錯(cuò)誤信息),則通過(guò)POST SCF_RUNTIME_API:SCF_RUNTIME_API_PORT/runtime/invocation/error返回錯(cuò)誤信息。
SCF服務(wù)傳遞返回給上層服務(wù),函數(shù)一次調(diào)用結(jié)束,進(jìn)入下一次event調(diào)用周期。
這里我們用SCF中CustomRuntime的Deno模板示例做說(shuō)明,如下圖所示,程序包里有:
·bootstrap:入口文件,這里是shell,可以看到紅線(xiàn)標(biāo)注這一行就是啟動(dòng)deno程序;
·deno二進(jìn)制:Deno Runtime,啟動(dòng)deno程序必須的launcher;
·demo.ts:用戶(hù)函數(shù),里面就實(shí)現(xiàn)了上面提到的和SCF服務(wù)端交互的邏輯,也是用戶(hù)業(yè)務(wù)邏輯的主要處理函數(shù)。
bootstrap主要是啟動(dòng)demo.ts,下面我們看看demo.ts里的代碼實(shí)現(xiàn):
可以看到,主要是完成初始化階段。下面再來(lái)看看調(diào)用是怎么完成的:
可以看到,是通過(guò)GET(fetch)循環(huán)拉取event,然后調(diào)用processEvent()來(lái)進(jìn)行處理。processEvent()邏輯如下所示:
分別處理正常返回和錯(cuò)誤返回。最后再來(lái)看一下我們是怎么封裝這里的postData()函數(shù)的:
以上就是一個(gè)Deno函數(shù)使用SCF的Custom Runtime實(shí)現(xiàn)云函數(shù)的全過(guò)程。
四、結(jié)語(yǔ)
從上文的論述我們不難看出:
1.SCF與語(yǔ)言無(wú)關(guān)
因?yàn)镃R的使用與語(yǔ)言無(wú)關(guān),所以解鎖了SCF的語(yǔ)言限制,也就是說(shuō)只要可以實(shí)現(xiàn)一個(gè)HTTP Client,就可以通過(guò)HTTP API的調(diào)用和SCF進(jìn)行交互,從而完成云函數(shù)的事件處理及調(diào)用。
2.bootstrap是入口
舉個(gè)例子,如果我用C語(yǔ)言實(shí)現(xiàn)一個(gè)HTTP Client,按照CR的約定完成與SCF的交互,那么完全可以編譯成一個(gè)名字叫bootstrap的二進(jìn)制文件,然后就可以跑C的FaaS函數(shù)了。
3.bootstrap可配置
用戶(hù)可以在bootstrap里面啟動(dòng)多個(gè)進(jìn)程,可以解鎖多種玩法,當(dāng)然,要符合安全,畢竟用戶(hù)函數(shù)運(yùn)行環(huán)境有安全限制。但是,這已經(jīng)可以解決一些“云函數(shù)+agent進(jìn)程”的需求。
4.使用簡(jiǎn)單
相對(duì)于學(xué)習(xí)各個(gè)語(yǔ)言的函數(shù)編寫(xiě)規(guī)范,了解云函數(shù)對(duì)各個(gè)語(yǔ)言的支持。使用CR只需要學(xué)習(xí)HTTP API的使用即可。更多的語(yǔ)言,環(huán)境相關(guān)的問(wèn)題都是用戶(hù)在業(yè)務(wù)開(kāi)發(fā)中使用到的,不需要額外學(xué)習(xí)。
Custom Runtime剛剛上線(xiàn),已經(jīng)得到了一些外網(wǎng)客戶(hù)的關(guān)注。比如,有人用Custom Runtime把Swift放到了SCF里面,并做了相應(yīng)的支持[3];有人用Custom Runtime在SCF中跑了WASM,并在上面做了Rust語(yǔ)言的支持[4]。
還有很多類(lèi)似場(chǎng)景,我們也在不斷的努力,引入更多的語(yǔ)言,借助語(yǔ)言的生態(tài),帶動(dòng)Serverless的生態(tài)發(fā)展。最后,歡迎大家體驗(yàn)SCF Custom Runtime,留下寶貴的意見(jiàn)!
參考資料:
[1]Custom Runtime說(shuō)明:
https://cloud.tencent.com/document/product/583/47274
[2]官網(wǎng)示例:
https://cloud.tencent.com/document/product/583/47610
[3]場(chǎng)景拓展1:
https://github.com/stevapple/swift-tencent-scf-runtime
[4]場(chǎng)景拓展2:
https://www.freecodecamp.org/news/rust-webassembly-serverless-tencent-cloud/
One More Thing