Function Compute基於執行個體生命週期增加多種回調操作,有效解決傳統應用遷移至Serverless架構時遇到的指標資料延遲或丟失等痛點。本文介紹Function Compute的運行時擴充功能原理、如何配置PreFreeze和PreStop回呼函數及回呼函數日誌查詢。
背景資訊
傳統應用遷移Serverless架構的痛點
傳統常駐的虛擬機器或者託管容器類服務通常從執行個體啟動到結束作為計費區間,即使該時間段沒有業務請求仍納入計費。Function Compute提供1 ms計費粒度,且只在有實際請求的區間內計費,在請求以外的時間段內執行個體會被冷凍。這樣基本消除了完全事件驅動的計費模型的閑置成本。然而冷凍機制也會打破一些傳統架構下long-running進程的假設,加大應用遷移的難度。由於Function Compute擁有特殊的運行環境,面對沒有冷啟動的情境,例如常用的開源分布式鏈路追蹤Tracing Analysis庫和第三方APM解決方案等,將無法追蹤並正確上報其資料。
阻礙傳統應用平滑遷移至Serverless架構的痛點如下。
非同步背景指標資料延遲或丟失:如果在請求期間沒有發送成功,則可能被延遲至下一次請求,或者資料點被丟棄。
同步發送指標增加延遲:如果在每個請求結束後都調用類似Flush介面,不僅增加了每個請求的延遲,對於後端服務也產生了不必要的壓力。
函數優雅下線受阻:執行個體關閉時應用有清理串連、關閉進程、上報狀態等需求。在Function Compute中執行個體的下線時機開發人員無法掌握,也缺少Webhook通知函數執行個體下線事件。
Function Compute編程模型擴充
Function Compute針對上述痛點發布了運行時擴充(Runtime Extensions)功能。該功能在現有的HTTP服務編程模型上擴充,在已有的HTTP伺服器的模型中增加了PreFreeze和PreStop Webhooks,擴充開發人員實現HTTP handler,監聽函數執行個體生命週期事件。
PreFreeze
在每次Function Compute服務決定冷凍當前函數執行個體前,Function Compute服務會調用HTTP GET /pre-freeze路徑,擴充開發人員負責實現相應邏輯以確保完成執行個體冷凍前的必要操作,例如等待指標發送成功等。函數調用InvokeFunction的時間不包含PreFreeze hook的執行時間。
PreStop
在每次Function Compute決定停止當前函數執行個體前,Function Compute服務會調用HTTP GET /pre-stop路徑,擴充開發人員負責實現相應邏輯以確保完成執行個體釋放前的必要操作,如關閉資料庫連結,以及上報、更新狀態等。
前提條件
已完成函數的建立,具體請參見建立函數。
使用限制
PreFreeze和PreStop回呼函數輸入參數沒有event參數。
PreFreeze和PreStop回呼函數無傳回值,在函數末尾增加返回邏輯無效。
所有Runtime均支援配置PreStop回呼函數;Python、PHP及C# Runtime不支援配置PreFreeze回呼函數。
如果使用Java Runtime,您需要將fc-java-core更新至1.4.0及以上版本,否則無法使用PreFreeze和PreStop擴充回呼函數。具體操作,請參見HTTP請求處理常式(HTTP Handler)。
如果您使用的是非Web Server模式的Custom Container Runtime,則配置的PreFreeze和PreStop回調無效。
當函數執行返回時,Function Compute將凍結函數執行個體,使用者不可假設調用返回時所有非同步進程、線程、協程等執行完成,也不可假設本次非同步寫入的日誌被重新整理。
配置PreFreeze和PreStop回調
喚起PreFreeze或PreStop中產生的費用計費方式與InvokeFunction計費方式一致。具體資訊,請參見計費說明。
通過控制台配置回調
當您使用控制台建立函數時,Function Compute不支援您配置PreFreeze及PreStop回調,您需要在更新函數時配置該回呼函數。
- 登入Function Compute控制台,在左側導覽列,單擊服務及函數。
- 在頂部功能表列,選擇地區,然後在服務列表頁面,單擊目標服務。
- 在函數管理頁面,單擊目標函數操作列的配置。
在編輯函數配置頁面的執行個體生命週期回調地區,設定回調程式與逾時時間,然後單擊儲存。
說明每一個擴充函數都需要配置單獨的回調程式和逾時時間,其中回調程式格式為[檔案名稱].[擴充函數名]。例如在Python Runtime中,建立函數時指定的PreStop回調為index.preStopHandler,那麼檔案名稱為index.py,PreStop函數名為preStopHandler。
配置擴充函數後,您需要在代碼執行中實現對應的函數。
單擊函數代碼頁簽,在代碼編輯地區,輸入擴充函數代碼。
例如,您配置的PreStop回調程式為
index.preStopHandler
,則需要實現preStopHandler函數。不同語言運行時實現函數執行個體生命週期回調的方法請參見函數執行個體生命週期回調方法。說明線上IDE支援PHP、Python、Node.js和Custom Runtime;但不支援Java、Go和.NET這類編譯性語言,以及Custom Container。
單擊代碼編輯器上方的部署代碼,然後單擊測試函數。
通過Serverless Devs配置回調
使用Serverless Devs配置PreFreeze、PreStop擴充函數時,s.yaml
設定檔範例程式碼片段如下所示:
codeUri: './code.zip'
......
instanceLifecycleConfig:
preFreeze:
handler: index.PreFreeze
timeout: 60
preStop:
handler: index.PreStop
timeout: 60
如果您需要關閉某個擴充函數,需要將擴充函數的handler
參數顯示置空,否則後端預設不更新。例如關閉PreFreeze函數,您需要按照以下配置進行部署更新,此時PreFreeze函數的timeout
參數已無效。
codeUri: './code.zip'
......
instanceLifecycleConfig:
preFreeze:
handler: ""
timeout: 60
preStop:
handler: index.PreStop
timeout: 60
不同語言運行時實現函數執行個體生命週期回調的方法請參見函數執行個體生命週期回調方法。
通過SDK配置回調
您可以通過SDK部署和更新擴充函數。本文介紹如何擷取在建立函數時配置PreStop和PreFreeze函數的SDK範例程式碼。
進入CreateFunction - 建立函數頁面,單擊調試,進入OpenAPI門戶。
在參數配置頁簽,根據需要建立函數的基本資料填寫輸入參數。
其中您可以在執行個體生命週期函數配置
instanceLifecycleConfig
欄位配置PreStop和PreFreeze回調。參數配置完成後,單擊SDK樣本頁簽,從而擷取對應語言的SDK範例程式碼。
不同語言運行時實現函數執行個體生命週期回調的方法請參見函數執行個體生命週期回調方法。
函數執行個體生命週期回調方法
不同語言運行時實現函數執行個體生命週期回調的方法請參考以下內容。
運行時 | 描述 | 參考文檔 |
Node.js | 通過Node.js實現並應用函數執行個體生命週期回調方法。 | |
Python | 通過Python實現並應用函數執行個體生命週期回調方法。 | |
PHP | 通過PHP實現並應用函數執行個體生命週期回調方法。 | |
Java | 通過Java運行時實現函數執行個體生命週期回調的方法。 | |
C# | 通過C#運行時實現函數執行個體生命週期回調的方法。 | |
Go | 通過Go實現函數執行個體生命週期回調的方法。 | |
Custom Runtime | 通過Custom Runtime實現函數執行個體生命週期回調的方法。 | |
Custom Container | 通過Web Server模式的Custom Container Runtime實現函數執行個體生命週期回調的方法。 |
查詢回呼函數相關日誌
配置函數執行個體生命週期回調並執行代碼實現對應的回呼函數後,您可以查詢執行個體生命週期回呼函數的相關日誌。
- 登入Function Compute控制台,在左側導覽列,單擊服務及函數。
- 在頂部功能表列,選擇地區,然後在服務列表頁面,單擊目標服務。
在函數管理頁面,單擊目標函數,然後單擊調用日誌頁簽。
在調用請求列表頁簽,找到想要查詢的請求行,複製執行個體 ID,然後單擊進階日誌。
您可以使用複製的執行個體ID,查詢所有生命週期回呼函數的Start/End日誌;還可以使用
執行個體ID+函數執行個體生命週期回調關鍵字
查詢指定回呼函數的Start/End日誌,例如,c-62833f38-20f1629801fa4bd***** and PreStop
。此外,您還可以根據Start/End日誌中的RequestId查詢請求的日誌資訊。如果使用者日誌中沒有RequestId,可以單擊該日誌中的表徵圖擷取上下文日誌。
計費說明
擴充HTTP hooks請求數不計費。擴充在單一實例多並發的情境下依然適用,假設同時有多個Invoke請求在相同執行個體執行,在所有請求都結束後,即將冷凍執行個體之前,會調用一次PreFreeze hook。
以下圖為例,函數規格為1 GB,從t1 PreFreeze開始到t6請求2結束的時間段(假設為1秒),則執行個體執行時間為t6-t1,消耗1s * 1 GB=1 CU。關於計費方式的具體資訊,請參見計費方式。