Catch up on highlights from Firebase at Google I/O 2023. Learn more

提示與技巧

本文檔描述了設計、實施、測試和部署 Cloud Functions 的最佳實踐。

正確性

本節介紹設計和實施 Cloud Functions 的一般最佳實踐。

編寫冪等函數

即使調用多次,您的函數也應該產生相同的結果。如果上一次調用在您的代碼中途失敗,這使您可以重試調用。有關詳細信息,請參閱重試事件驅動函數

不啟動後台活動

後台活動是您的功能終止後發生的任何事情。一旦函數返回或以其他方式發出完成信號,例如通過調用 Node.js 事件驅動函數中的callback參數,函數調用就完成。正常終止後運行的任何代碼都無法訪問 CPU,也不會取得任何進展。

此外,當在同一環境中執行後續調用時,您的後台活動將恢復,從而乾擾新的調用。這可能會導致難以診斷的意外行為和錯誤。在函數終止後訪問網絡通常會導致連接被重置( ECONNRESET錯誤代碼)。

通常可以在來自各個調用的日誌中檢測到後台活動,方法是查找在表示調用完成的行之後記錄的任何內容。後台活動有時會隱藏在代碼中更深的地方,尤其是在存在回調或計時器等異步操作時。檢查您的代碼以確保所有異步操作在您終止函數之前完成。

始終刪除臨時文件

臨時目錄中的本地磁盤存儲是一個內存文件系統。您編寫的文件會消耗您的函數可用的內存,有時會在兩次調用之間持續存在。未能顯式刪除這些文件可能最終導致內存不足錯誤和隨後的冷啟動。

您可以通過在 GCP Console 的函數列表中選擇它並選擇內存使用圖來查看單個函數使用的內存。

不要嘗試在臨時目錄之外寫入,並確保使用與平台/操作系統無關的方法來構建文件路徑。

在使用流水線處理較大的文件時,您可以減少內存需求。例如,您可以通過創建讀取流、將其傳遞到基於流的進程並將輸出流直接寫入 Cloud Storage 來處理 Cloud Storage 上的文件。

工具

本節提供了有關如何使用工具來實施、測試 Cloud Functions 以及與 Cloud Functions 交互的指南。

地方發展

函數部署需要一點時間,因此在本地測試函數代碼通常會更快。

Firebase 開發人員可以使用Firebase CLI Cloud Functions Emulator

使用 Sendgrid 發送郵件

Cloud Functions 不允許端口 25 上的出站連接,因此您無法與 SMTP 服務器建立非安全連接。發送電子郵件的推薦方法是使用SendGrid 。您可以在 Google Compute Engine 的從實例發送電子郵件教程中找到用於發送電子郵件的其他選項。

表現

本節介紹優化性能的最佳實踐。

明智地使用依賴關係

因為函數是無狀態的,所以執行環境通常從頭開始初始化(在所謂的冷啟動期間)。發生冷啟動時,將評估函數的全局上下文。

如果您的函數導入模塊,那麼這些模塊的加載時間會增加冷啟動期間的調用延遲。您可以通過正確加載依賴項而不加載您的函數不使用的依賴項來減少這種延遲以及部署您的函數所需的時間。

使用全局變量在未來的調用中重用對象

無法保證為將來的調用保留 Cloud Functions 的狀態。然而,Cloud Functions 經常回收之前調用的執行環境。如果您在全局範圍內聲明一個變量,則它的值可以在後續調用中重複使用,而無需重新計算。

通過這種方式,您可以緩存在每次函數調用時重新創建可能代價高昂的對象。將此類對像從函數體移至全局範圍可能會顯著提高性能。下面的示例只為每個函數實例創建一次重對象,並在到達給定實例的所有函數調用中共享它:

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}`);
});

在全局範圍內緩存網絡連接、庫引用和 API 客戶端對象尤為重要。有關示例,請參閱優化網絡

對全局變量進行惰性初始化

如果您在全局範圍內初始化變量,初始化代碼將始終通過冷啟動調用執行,從而增加函數的延遲。在某些情況下,如果在try / catch塊中未正確處理,這會導致正在調用的服務間歇性超時。如果某些對象未在所有代碼路徑中使用,請考慮按需延遲初始化它們:

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');
});

如果您在單個文件中定義多個函數,並且不同的函數使用不同的變量,這一點尤其重要。除非使用延遲初始化,否則可能會在已初始化但從未使用過的變量上浪費資源。

通過設置最小實例數減少冷啟動

默認情況下,Cloud Functions 根據傳入請求的數量縮放實例數量。您可以通過設置 Cloud Functions 必須準備好為請求提供服務的最小實例數來更改此默認行為。設置最小實例數可減少應用程序的冷啟動。如果您的應用程序對延遲敏感,我們建議設置最小實例數。

有關這些運行時選項的更多信息,請參閱控制縮放行為

額外資源

在“Google Cloud Performance Atlas”視頻Cloud Functions Cold Boot Time中了解有關優化性能的更多信息。