네트워킹 최적화
컬렉션을 사용해 정리하기
내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요.
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 클라이언트 객체를 만들면 호출당 연결은 1회, DNS 쿼리는 2회가 발생합니다. 불필요한 연결과 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
이 명령어는 300초 동안 30QPS로 해당 URL을 가져옵니다.
테스트를 수행한 후 Cloud 콘솔의 Cloud Functions API 할당량 페이지에서 연결 할당량의 사용량을 확인하세요. 사용량이 지속적으로 30 내외라면 호출할 때마다 1번 연결하는 것이고, 30의 배수라면 여러 번 연결하는 것입니다. 코드를 최적화한 후에는 테스트를 시작할 때만 10~30 정도의 적은 연결 수가 표시되어야 합니다.
또한 같은 페이지의 CPU 할당량 플롯에서 최적화 전후의 CPU 비용을 비교할 수 있습니다.
달리 명시되지 않는 한 이 페이지의 콘텐츠에는 Creative Commons Attribution 4.0 라이선스에 따라 라이선스가 부여되며, 코드 샘플에는 Apache 2.0 라이선스에 따라 라이선스가 부여됩니다. 자세한 내용은 Google Developers 사이트 정책을 참조하세요. 자바는 Oracle 및/또는 Oracle 계열사의 등록 상표입니다.
최종 업데이트: 2025-08-29(UTC)
[null,null,["최종 업데이트: 2025-08-29(UTC)"],[],[],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."]]