نصائح

يصف هذا المستند أفضل الممارسات لتصميم وظائف السحابة الإلكترونية وتنفيذها واختبارها ونشرها

الإجابات الصحيحة

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

كتابة الدوال غير الثابتة

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

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

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

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