تحسين الشبكات

تتيح لك بساطة Cloud Functions تطوير الرمز بسرعة وتشغيله في بيئة بدون خادم. على نطاق معتدل، تكون تكلفة تشغيل الدوال منخفضة، وقد لا يبدو تحسين الرمز البرمجي أولوية قصوى. ومع توسيع نطاق عملية النشر، يصبح تحسين الرمز البرمجي مهمًا بشكل متزايد.

يوضّح هذا المستند كيفية تحسين الشبكات لدوالك. في ما يلي بعض مزايا تحسين الشبكات:

  • تقليل وقت وحدة المعالجة المركزية (CPU) الذي يتم استخدامه في إنشاء اتصالات صادرة جديدة عند كل استدعاء دالة.
  • تقليل احتمالية استنفاد حصص الاتصال أو نظام أسماء النطاقات (DNS) quotas.

الحفاظ على الاتصالات المستمرة

يقدم هذا القسم أمثلة على كيفية الحفاظ على الاتصالات المستمرة في دالة. قد يؤدي عدم إجراء ذلك إلى استنفاد حصص الاتصال بسرعة.

تتناول هذه الفقرة السيناريوهات التالية:

  • HTTP/S
  • Google APIs

طلبات 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) وتعرض نص الاستجابة أو أي مجموعة من القيم التي يمكن تحويلها إلى كائن Response باستخدام make_response.

الوصول إلى Google APIs

يستخدم المثال أدناه Cloud Pub/Sub، ولكن هذه الطريقة تعمل أيضًا مع مكتبات العملاء الأخرى، مثل Cloud Natural Language أو Cloud Spanner. يُرجى العِلم أنّ تحسينات الأداء قد تعتمد على التنفيذ الحالي لمكتبات عملاء معيّنة.

يؤدي إنشاء كائن عميل Pub/Sub إلى اتصال واحد وطلبَي بحث عن نظام أسماء النطاقات (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 هذه مثيلاً مخزّنًا مؤقتًا لمكتبة العميل لتقليل عدد الاتصالات المطلوبة لكل استدعاء دالة. تأخذ الدالة كائن طلب object (flask.Request) وتعرض نص الاستجابة أو أي مجموعة من القيم التي يمكن تحويلها إلى كائن Response باستخدام make_response.

يتم ضبط متغيّر البيئة GCP_PROJECT تلقائيًا في وقت تشغيل Python 3.7. في أوقات التشغيل اللاحقة، احرص على تحديد هذا المتغيّر عند نشر الدالة. الاطّلاع على مقالة ضبط متغيّرات البيئة.

الاتصالات الصادرة

مهلات الطلبات الصادرة

تنتهي مهلة الطلبات من دالتك إلى شبكة السحابة الافتراضية الخاصة (VPC) بعد 10 دقائق من وقت عدم النشاط. بالنسبة إلى الطلبات من دالتك إلى الإنترنت، تنتهي المهلة بعد 20 دقيقة من وقت عدم النشاط.

إعادة ضبط الاتصالات الصادرة

يمكن إنهاء عمليات نقل البيانات من دالتك إلى كلّ من شبكة السحابة الافتراضية الخاصة (VPC) والإنترنت واستبدالها أحيانًا عند إعادة تشغيل البنية الأساسية أو تعديلها. إذا كان تطبيقك يعيد استخدام الاتصالات الطويلة الأمد، ننصحك بضبط تطبيقك لإعادة إنشاء الاتصالات لتجنُّب إعادة استخدام اتصال غير صالح.

اختبار دالتك تحت التحميل

لقياس عدد الاتصالات التي تجريها دالتك في المتوسط، يمكنك نشرها كدالة HTTP واستخدام إطار عمل لاختبار الأداء لاستدعائها بمعدّل طلبات في الثانية (QPS) معيّن. أحد الخيارات المتاحة هو Artillery، الذي يمكنك استدعاؤه باستخدام سطر واحد:

$ artillery quick -d 300 -r 30 URL

يجلب هذا الأمر عنوان URL المحدّد بمعدّل 30 طلبًا في الثانية لمدة 300 ثانية.

بعد إجراء الاختبار، تحقَّق من استخدام حصة الاتصال في صفحة حصة Cloud Functions API في Cloud Console. إذا كان الاستخدام يبلغ باستمرار حوالي 30 (أو مضاعفاته)، فأنت تنشئ اتصالاً واحدًا (أو عدة اتصالات) في كل استدعاء. بعد تحسين الرمز البرمجي، من المفترض أن تظهر بضعة اتصالات (من 10 إلى 30) في بداية الاختبار فقط.

يمكنك أيضًا مقارنة تكلفة وحدة المعالجة المركزية (CPU) قبل التحسين وبعده في الرسم البياني لحصة وحدة المعالجة المركزية (CPU) على الصفحة نفسها.