本文件將說明設計、導入、測試、 並部署 Cloud Functions。
正確性
本節說明設計和實作的一般最佳做法 Cloud Functions。
編寫冪等函式
即使多次呼叫函式,這些函式也應該產生相同結果。這樣一來,如果之前叫用程式碼的作業中途失敗,您便可以重試叫用。若需更多資訊,請參閲 重試事件導向函式。
請勿啟動背景活動
背景活動是指函式終止後發生的任何活動。
函式傳回或以其他方式發出信號後,函式叫用即結束
完成,例如,在 Node.js 事件導向中呼叫 callback
引數
函式。在安全終止後執行的任何程式碼都無法存取
也完全不會有任何進展
此外,在相同的環境中執行後續叫用時,
背景活動就會繼續執行,同時幹擾新的叫用作業。這可能會
會導致非預期的行為和錯誤難以診斷的錯誤。存取
在函式終止後使用網路,通常會導致連線重設
(ECONNRESET
錯誤代碼)。
通常可以透過個別叫用的記錄檔偵測背景活動, 方法是尋找位於「叫用」行的那一行 已完成。背景活動有時可能會掩蓋在程式碼中 在存在非同步作業 (例如回呼或計時器) 的情況下,更是如此。 請先檢查程式碼,確認所有非同步作業皆已完成,再執行 終止函式。
一律刪除暫存檔案
暫存目錄中的本機磁碟儲存空間是一個記憶體內部檔案系統。您編寫的檔案會耗用用於函式的記憶體,而且有時會在叫用間持續存在。不明確刪除這些檔案最終可能會導致發生記憶體不足的錯誤,並造成後續冷啟動。
如要查看個別函式使用的記憶體,請在 函式清單 Google Cloud 控制台,然後選擇「記憶體用量」圖表。
請勿嘗試在暫存目錄外部編寫檔案,並務必使用獨立於平台/OS 的方法建構檔案路徑。
您可以使用管道來減少記憶體需求, 例如,您可以建立讀取串流,以處理 Cloud Storage 中的檔案 並寫入輸出串流 遷移至 Cloud Storage
Functions Framework
當您部署函式時,函式架構會自動新增 依附元件確保相同的依附元件 在不同環境間一致安裝,因此建議 您會將函式固定至特定版本的 Functions Framework。
如要這麼做,請在相關鎖定檔案中加入偏好的版本
(例如,package-lock.json
代表 Node.js,或 requirements.txt
代表 Python)。
工具
本節提供指南,說明如何使用工具實作、測試及 與 Cloud Functions 互動。
本機開發
函式部署需要一點時間,因此測試程式碼通常更快 您本機函式的結構
Firebase 開發人員可以使用 Firebase CLI Cloud Functions 模擬器。使用 Sendgrid 傳送電子郵件
Cloud Functions 不允許透過通訊埠 25 傳出連線,因此您無法透過通訊埠 25 傳出連線 對 SMTP 伺服器建立不安全的連線。建議的傳送方式 電子郵件使用 SendGrid。如想查看其他選項 讓您在以下位置傳送電子郵件 從執行個體傳送電子郵件 Google Compute Engine 教學課程
成效
本節說明最佳化效能的最佳做法。
謹慎使用依附元件
由於函式是無狀態的,因此執行環境通常是從頭開始初始化 (這期間就是所謂的「冷啟動」)。發生冷啟動時,會評估函式的全域背景資訊。
如果函式匯入模組,在冷啟動期間,這些模組的載入時間會增加叫用的延遲時間。您可以正確載入依附元件,而不載入函式不使用的依附元件,來減少這一延遲時間以及部署函式需要的時間。
使用全域變數在未來叫用中重複使用物件
即使函式的狀態 而保留下來,以供日後叫用使用不過,Cloud Functions 通常會回收 先前叫用的執行環境。如果您在 全域範圍,因此其值可在後續叫用中重複使用 重新運算
這樣一來,您便可以快取在每次叫用函式時重新建立起來費用可能比較高的的物件。將這類物件從函式主體移至全域範圍可能會使效能大幅提升。下列範例只會為每個函式執行個體建立一個重型物件,並在到達指定執行個體的所有函式叫用中共用這個物件:
Node.js
console.log('Global scope'); const perInstance = heavyComputation(); const functions = require('firebase-functions'); exports.function = functions.https.onRequest((req, res) => { console.log('Function invocation'); const perFunction = lightweightComputation(); res.send(`Per instance: ${perInstance}, per function: ${perFunction}`); });
Python
import time from firebase_functions import https_fn # Placeholder def heavy_computation(): return time.time() # Placeholder def light_computation(): return time.time() # Global (instance-wide) scope # This computation runs at instance cold-start instance_var = heavy_computation() @https_fn.on_request() def scope_demo(request): # Per-function scope # This computation runs every time this function is called function_var = light_computation() return https_fn.Response(f"Instance: {instance_var}; function: {function_var}")
此 HTTP 函式採用要求物件 (flask.Request
),並傳回
回應文字,或任何可以轉換成
使用 Response
物件
make_response
。
快取網路連線、程式庫參考資料、 和 API 用戶端物件 如需範例,請參閱為網路連線進行最佳化一文。
對全域變數執行延遲初始化
如果您在全域範圍內初始化變數,初始化程式碼一律會
,以便增加函式的延遲時間。
在某些情況下,這會導致呼叫的服務發生間歇性逾時
如未在 try
/catch
區塊中妥善處理這些程式碼如果某些物件並未在所有程式碼路徑中使用,請考慮根據需要延遲初始化這些物件:
Node.js
const functions = require('firebase-functions'); let myCostlyVariable; exports.function = functions.https.onRequest((req, res) => { doUsualWork(); if(unlikelyCondition()){ myCostlyVariable = myCostlyVariable || buildCostlyVariable(); } res.status(200).send('OK'); });
Python
from firebase_functions import https_fn # Always initialized (at cold-start) non_lazy_global = file_wide_computation() # Declared at cold-start, but only initialized if/when the function executes lazy_global = None @https_fn.on_request() def lazy_globals(request): global lazy_global, non_lazy_global # This value is initialized only if (and when) the function is called if not lazy_global: lazy_global = function_specific_computation() return https_fn.Response(f"Lazy: {lazy_global}, non-lazy: {non_lazy_global}.")
此 HTTP 函式使用延遲初始化的全域函式。會接收要求物件
(flask.Request
),然後傳回回應文字,或是
轉換成 Response
物件
make_response
。
如果您在單一檔案中定義多個函式,且不同函式使用不同變數,這個方法尤為重要。除非您使用延遲初始化,否則會浪費已初始化但從未使用的變數資源。
設定執行個體數量下限,藉此減少冷啟動的情形
根據預設,Cloud Functions 會根據 傳入要求數量如要變更這項預設行為,只需設定 Cloud Functions 必須保持就緒的執行個體數量下限 廣告放送要求設定執行個體數量下限可減少冷啟動的情形 應用程式建議您設定執行個體的數量下限 容易受到延遲時間影響
詳情請見 控管資源調度行為 進一步瞭解這些執行階段選項其他資源
如要進一步瞭解如何最佳化效能,請前往「Google Cloud 效能」 Atlas」影片 Cloud Functions 冷啟動時間。