بهینه سازی شبکه

سادگی Cloud Functions به شما امکان می‌دهد به سرعت کد را توسعه داده و آن را در یک محیط بدون سرور اجرا کنید. در مقیاس متوسط، هزینه اجرای توابع کم است و بهینه‌سازی کد شما ممکن است اولویت بالایی به نظر نرسد. با این حال، با افزایش مقیاس استقرار، بهینه‌سازی کد شما به طور فزاینده‌ای اهمیت پیدا می‌کند.

این سند نحوه بهینه‌سازی شبکه برای عملکردهای شما را شرح می‌دهد. برخی از مزایای بهینه‌سازی شبکه به شرح زیر است:

  • کاهش زمان صرف شده توسط پردازنده برای ایجاد اتصالات خروجی جدید در هر فراخوانی تابع.
  • احتمال اتمام اتصال یا سهمیه DNS را کاهش دهید.

حفظ ارتباطات پایدار

این بخش مثال‌هایی از نحوه‌ی حفظ اتصالات پایدار در یک تابع ارائه می‌دهد. عدم انجام این کار می‌تواند منجر به اتمام سریع سهمیه‌های اتصال شود.

سناریوهای زیر در این بخش بررسی می‌شوند:

  • HTTP/S
  • API های گوگل

درخواست‌های HTTP/S

قطعه کد بهینه شده زیر نحوه حفظ اتصالات پایدار را به جای ایجاد یک اتصال جدید پس از هر فراخوانی تابع نشان می‌دهد:

نود جی اس

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();
});

پایتون

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 از یک مجموعه اتصال (connection pool) برای ارسال درخواست‌های HTTP استفاده می‌کند. این تابع یک شیء درخواست ( flask.Request ) می‌گیرد و متن پاسخ یا هر مجموعه‌ای از مقادیر را که می‌تواند با استفاده از make_response به یک شیء Response تبدیل شود، برمی‌گرداند.

دسترسی به API های گوگل

مثال زیر از Cloud Pub/Sub استفاده می‌کند، اما این رویکرد برای سایر کتابخانه‌های کلاینت نیز کار می‌کند - برای مثال، Cloud Natural Language یا Cloud Spanner . توجه داشته باشید که بهبود عملکرد ممکن است به پیاده‌سازی فعلی کتابخانه‌های کلاینت خاص بستگی داشته باشد.

ایجاد یک شیء Pub/Sub client منجر به یک اتصال و دو پرس‌وجوی DNS در هر فراخوانی می‌شود. برای جلوگیری از اتصالات و پرس‌وجوهای DNS غیرضروری، شیء Pub/Sub client را در محدوده سراسری، همانطور که در نمونه زیر نشان داده شده است، ایجاد کنید:

گره.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');
        }
    });
});

پایتون

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 به طور خودکار در زمان اجرای پایتون ۳.۷ تنظیم می‌شود. در زمان‌های اجرای بعدی، مطمئن شوید که آن را در هنگام استقرار تابع مشخص می‌کنید. به پیکربندی متغیرهای محیطی مراجعه کنید.

اتصالات خروجی

مهلت‌های زمانی درخواست‌های خروجی

پس از ۱۰ دقیقه زمان بیکاری، برای درخواست‌های ارسالی از تابع شما به شبکه VPC، یک مهلت زمانی وجود دارد. برای درخواست‌های ارسالی از تابع شما به اینترنت، پس از ۲۰ دقیقه زمان بیکاری، یک مهلت زمانی وجود دارد.

اتصال خروجی بازنشانی می‌شود

جریان‌های اتصال از تابع شما به شبکه VPC و اینترنت می‌توانند گاهی اوقات هنگام راه‌اندازی مجدد یا به‌روزرسانی زیرساخت‌های زیربنایی، خاتمه یافته و جایگزین شوند. اگر برنامه شما از اتصالات طولانی مدت استفاده مجدد می‌کند، توصیه می‌کنیم برنامه خود را برای برقراری مجدد اتصالات پیکربندی کنید تا از استفاده مجدد از یک اتصال مرده جلوگیری شود.

تست بارگذاری تابع شما

برای اندازه‌گیری تعداد اتصالاتی که تابع شما به طور متوسط ​​انجام می‌دهد، آن را به عنوان یک تابع HTTP مستقر کنید و از یک چارچوب تست عملکرد برای فراخوانی آن در QPS خاص استفاده کنید. یک گزینه ممکن Artillery است که می‌توانید با یک خط فراخوانی کنید:

$ artillery quick -d 300 -r 30 URL

این دستور URL داده شده را با سرعت 30 QPS و به مدت 300 ثانیه دریافت می‌کند.

پس از انجام آزمایش، میزان استفاده از سهمیه اتصال خود را در صفحه سهمیه API Cloud Functions در کنسول ابری بررسی کنید. اگر میزان استفاده به طور مداوم حدود 30 (یا مضربی از آن) باشد، شما در هر فراخوانی یک (یا چند) اتصال برقرار می‌کنید. پس از بهینه‌سازی کد خود، باید ببینید که فقط در ابتدای آزمایش چند (10 تا 30) اتصال رخ می‌دهد.

همچنین می‌توانید هزینه CPU را قبل و بعد از بهینه‌سازی در نمودار سهمیه CPU در همان صفحه مقایسه کنید.