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

Tính đơn giản của Cloud Functions giúp bạn nhanh chóng phát triển 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 thấp và việc tối ưu hoá mã có vẻ không phải là mức độ ưu tiên cao. Tuy nhiên, khi quy mô triển khai mở rộng, 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 của bạn. Sau đây là một số lợi ích của việc tối ưu hoá mạng:

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

Duy trì sự kết nối bền vững

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

Các trường hợp sau được đề cập trong phần này:

  • HTTP/S
  • Google API

Yêu cầu HTTP/S

Đoạn mã được tối ưu hoá dưới đây cho biết cách duy trì các kết nối bền vững thay vì tạo một kết nối mới trên mỗi lệnh 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 nhóm kết nối để thực hiện các yêu cầu HTTP. Phương thức này lấy 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 API của Google

Ví dụ bên dưới sử dụng Cloud Pub/Sub, nhưng phương pháp này cũng áp dụng cho các thư viện ứng dụng khác – ví dụ: Cloud Natural Language hoặc Cloud Spanner. Xin lưu ý rằng mức độ cải thiện về 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 một đối tượng ứng dụng Pub/Sub sẽ dẫn đến một kết nối và 2 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 ở phạm vi toàn cục như trong mẫu dưới đây:

nút.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 phiên bản 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. Phương thức này lấy 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 thời gian chạy sau này, hãy nhớ chỉ định giá trị này trong quá trình triển khai hàm. Hãy xem bài viết Định cấu hình các biến môi trường.

Kiểm thử tải hàm của bạn

Để đo lường số lượng kết nối trung bình mà hàm của bạn thực hiện, bạn chỉ cần triển khai hàm đó dưới dạng một hàm HTTP và sử dụng khung kiểm thử hiệu suất để gọi hàm đó tại một số QPS nhất định. Bạn có thể chọn Pháo, trong đó bạn có thể gọi phương thức này 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 với tốc độ 30 QPS trong 300 giây.

Sau khi kiểm thử, hãy kiểm tra việc sử dụng hạn mức kết nối trên trang hạn mức API Cloud Functions trong Cloud Console. Nếu mức sử dụng nhất quán vào khoảng 30 (hoặc nhiều lần), thì bạn đang thiết lập một (hoặc nhiều) 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ỉ xuất hiện 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.