הפשטות של Cloud Functions מאפשרת לכם לפתח קוד במהירות ולהריץ אותו בסביבה ללא שרת (serverless). בשימוש בינוני, העלות של הפעלת פונקציות נמוכה, ולכן יכול להיות שלא תהיה לכם עדיפות גבוהה לאופטימיזציה של הקוד. אבל ככל שהפריסה גדלה, האופטימיזציה של הקוד הופכת לחשובה יותר.
במאמר הזה מוסבר איך לבצע אופטימיזציה של הרשתות עבור הפונקציות. אלה כמה מהיתרונות של אופטימיזציה של הרשת:
- לקצר את הזמן שנדרש למעבד כדי ליצור חיבורים יוצאים חדשים בכל קריאה לפונקציה.
- להקטין את הסיכוי לחריגה ממכסות החיבור או ה-DNS.
שמירה על חיבורים מתמידים
בקטע הזה מופיעות דוגמאות לאופן שבו שומרים על חיבורים מתמידים בפונקציה. אם לא תעשו את זה, יכול להיות שתגיעו במהירות למכסת החיבורים.
התרחישים הבאים מוסברים בקטע הזה:
- 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 לכל הפעלה. כדי למנוע חיבורים ושאילתות 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
) ומחזירה את טקסט התגובה, או כל קבוצה של ערכים שאפשר להפוך לאובייקט Response
באמצעות make_response
.
משתנה הסביבה GCP_PROJECT
מוגדר אוטומטית בזמן הריצה של Python 3.7. בסביבות ריצה מאוחרות יותר, חשוב לציין את זה כשפורסים את הפונקציה. הוראות להגדרת משתני סביבה
חיבורים יוצאים
זמן קצוב לתפוגה של בקשות יוצאות
יש פסק זמן אחרי 10 דקות של חוסר פעילות בבקשות מהפונקציה לרשת ה-VPC. אם הפונקציה שולחת בקשות לאינטרנט, היא תפסיק לפעול אחרי 20 דקות של חוסר פעילות.
איפוסים של חיבורים יוצאים
יכול להיות שהחיבורים מהפונקציה שלכם לרשת ה-VPC ולאינטרנט יופסקו מדי פעם ויוחלפו, אם התשתית הבסיסית תופעל מחדש או תעודכן. אם האפליקציה שלכם עושה שימוש חוזר בחיבורים לטווח ארוך, מומלץ להגדיר אותה כך שתבצע חיבורים מחדש כדי למנוע שימוש חוזר בחיבור לא פעיל.
בדיקת טעינה של הפונקציה
כדי למדוד כמה חיבורים הפונקציה מבצעת בממוצע, צריך לפרוס אותה כפונקציית HTTP ולהשתמש במסגרת לבדיקת ביצועים כדי להפעיל אותה ב-QPS מסוים. אפשרות אחת היא Artillery, שאפשר להפעיל אותה באמצעות שורה אחת:
$ artillery quick -d 300 -r 30 URL
הפקודה הזו מאחזרת את כתובת ה-URL הנתונה ב-30 QPS למשך 300 שניות.
אחרי שמבצעים את הבדיקה, בודקים את השימוש במכסת החיבורים בדף Cloud Functions מכסת ה-API במסוף Cloud. אם השימוש הוא באופן עקבי בסביבות 30 (או כפולה של 30), אתם יוצרים חיבור אחד (או כמה) בכל הפעלה. אחרי שמבצעים אופטימיזציה של הקוד, אמורות להתרחש כמה (10-30) התחברויות רק בתחילת הבדיקה.
אפשר גם להשוות את עלות המעבד לפני ואחרי האופטימיזציה בתרשים של מכסת המעבד באותו דף.