您好,登錄后才能下訂單哦!
如何進行云函數SCF Node.js Runtime實踐,很多新手對此不是很清楚,為了幫助大家解決這個難題,下面小編將為大家詳細講解,有這方面需求的人可以來學習下,希望你能有所收獲。
騰訊云云函數 SCF 最近新發布了 Node.js 12.16 的 runtime,也是國內首家支持 Node.js 12.x 的主流云服務商。
Node.js 版本的升級帶來了新的特性以及性能方面的提升,有興趣的同學可以參考國外一博主總結的文章《Node.js 12: The future of server-side JavaScript》了解具體內容。
其中比較重要的一點是啟動速度提升,通過 v8 code cache
的支持,構建時提前為內置庫生成代碼緩存,提升 30% 的啟動耗時。
騰訊云云函數 SCF 為了讓 Serverless 更加符合 Node.js 原生的使用體驗,針對 Node.js runtime 做了針對性的優化。 借這個機會,我想和大家分享一下如何使用騰訊云云函數來開發 Node.js 應用以及 scf 的 Node.js runtime 實現的原理。
首先我們看一下最基本的 Node.js 入口函數:
exports.main_handler = (event, context, callback) => { console.log("Hello World"); console.log(event); console.log(context); callback(null, event); };
runtime 會將三個參數傳遞到處理程序方法。
包含來自調用程序的信息。調用程序在調用時將該信息作為 JSON 格式字符串傳遞,事件結構因服務而異。
定時觸發器的 event 對象就包括了觸發的時間,觸發器的名稱 {Message: "", Time: "2020-05-08T14:30:00Z", TriggerName: "time_5", Type: "Timer"}
apigateway 觸發器的 event 對象透傳了 http 請求的完整內容以及 apigateway 定制化的 http 請求頭部信息
{"headerParameters":{},"headers":{...},"httpMethod":"GET","path":"/params_log","pathParameters":{},"queryString":{},"queryStringParameters":{},"requestContext":{"httpMethod":"ANY","identity":{},"path":"/params_log","serviceId":"service-9khp96qy","sourceIp":"120.229.9.165","stage":"release"}}
cos 觸發器的 event 對象包括了觸發執行的具體 cos 操作以及 cos 對象
{"Records":[{"cos":{"cosBucket":{"appid":"1251133793","name":"test","region":"gz"},"cosNotificationId":"unkown","cosObject":{"key":"/1251133793/test/xxx.png","meta":{"Content-Type":"image/png","x-cos-request-id":"NWViNTZmMmFfOTJhODQwYV80MGZmXzI0Y2ZkYmM="},"size":6545739,"url":"...","vid":""},"cosSchemaVersion":"1.0"},"event":{"eventName":"cos:ObjectCreated:Put","eventQueue":"qcs:0:scf:ap-guangzhou:appid/1251133793:default.params_log.$DEFAULT","eventSource":"qcs::cos","eventTime":1588948779,"eventVersion":"1.0","reqid":1038862404,"requestParameters":{"requestHeaders":{"Authorization":"..."},"requestSourceIP":"120.229.9.165"},"reservedInfo":""}}]}
我們來看一下一個完整的 context 包含的內容:
callbackWaitsForEmptyEventLoop: true, getRemainingTimeInMillis: 200, memory_limit_in_mb: 128, time_limit_in_ms: 3000, environment: "{"SCF_NAMESPACE":"demo","TENCENTCLOUD_SECRETID":"...","TENCENTCLOUD_SECRETKEY":"...","TENCENTCLOUD_SESSIONTOKEN":"..."}" function_name: "params", function_version: "$LATEST", namespace: "demo", request_id: "ab42b693-8bfd-4dc1-b228-60360a63e06c", tencentcloud_appid: "...", tencentcloud_region: "ap-chengdu", tencentcloud_uin: "..."
從上面的內容可以看到,該對象包含的內容有:
函數配置信息,比如設置的內容大小,超時時間等
執行身份認證信息。如果設置了函數的運行角色(角色必須要包含對應操作的授權策略),在環境變量中會注入 secretId,secretKey,sessionToken,在訪問第三方云服務,比如 cos、自定義監控數據上報時就可以使用這幾個值直接調用云 api,而不用在代碼里面去 hard code 各種密鑰信息
環境變量:包括了用戶自定義的環境變量以及一些系統環境變量
執行環境基本信息:包括了當前函數調用的地域,用戶的 appId,uin
回調函數采用兩個參數:一個 Error 和一個返回。返回對象必須與 JSON.stringify
兼容。異步函數將忽略 callback 的返回,必須通過 return、throw exception 或者 promise 來處理返回或錯誤
const https = require('https') let url = "https://cloud.tencent.com/" exports.main_handler = function(event, context, callback) { https.get(url, (res) => { callback(null, res.statusCode) }).on('error', (e) => { callback(Error(e)) }) }
我們來看一下,針對異步場景(async 函數)和非異步場景,云函數怎么把返回值傳遞出去
對于異步函數,可以使用 return 和 throw 來發送返回或錯誤。函數必須使用 async 關鍵字。在異步函數中,第三個參數 callback 沒有定義
示例:異步函數
const https = require('https') let url = "https://cloud.tencent.com/" const httpRequest = url => { const promise = new Promise(function(resolve, reject) { https .get(url, res => { resolve(res.statusCode) }) .on('error', e => { reject(Error(e)) }) }) return promise } exports.handler = async function(event, context) { try{ const result = await httpRequest(url) // 在async函數中callback未定義 // callback(null, result) return result }catch(e) { throw e } }
還是上面的例子,發起一個 http 請求,如果用同步函數實現,參照以下示例
示例:同步函數,callback 返回
const https = require('https') let url = "https://cloud.tencent.com/" exports.handler = function(event, context, callback) { https.get(url, (res) => { // 只能通過callback返回,return會被忽略 callback(null, res.statusCode) }).on('error', (e) => { callback(Error(e)) }) }
正常的 Node.js web framework 在 response 返回后,異步邏輯還是繼續在執行的。而 Serverless 場景下,由于機制和 framework的差別,對于已經返回 responese 的情況,一種是等著異步都處理完再來返回,這樣保證了一次調用的完整性。另外一種就是在返回后就直接結束當次調用,直接掛起異步處理。
騰訊云云函數針對 Node.js 的異步場景,實現了返回和結束分離的特殊機制。
入口函數的同步執行過程完成及返回后,云函數的調用將立刻返回,并將代碼的返回信息返回給函數調用方
同步流程處理并返回后,代碼中的異步邏輯可以繼續執行和處理,直到異步事件執行完成后,云函數的實際執行過程才完成和退出。
默認情況下,函數執行會等待所有異步執行結束才算一次調用結束,但也給用戶提供了關閉事件循環等待的選項,用戶可以關閉事件循環等待來自行控制函數的返回時機。通過在 callback 回調執行前設置 context.callbackWaitsForEmptyEventLoop = false
,可以使云函數在執行返回后立刻凍結進程,不再等待異步循環內的事件
比如一下示例代碼,代碼里面發起了一個異步 http 請求,另外有一個 2s 后執行的 setTimeout
const https = require('https') let url = "https://cloud.tencent.com/" const httpRequest = url => { const promise = new Promise(function(resolve, reject) { https .get(url, res => { resolve(res.statusCode) }) .on('error', e => { reject(Error(e)) }) }) return promise } exports.main_handler = async function(event, context) { // 設置該選項為false會不等待異步隊列執行完,而是在返回后直接凍結process //context.callbackWaitsForEmptyEventLoop = false try{ const result = await httpRequest(url) setTimeout(() => { console.log('timeout log') }, 2000) return result }catch(e) { throw e } }
在 http 請求完成后,會立即返回給調用方,不會等待 setTimeout 的異步實踐執行完。而在返回后,程序會繼續執行,直到 setTimeout 的事件執行完才算本次調用結束。
在設置了 context.callbackWaitsForEmptyEventLoop = false
后,在 return 后進程會被凍結,setTimeout 里面的執行邏輯會被掛起
以下是單實例內 runtime 運行的完整流程圖
針對 Node.js應用,有以下幾個實踐建議:
日志:runtime重寫了 console 的幾個主要方法,而且是在 require 用戶文件之后,所以用戶自定義日志選項會無效
緩存復用:在入口函數外可以定義變量,存儲可以復用的緩存對象,比如數據庫的連接等 Node.js 的模塊實現邏輯中,如果一個 module 被 require 過,該模塊就會被 cache 到內存中,再次被 require時不會重新初始化。針對這一特性,如果實例一直再復用,那么在入口文件中,入口函數外定義的變量都不會被銷毀,可以達到復用的效果
內置部分 npm 包,可以直接使用,具體參照文檔。部署云函數代碼時推薦 npm install --production
,減少代碼包的體積,提升上傳速度和執行速度
執行角色:配置執行角色,從 context 中可以獲取臨時的密鑰信息,可以用了訪問有相應權限的第三方服務,而不用在代碼內寫死密鑰信息
看完上述內容是否對您有幫助呢?如果還想對相關知識有進一步的了解或閱讀更多相關文章,請關注億速云行業資訊頻道,感謝您對億速云的支持。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。