Tối ưu hoá kết nối mạng

Sự đơn giản của Cloud Functions giúp bạn nhanh chóng phát triển mã và chạy mã trong môi trường không máy chủ. Ở quy mô vừa phải, chi phí chạy các hàm là thấp và việc tối ưu hoá mã có thể không phải là ưu tiên cao. Tuy nhiên, khi quy mô triển khai tăng lên, việc tối ưu hoá mã ngày càng trở nên quan trọng.

Tài liệu này mô tả cách tối ưu hoá kết nối mạng cho các hàm. Sau đây là một số lợi ích của việc tối ưu hoá kết nối mạng:

  • Giảm thời gian của CPU để thiết lập các kết nối mới cho dữ liệu gửi đi tại mỗi lệnh gọi hàm.
  • Giảm khả năng hết hạn mức kết nối hoặc DNS.

Duy trì kết nối ổn định

Phần này đưa ra các ví dụ về cách duy trì kết nối ổn định trong một hàm. Nếu không làm như vậy, bạn có thể nhanh chóng sử dụng hết hạn mức kết nối.

Phần này đề cập đến các trường hợp sau:

  • HTTP/S
  • Google API

Yêu cầu HTTP/S

Đoạn mã được tối ưu hoá dưới đây cho thấy cách duy trì kết nối ổn định thay vì tạo kết nối mới mỗi khi gọi hàm:

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!")
    

Hàm HTTP này sử dụng một nhóm kết nối để tạo các yêu cầu HTTP. Hàm này nhận một đối tượng yêu cầu (flask.Request) và trả về văn bản phản hồi hoặc bất kỳ tập hợp giá trị nào có thể chuyển thành đối tượng Response bằng cách sử dụng make_response.

Truy cập vào các API của Google

Ví dụ dưới đây sử dụng Cloud Pub/Sub, nhưng phương pháp này cũng áp dụng được cho các thư viện ứng dụng khác, chẳng hạn như Cloud Natural Language hoặc Cloud Spanner. Xin lưu ý rằng mức độ cải thiện hiệu suất có thể phụ thuộc vào cách triển khai hiện tại của một số thư viện ứng dụng cụ thể.

Việc tạo đối tượng ứng dụng Pub/Sub sẽ dẫn đến một kết nối và hai truy vấn DNS cho mỗi lệnh gọi. Để tránh các kết nối và truy vấn DNS không cần thiết, hãy tạo đối tượng ứng dụng Pub/Sub trong phạm vi chung như trong mẫu dưới đây:

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")
    

Hàm HTTP này sử dụng một thực thể thư viện ứng dụng được lưu vào bộ nhớ đệm để giảm số lượng kết nối cần thiết cho mỗi lệnh gọi hàm. Hàm này nhận một đối tượng yêu cầu (flask.Request) và trả về văn bản phản hồi hoặc bất kỳ tập hợp giá trị nào có thể chuyển thành đối tượng Response bằng cách sử dụng make_response.

Biến môi trường GCP_PROJECT được đặt tự động trong thời gian chạy Python 3.7. Trong các môi trường thời gian chạy sau này, hãy nhớ chỉ định biến này khi triển khai hàm. Xem phần Định cấu hình biến môi trường.

Kết nối đi

Hết thời gian chờ yêu cầu gửi đi

Có thời gian chờ sau 10 phút không hoạt động đối với các yêu cầu từ hàm của bạn đến mạng VPC. Đối với các yêu cầu từ hàm của bạn đến Internet, thời gian chờ sẽ hết sau 20 phút không hoạt động.

Số lần đặt lại kết nối đi

Đôi khi, các luồng kết nối từ hàm của bạn đến cả mạng VPC và Internet có thể bị chấm dứt và thay thế khi cơ sở hạ tầng cơ bản được khởi động lại hoặc cập nhật. Nếu ứng dụng của bạn sử dụng lại các kết nối tồn tại lâu, bạn nên định cấu hình ứng dụng để thiết lập lại kết nối nhằm tránh sử dụng lại kết nối đã chết.

Kiểm thử tải hàm

Để đo lường số lượng kết nối trung bình mà hàm của bạn thực hiện, hãy triển khai hàm đó dưới dạng hàm HTTP và sử dụng khung kiểm thử hiệu suất để gọi hàm đó ở một số QPS nhất định. Một lựa chọn khả thi là Artillery, bạn có thể gọi bằng một dòng duy nhất:

$ artillery quick -d 300 -r 30 URL

Lệnh này tìm nạp URL đã cho ở tốc độ 30 QPS trong 300 giây.

Sau khi thực hiện kiểm thử, hãy kiểm tra mức sử dụng hạn mức kết nối trên trang hạn mức API Cloud Functions trong bảng điều khiển Google Cloud. Nếu mức sử dụng luôn ở khoảng 30 (hoặc bội số của 30), thì tức là bạn đang thiết lập một (hoặc một số) kết nối trong mỗi lệnh gọi. Sau khi tối ưu hoá mã, bạn sẽ thấy một vài (10-30) kết nối chỉ xảy ra khi bắt đầu kiểm thử.

Bạn cũng có thể so sánh chi phí CPU trước và sau khi tối ưu hoá trên biểu đồ hạn mức CPU trên cùng một trang.