نصائح

يصف هذا المستند أفضل الممارسات لتصميم دوال Cloud وتنفيذها واختبارها ونشرها.

التصحيح

يوضّح هذا القسم أفضل الممارسات العامة لتصميم دوال السحابة وتنفيذها.

كتابة الدوال المساعِدة

يجب أن تؤدي الدوال إلى نفس النتيجة حتى إذا تم استدعائها عدة مرات. يتيح لك ذلك إعادة محاولة الاستدعاء في حال تعذُّر إكمال الاستدعاء السابق من خلال الرمز. لمزيد من المعلومات، راجِع إعادة تجربة الدوال المستندة إلى الأحداث.

عدم بدء الأنشطة في الخلفية

النشاط في الخلفية هو أي شيء يحدث بعد إنهاء الوظيفة. ينتهي استدعاء الدالة عند عرض الدالة أو الإشارة إلى إكمالها، مثلاً من خلال استدعاء الوسيطة callback في دوال Node.js المستندة إلى الحدث. أي رمز يتم تشغيله بعد الإنهاء السلس لا يمكنه الوصول إلى وحدة المعالجة المركزية (CPU) ولن يتم إحراز أي تقدم.

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

وغالبًا ما يتم اكتشاف النشاط في الخلفية في السجلات من الاستدعاءات الفردية، وذلك من خلال العثور على أي شيء تم تسجيله بعد السطر الذي يشير إلى انتهاء الاستدعاء. قد يكون النشاط في الخلفية أحيانًا أعمق في الرمز، خاصةً عند وجود عمليات غير متزامنة مثل عمليات معاودة الاتصال أو الموقتات. راجع التعليمات البرمجية للتأكد من انتهاء جميع العمليات غير المتزامنة قبل إنهاء الوظيفة.

حذف الملفات المؤقتة دائمًا

تخزين القرص المحلي في الدليل المؤقت هو نظام ملفات في الذاكرة. تستهلك الملفات التي تكتبها الذاكرة المتاحة لوظيفتك، وفي بعض الأحيان تستمر بين الاستدعاءات. قد يؤدي الفشل في حذف هذه الملفات بشكل صريح في النهاية إلى خطأ خارج الذاكرة وبداية باردة لاحقة.

يمكنك عرض الذاكرة المستخدمة بواسطة دالة فردية عن طريق اختيارها في قائمة الدوال في وحدة تحكُّم Google Cloud Platform واختيار الرسم البياني استخدام الذاكرة.

لا تحاول الكتابة خارج الدليل المؤقت، وتأكد من استخدام طرق مستقلة عن النظام الأساسي/نظام التشغيل لإنشاء مسارات الملفات.

يمكنك تقليل متطلبات الذاكرة عند معالجة ملفات أكبر حجمًا باستخدام المعالجة المتوازية. على سبيل المثال، يمكنك معالجة ملف على Cloud Storage من خلال إنشاء عملية بث للقراءة، وتمريره خلال عملية قائمة على البث، وكتابة مجموعة بث الإخراج مباشرة إلى Cloud Storage.

إطار عمل الدوال

عند نشر دالة، تتم إضافة إطار عمل الدوال تلقائيًا كتبعية باستخدام إصدارها الحالي. ولضمان تثبيت التبعيات نفسها بشكل متّسق في بيئات مختلفة، ننصحك بتثبيت الدالة على إصدار معيّن من إطار عمل الدوال.

لإجراء ذلك، عليك تضمين الإصدار المفضّل لديك في ملف القفل ذي الصلة (على سبيل المثال، package-lock.json في Node.js أو requirements.txt في Python).

الأدوات

يقدّم هذا القسم إرشادات حول كيفية استخدام الأدوات لتنفيذ دوال السحابة واختبارها والتفاعل معها.

التنمية المحلية

يستغرق نشر الدالة بعض الوقت، لذلك غالبًا ما يكون اختبار رمز الدالة محليًا بشكل أسرع.

يمكن لمطوّري البرامج في Firebase استخدام محاكي وظائف السحابة الإلكترونية لواجهة سطر الأوامر في Firebase.

استخدام Sendgrid لإرسال الرسائل الإلكترونية

لا تسمح "دوال السحابة" باتصالات صادرة على المنفذ 25، لذلك لا يمكنك إجراء اتصالات غير آمنة إلى خادم SMTP. إنّ الطريقة الموصى بها لإرسال رسائل البريد الإلكتروني هي استخدام SendGrid. يمكنك العثور على خيارات أخرى لإرسال الرسائل الإلكترونية في الدليل التعليمي إرسال رسالة إلكترونية من مثيل لبرنامج Google Compute Engine.

الأداء

يوضّح هذا القسم أفضل الممارسات لتحسين الأداء.

استخدام التبعيات بحكمة

ولأن الدوال عديمة الحالة، غالبًا ما تتم تهيئة بيئة التنفيذ من البداية (خلال ما يُعرف باسم البدء البارد). عند حدوث البدء البارد، يتم تقييم السياق العام للدالة.

إذا كانت الدوال تستورِد وحدات، يمكن أن يزيد وقت تحميل هذه الوحدات من وقت استجابة الاستدعاء أثناء التشغيل على البارد. يمكنك تقليل وقت الاستجابة هذا، بالإضافة إلى الوقت اللازم لنشر الدالة، من خلال تحميل التبعيات بشكل صحيح وعدم تحميل التبعيات التي لا تستخدمها دالتك.

استخدام المتغيرات العمومية لإعادة استخدام العناصر في الاستدعاءات المستقبلية

وليس هناك ما يضمن الحفاظ على حالة دالة Cloud من أجل الاستدعاءات المستقبلية. ومع ذلك، غالبًا ما تُعيد دوال Cloud تدوير بيئة تنفيذ استدعاء سابق. إذا أعلنت عن متغير في النطاق العمومي، فيمكن إعادة استخدام قيمته في الاستدعاءات اللاحقة بدون الحاجة إلى إعادة الحساب.

بهذه الطريقة، يمكنك تخزين العناصر التي قد تكون مكلفة لإعادة إنشائها في كل استدعاء دالة. قد يؤدي نقل هذه الكائنات من النص الأساسي للدالة إلى النطاق العمومي إلى تحسينات كبيرة في الأداء. ينشئ المثال التالي كائنًا ثقيلًا فقط مرة واحدة لكل مثيل دالة، ويشاركه عبر جميع استدعاءات الدوال التي تصل إلى الحالة المحددة:

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

Python

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.

من المهم بشكل خاص تخزين اتصالات الشبكة ومراجع المكتبة وكائنات عميل واجهة برمجة التطبيقات في النطاق العمومي. راجع تحسين الشبكات للحصول على أمثلة.

إجراء الإعداد الكسول للمتغيرات العمومية

في حال تهيئة المتغيرات في النطاق العمومي، سيتم دائمًا تنفيذ رمز الإعداد من خلال استدعاء البدء على البارد، ما يؤدي إلى زيادة وقت استجابة الدالة. في بعض الحالات، يؤدي ذلك إلى مهلات متقطّعة للخدمات التي يتم طلبها إذا لم يتم التعامل معها بشكل مناسب في مجموعة 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');
});

Python

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 تلقائيًا عدد المثيلات بناءً على عدد الطلبات الواردة. يمكنك تغيير هذا السلوك التلقائي عن طريق ضبط حدّ أدنى لعدد الحالات التي يجب أن تظلّ فيها دوال Cloud جاهزة لخدمة الطلبات. يؤدي تعيين حد أدنى لعدد الحالات إلى تقليل بدء تشغيل التطبيق على البارد. نقترح ضبط حدّ أدنى لعدد المثيلات إذا كان تطبيقك حساسًا لوقت الاستجابة.

راجِع التحكّم في سلوك التوسيع للحصول على مزيد من المعلومات حول خيارات وقت التشغيل هذه.

مراجع إضافية

يمكنك الاطّلاع على مزيد من المعلومات عن تحسين الأداء في فيديو "Google Cloud Performance Atlas" وقت التشغيل على البارد لدوال Cloud.