优化网络
使用集合让一切井井有条
根据您的偏好保存内容并对其进行分类。
Cloud Functions 简单易用,让您可以快速开发代码并在无服务器环境中运行。在规模适中的情况下,运行函数的成本很低,因此优化代码似乎不是一项高优先级的工作。但是,随着部署规模的扩大,代码优化会变得越来越重要。
本文档介绍如何优化函数的网络连接方式。优化网络连接方式可以获得如下好处:
- 减少在每次函数调用时建立新连接所需的 CPU 时间。
- 降低用尽连接配额或 DNS 配额的可能性。
维持持久性连接
本部分通过若干示例,说明如何在函数中维持持久性连接。如果不在函数中维持持久性连接,可能会迅速耗尽连接配额。
本部分包含下列使用场景:
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 Language 或 Cloud 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 运行时中会自动设置。在较新的运行时中,请务必在函数部署时指定它。请参阅配置环境变量。
出站连接
出站请求超时
对于从函数到 VPC 网络的请求,空闲时间达到 10 分钟后超时。对于从函数到互联网的请求,空闲时间达到 20 分钟后超时。
出站连接重置
在底层基础设施重启或更新时,从函数到 VPC 网络和互联网的连接流可能会偶尔被终止和替换。如果您的应用重复使用长期有效的连接,我们建议您将应用配置为重新建立连接,以避免重用无效连接。
函数负载测试
如需测量您的函数平均执行多少次连接,请将其部署为 HTTP 函数,然后使用性能测试框架以特定的 QPS 对其进行调用。您可选择使用 Artillery - 只需一行代码就能调用:
$ artillery quick -d 300 -r 30 URL
此命令会以 30 QPS 的速度提取指定的网址,持续时间为 300 秒。
执行测试后,您可以在 Cloud 控制台中前往 Cloud Functions API 配额页面检查连接配额的使用情况。如果使用量一直在 30(或其倍数)左右,说明您在每次调用中都会建立一个(或多个)连接。优化代码后,您应该只会在测试开始时看到一些连接(10-30 个)。
您还可以在同一页面上的 CPU 配额图中比较优化前后的 CPU 费用。
如未另行说明,那么本页面中的内容已根据知识共享署名 4.0 许可获得了许可,并且代码示例已根据 Apache 2.0 许可获得了许可。有关详情,请参阅 Google 开发者网站政策。Java 是 Oracle 和/或其关联公司的注册商标。
最后更新时间 (UTC):2025-08-17。
[null,null,["最后更新时间 (UTC):2025-08-17。"],[],[],null,["\u003cbr /\u003e\n\nThe simplicity of Cloud Functions lets you quickly develop code and run it in\na serverless environment. At moderate scale, the cost of running functions is\nlow, and optimizing your code might not seem like a high priority. As your\ndeployment scales up, however, optimizing your code becomes increasingly\nimportant.\n\nThis document describes how to optimize networking for your functions. Some of\nthe benefits of optimizing networking are as follows:\n\n- Reduce CPU time spent in establishing new outbound connections at each function call.\n- Reduce the likelihood of running out of connection or DNS [quotas](https://cloud.google.com/functions/quotas).\n\nMaintaining Persistent Connections\n\nThis section gives examples of how to maintain persistent connections in a\nfunction. Failure to do so can result in quickly exhausting connection quotas.\n\nThe following scenarios are covered in this section:\n\n- HTTP/S\n- Google APIs\n\nHTTP/S Requests\n\nThe optimized code snippet below shows how to maintain persistent connections\ninstead of creating a new connection upon every function invocation: \n\nNode.js \n\n```javascript\nconst http = require('http');\nconst functions = require('firebase-functions');\n\n// Setting the `keepAlive` option to `true` keeps\n// connections open between function invocations\nconst agent = new http.Agent({keepAlive: true});\n\nexports.function = functions.https.onRequest((request, response) =\u003e {\n req = http.request({\n host: '',\n port: 80,\n path: '',\n method: 'GET',\n agent: agent, // Holds the connection open after the first invocation\n }, res =\u003e {\n let rawData = '';\n res.setEncoding('utf8');\n res.on('data', chunk =\u003e { rawData += chunk; });\n res.on('end', () =\u003e {\n response.status(200).send(`Data: ${rawData}`);\n });\n });\n req.on('error', e =\u003e {\n response.status(500).send(`Error: ${e.message}`);\n });\n req.end();\n});\n```\n\nPython \n\n```python\nfrom firebase_functions import https_fn\nimport requests\n\n# Create a global HTTP session (which provides connection pooling)\nsession = requests.Session()\n\n@https_fn.on_request()\ndef connection_pooling(request):\n\n # The URL to send the request to\n url = \"http://example.com\"\n\n # Process the request\n response = session.get(url)\n response.raise_for_status()\n return https_fn.Response(\"Success!\")\n \n```\n\nThis HTTP function uses a connection pool to make HTTP requests. It takes a\nrequest object (`flask.Request`) and returns the response text, or any set\nof values that can be turned into a `Response` object using\n[`make_response`](https://flask.palletsprojects.com/en/3.0.x/api/#flask.make_response).\n\nAccessing Google APIs\n\nThe example below uses [Cloud\nPub/Sub](//cloud.google.com/pubsub/docs/reference/libraries), but this approach\nalso works for other client libraries---for example, [Cloud Natural\nLanguage](//cloud.google.com/natural-language/docs/reference/libraries) or\n[Cloud Spanner](//cloud.google.com/spanner/docs/reference/libraries). Note that\nperformance improvements may depend on the current implementation of particular\nclient libraries.\n\nCreating a Pub/Sub client object results in one connection and two DNS queries\nper invocation. To avoid unnecessary connections and DNS queries, create the\nPub/Sub client object in global scope as shown in the sample below: \n\nnode.js \n\n```javascript\nconst PubSub = require('@google-cloud/pubsub');\nconst functions = require('firebase-functions');\nconst pubsub = PubSub();\n\nexports.function = functions.https.onRequest((req, res) =\u003e {\n const topic = pubsub.topic('');\n\n topic.publish('Test message', err =\u003e {\n if (err) {\n res.status(500).send(`Error publishing the message: ${err}`);\n } else {\n res.status(200).send('1 message published');\n }\n });\n});\n```\n\nPython \n\n```python\nimport os\n\nfrom firebase_functions import https_fn\nfrom google.cloud import pubsub_v1\n\n# from firebase_functions import https_fn\n# Create a global Pub/Sub client to avoid unneeded network activity\npubsub = pubsub_v1.PublisherClient()\n\n@https_fn.on_request()\ndef gcp_api_call(request):\n\n project = os.getenv(\"GCP_PROJECT\")\n request_json = request.get_json()\n\n topic_name = request_json[\"topic\"]\n topic_path = pubsub.topic_path(project, topic_name)\n\n # Process the request\n data = b\"Test message\"\n pubsub.publish(topic_path, data=data)\n\n return https_fn.Response(\"1 message published\")\n \n```\n\nThis HTTP function uses a cached client library instance to reduce the\nnumber of connections required per function invocation. It takes a request\nobject (`flask.Request`) and returns the response text, or any set of values\nthat can be turned into a `Response` object using\n[`make_response`](https://flask.palletsprojects.com/en/3.0.x/api/#flask.make_response).\n\nThe `GCP_PROJECT` environment variable is set automatically in the Python\n3.7 runtime. In later runtimes, make sure to specify it on function\ndeployment. See [Configure environment\nvariables](https://cloud.google.com/run/docs/configuring/services/environment-variables).\n\nOutbound connections\n\nOutbound request timeouts\n\nThere is a timeout after 10 minutes of idle time for requests from your function\nto the VPC network. For requests from your function to the internet, there is a\ntimeout after 20 minutes of idle time.\n\nOutbound connection resets\n\nConnection streams from your function to both the [VPC\nnetwork](https://cloud.google.com/run/docs/configuring/connecting-vpc) and\ninternet can be occasionally terminated and replaced when underlying\ninfrastructure is restarted or updated. If your application reuses long-lived\nconnections, we recommend that you configure your application to re-establish\nconnections to avoid the reuse of a dead connection.\n\nLoad-testing Your Function\n\nTo measure how many connections your function performs on average, deploy\nit as a HTTP function and use a performance-testing framework to invoke it at\ncertain QPS. One possible choice is [Artillery](https://artillery.io/), which\nyou can invoke with a single line: \n\n```\n$ artillery quick -d 300 -r 30 URL\n```\n\nThis command fetches the given URL at 30 QPS for 300 seconds.\n\nAfter performing the test, check the usage of your connection quota on the [Cloud Functions API quota\npage](https://console.cloud.google.com/apis/api/cloudfunctions.googleapis.com/quotas) in Cloud\nConsole. If the usage is consistently around 30 (or its multiple), you are\nestablishing one (or several) connections in every invocation. After you\noptimize your code, you should see a few (10-30) connections occur only at the\nbeginning of the test.\n\nYou can also compare the CPU cost before and after the optimization on the CPU\nquota plot on the same page."]]