טיפים & טריקים

מסמך זה מתאר שיטות עבודה מומלצות לתכנון, יישום, בדיקה ופריסה של פונקציות ענן.

נְכוֹנוּת

סעיף זה מתאר שיטות עבודה מומלצות כלליות לתכנון והטמעה של פונקציות ענן.

כתוב פונקציות אימפוטנטיות

הפונקציות שלך אמורות לייצר את אותה תוצאה גם אם הן נקראות מספר פעמים. זה מאפשר לך לנסות להפעיל שוב אם ההתקשרות הקודמת נכשלת באמצע הקוד שלך. למידע נוסף, ראה ניסיון חוזר של פונקציות מונעות אירועים .

אל תתחיל בפעילויות רקע

פעילות רקע היא כל דבר שקורה לאחר סיום הפונקציה שלך. הפעלת פונקציה מסתיימת ברגע שהפונקציה חוזרת או מאותתת אחרת על השלמה, כגון על ידי קריאה לארגומנט callback בפונקציות מונעות אירועים של Node.js. כל קוד המופעל לאחר סיום חינני אינו יכול לגשת למעבד ולא יתקדם.

בנוסף, כאשר מבוצעת הזמנה עוקבת באותה סביבה, פעילות הרקע שלך מתחדשת, מה שמפריע להתקשרות החדשה. זה עלול להוביל להתנהגות בלתי צפויה ולשגיאות שקשה לאבחן. גישה לרשת לאחר סיום פונקציה מובילה בדרך כלל לאיפוס חיבורים (קוד שגיאה ECONNRESET ).

לעתים קרובות ניתן לזהות פעילות רקע ביומנים מקריאת שיחות בודדות, על ידי מציאת כל דבר שנרשם אחרי השורה שאומרת שההפניה הסתיימה. פעילות רקע יכולה לפעמים להיקבר עמוק יותר בקוד, במיוחד כאשר קיימות פעולות אסינכרוניות כגון התקשרות חוזרת או טיימרים. בדוק את הקוד שלך כדי לוודא שכל הפעולות הא-סינכרוניות מסתיימות לפני שתסיים את הפונקציה.

מחק תמיד קבצים זמניים

אחסון דיסק מקומי בספרייה הזמנית הוא מערכת קבצים בזיכרון. קבצים שאתה כותב צורכים זיכרון זמין לפונקציה שלך, ולפעמים נמשכים בין הפעלות. אי מחיקה מפורשת של קבצים אלה עלולה להוביל בסופו של דבר לשגיאה של מחוץ לזיכרון ולהתחלה קרה לאחר מכן.

אתה יכול לראות את הזיכרון בשימוש על ידי פונקציה בודדת על ידי בחירתו ברשימת הפונקציות ב-GCP Console ובחירה בחלקת השימוש בזיכרון .

אל תנסה לכתוב מחוץ לספרייה הזמנית, והקפד להשתמש בשיטות בלתי תלויות בפלטפורמה/מערכת ההפעלה כדי לבנות נתיבי קבצים.

ניתן לצמצם את דרישות הזיכרון בעת ​​עיבוד קבצים גדולים יותר באמצעות צנרת. לדוגמה, אתה יכול לעבד קובץ ב-Cloud Storage על-ידי יצירת זרם קריאה, העברתו דרך תהליך מבוסס-זרם, וכתיבת זרם הפלט ישירות ל-Cloud Storage.

מסגרת פונקציות

כאשר אתה פורס פונקציה, מסגרת הפונקציות מתווספת אוטומטית כתלות, תוך שימוש בגירסה הנוכחית שלה. כדי להבטיח שאותן תלות מותקנות באופן עקבי בסביבות שונות, אנו ממליצים להצמיד את הפונקציה שלך לגרסה ספציפית של מסגרת הפונקציות.

לשם כך, כלול את הגרסה המועדפת עליך בקובץ הנעילה הרלוונטי (לדוגמה, package-lock.json עבור Node.js, או requirements.txt עבור Python).

כלים

סעיף זה מספק הנחיות כיצד להשתמש בכלים ליישום, בדיקה ואינטראקציה עם פונקציות ענן.

פיתוח מקומי

פריסת הפונקציות לוקחת מעט זמן, ולכן לרוב מהיר יותר לבדוק את הקוד של הפונקציה שלך באופן מקומי.

מפתחי Firebase יכולים להשתמש באמולטור Firebase CLI Cloud Functions .

השתמש ב-Sendgrid כדי לשלוח אימיילים

Cloud Functions אינו מאפשר חיבורים יוצאים ביציאה 25, כך שלא ניתן ליצור חיבורים לא מאובטחים לשרת SMTP. הדרך המומלצת לשלוח מיילים היא להשתמש ב- SendGrid . תוכל למצוא אפשרויות אחרות לשליחת דוא"ל במדריך שליחת דוא"ל ממופע עבור Google Compute Engine.

ביצועים

סעיף זה מתאר שיטות עבודה מומלצות למיטוב ביצועים.

השתמש בתלות בחוכמה

מכיוון שפונקציות הן חסרות מצב, סביבת הביצוע מאותחלת לעתים קרובות מאפס (במהלך מה שמכונה התחלה קרה ). כאשר מתרחשת התחלה קרה, ההקשר הגלובלי של הפונקציה מוערך.

אם הפונקציות שלך מייבאות מודולים, זמן הטעינה של מודולים אלה יכול להוסיף לעיכוב ההפעלה במהלך התחלה קרה. אתה יכול להפחית את זמן האחזור הזה, כמו גם את הזמן הדרוש לפריסת הפונקציה שלך, על ידי טעינת תלות נכונה ולא טעינת תלות שהפונקציה שלך לא משתמשת בה.

השתמש במשתנים גלובליים כדי לעשות שימוש חוזר באובייקטים בהתקשרויות עתידיות

אין ערובה שהמצב של פונקציית ענן יישמר עבור הפעלות עתידיות. עם זאת, Cloud Functions ממחזרת לעתים קרובות את סביבת הביצוע של הזמנה קודמת. אם אתה מצהיר על משתנה בהיקף גלובלי, ניתן לעשות שימוש חוזר בערכו בהפניות עוקבות ללא צורך לחשב מחדש.

בדרך זו אתה יכול לשמור אובייקטים שעשויים להיות יקרים ליצור מחדש בכל הפעלת פונקציה. העברת אובייקטים כאלה מגוף הפונקציה להיקף גלובלי עשויה לגרום לשיפורי ביצועים משמעותיים. הדוגמה הבאה יוצרת אובייקט כבד רק פעם אחת לכל מופע של פונקציה, ומשתפת אותו בכל הפעלות לפונקציה המגיעות למופע הנתון:

Node.js

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
  console.log('Function invocation');
  const perFunction = lightweightComputation();

  res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

פִּיתוֹן

import time

from firebase_functions import https_fn

# Placeholder
def heavy_computation():
  return time.time()

# Placeholder
def light_computation():
  return time.time()

# Global (instance-wide) scope
# This computation runs at instance cold-start
instance_var = heavy_computation()

@https_fn.on_request()
def scope_demo(request):

  # Per-function scope
  # This computation runs every time this function is called
  function_var = light_computation()
  return https_fn.Response(f"Instance: {instance_var}; function: {function_var}")
  

פונקציית HTTP זו לוקחת אובייקט בקשה ( flask.Request ), ומחזירה את טקסט התגובה, או כל סט של ערכים שניתן להפוך לאובייקט Response באמצעות make_response .

חשוב במיוחד לשמור במטמון חיבורי רשת, הפניות לספריה ואובייקטי לקוח API בהיקף גלובלי. ראה אופטימיזציה של רשתות לקבלת דוגמאות.

בצע אתחול עצלן של משתנים גלובליים

אם אתה מאתחל משתנים בהיקף גלובלי, קוד האתחול יתבצע תמיד באמצעות הפעלת הפעלה קרה, מה שמגדיל את ההשהיה של הפונקציה שלך. במקרים מסוימים, הדבר גורם לפסקי זמן לסירוגין לשירותים הנקראים אם הם לא מטופלים כראוי בחסימת try / catch . אם חלק מהאובייקטים אינם נמצאים בשימוש בכל נתיבי הקוד, שקול לאתחל אותם בעצלתיים לפי דרישה:

Node.js

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
  doUsualWork();
  if(unlikelyCondition()){
      myCostlyVariable = myCostlyVariable || buildCostlyVariable();
  }
  res.status(200).send('OK');
});

פִּיתוֹן

from firebase_functions import https_fn

# Always initialized (at cold-start)
non_lazy_global = file_wide_computation()

# Declared at cold-start, but only initialized if/when the function executes
lazy_global = None

@https_fn.on_request()
def lazy_globals(request):

  global lazy_global, non_lazy_global

  # This value is initialized only if (and when) the function is called
  if not lazy_global:
      lazy_global = function_specific_computation()

  return https_fn.Response(f"Lazy: {lazy_global}, non-lazy: {non_lazy_global}.")
  

פונקציית HTTP זו משתמשת בגלובלים מאתחלים בעצלתיים. זה לוקח אובייקט בקשה ( flask.Request ), ומחזיר את טקסט התגובה, או כל סט של ערכים שניתן להפוך לאובייקט Response באמצעות make_response .

זה חשוב במיוחד אם אתה מגדיר מספר פונקציות בקובץ בודד, ופונקציות שונות משתמשות במשתנים שונים. אלא אם כן אתה משתמש באתחול עצל, אתה עלול לבזבז משאבים על משתנים שאותחל אך מעולם לא נעשה בהם שימוש.

צמצם התחלות קרות על ידי הגדרת מספר מינימלי של מופעים

כברירת מחדל, Cloud Functions משנה את מספר המופעים על סמך מספר הבקשות הנכנסות. אתה יכול לשנות את התנהגות ברירת המחדל הזו על ידי הגדרת מספר מינימלי של מופעים ש-Cloud Functions חייבת להחזיק מוכנה להגשת בקשות. הגדרת מספר מינימלי של מופעים מפחיתה התחלות קרות של היישום שלך. אנו ממליצים להגדיר מספר מינימלי של מופעים אם היישום שלך רגיש לאחזור.

ראה בקרת התנהגות קנה מידה למידע נוסף על אפשרויות זמן ריצה אלה.

משאבים נוספים

קבל מידע נוסף על אופטימיזציה של ביצועים בסרטון "Google Cloud Performance Atlas" פונקציות ענן זמן אתחול קר .