最佳化網路

Cloud Functions 的簡易性可讓您快速開發程式碼,並在無伺服器環境中執行。在中等規模情況下,函式的執行費用較低,最佳化程式碼似乎顯得不那麼迫切。但隨著開發規模的增長,最佳化程式碼就會變得越來越重要。

本文件說明如何針對您的函式最佳化網路。最佳化網路的部分優點如下所述:

  • 減少每次函式呼叫時,建立新傳出連線所需的 CPU 時間。
  • 降低連線或 DNS 配額用盡的可能性。

保持永久連線

本節提供如何在函式中保持永久連線的範例。如果不能永久連線,會導致快速用盡連線配額。

本節介紹下列情境:

  • HTTP/S
  • Google API

HTTP/S 要求

以下經過最佳化的程式碼片段顯示如何保持永久連線,而不必在每次叫用函式時建立新連線:

Node.js

const http = require('http');
const functions = require('firebase-functions');

// Setting the `keepAlive` option to `true` keeps
// connections open between function invocations
const agent = new http.Agent({keepAlive: true});

exports.function = functions.https.onRequest((request, response) => {
    req = http.request({
        host: '',
        port: 80,
        path: '',
        method: 'GET',
        agent: agent, // Holds the connection open after the first invocation
    }, res => {
        let rawData = '';
        res.setEncoding('utf8');
        res.on('data', chunk => { rawData += chunk; });
        res.on('end', () => {
            response.status(200).send(`Data: ${rawData}`);
        });
    });
    req.on('error', e => {
        response.status(500).send(`Error: ${e.message}`);
    });
    req.end();
});

Python

from firebase_functions import https_fn
import requests

# Create a global HTTP session (which provides connection pooling)
session = requests.Session()

@https_fn.on_request()
def connection_pooling(request):

    # The URL to send the request to
    url = "http://example.com"

    # Process the request
    response = session.get(url)
    response.raise_for_status()
    return https_fn.Response("Success!")
    

這個 HTTP 函式會使用連線集區提出 HTTP 要求。它會取得要求物件 (flask.Request),並傳回回應文字,或任何可透過 make_response 轉換為 Response 物件的值組合。

存取 Google API

下方範例使用 Cloud Pub/Sub,但這項做法也適用於其他用戶端程式庫,例如 Cloud Natural LanguageCloud Spanner。請注意,效能的提升可能取決於特定用戶端程式庫的目前實作。

建立 Pub/Sub 用戶端物件會導致每次叫用時產生一個連線和兩個 DNS 查詢。為避免不必要的連線和 DNS 查詢,請在全域範圍內建立 Pub/Sub 用戶端物件,如以下範例所示:

node.js

const PubSub = require('@google-cloud/pubsub');
const functions = require('firebase-functions');
const pubsub = PubSub();

exports.function = functions.https.onRequest((req, res) => {
    const topic = pubsub.topic('');

    topic.publish('Test message', err => {
        if (err) {
            res.status(500).send(`Error publishing the message: ${err}`);
        } else {
            res.status(200).send('1 message published');
        }
    });
});

Python

import os

from firebase_functions import https_fn
from google.cloud import pubsub_v1

# from firebase_functions import https_fn
# Create a global Pub/Sub client to avoid unneeded network activity
pubsub = pubsub_v1.PublisherClient()

@https_fn.on_request()
def gcp_api_call(request):

    project = os.getenv("GCP_PROJECT")
    request_json = request.get_json()

    topic_name = request_json["topic"]
    topic_path = pubsub.topic_path(project, topic_name)

    # Process the request
    data = b"Test message"
    pubsub.publish(topic_path, data=data)

    return https_fn.Response("1 message published")
    

這個 HTTP 函式會使用快取的用戶端程式庫例項,減少每次函式叫用所需的連線數量。它會取得要求物件 (flask.Request),並傳回回應文字,或任何可透過 make_response 轉換為 Response 物件的值組合。

GCP_PROJECT 環境變數會在 Python 3.7 執行階段中自動設定。在後續執行階段中,請務必在函式部署作業中指定此值。請參閱「設定環境變數」。

外出連線

傳出要求逾時

函式傳送至虛擬私有雲網路的要求,在閒置 10 分鐘後就會逾時。如果函式向網際網路傳送要求,則會在閒置 20 分鐘後逾時。

外寄連線重設

當底層基礎架構重新啟動或更新時,從函式連線至虛擬私有雲網路和網際網路的連線串流可能會偶爾終止並取代。如果應用程式重複使用長效連線,建議您將應用程式設為重新建立連線,以免重複使用已中斷的連線。

對函式進行負載測試

如要測量您的函式平均執行的連線數,只需將其部署為 HTTP 函式,並使用效能測試架構,以特定的每秒查詢數 (QPS) 叫用這個函式即可。一個可能的選擇是 Artillery,您可以使用以下這行程式碼予以叫用:

$ artillery quick -d 300 -r 30 URL

這個指令會以 30 QPS 的頻率擷取指定網址 300 秒。

測試完成後,請前往 Cloud 控制台的 Cloud Functions API 配額頁面,查看連線配額的使用情形。如果使用情況一直是大約 30 或其倍數,即表示您將會在每次叫用時建立一個或多個連線。最佳化程式碼之後,您應該會發現只有在測試開始時,建立了一些連線 (數目大概是10-30 個)。

您也可以在同一頁面的 CPU 配額圖中比較最佳化前後的 CPU 費用。