الأداء والنطاق في Durable Functions (Azure Functions)

لتحسين الأداء وقابلية التوسع، من المهم فهم خصائص التحجيم الفريدة لـ Durable Functions. في هذه المقالة، نوضح كيف يتم قياس العمال بناءً على الحمل، وكيف يمكن ضبط المعلمات المختلفة.

تحجيم عامل

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

يوضح الرسم التخطيطي التالي هذا المفهوم:

مخطط تحجيم العامل

التحجيم التلقائي

كما هو الحال مع جميع Azure Functions التي تعمل في خطط الاستهلاك والتقسيط المريح، تدعم Durable Functions التحجيم التلقائي عبر وحدة تحكم مقياس Azure Functions. يراقب Scale Controller المدة التي يجب أن تنتظرها الرسائل والمهام قبل معالجتها. بناءً على فترات الاستجابة هذه، يمكن أن تقرر ما إذا كنت تريد إضافة العمال أو إزالتهم.

إشعار

بدءًا من Durable Functions 2.0، يمكن تكوين تطبيقات الدوال لتعمل ضمن نقاط نهاية الخدمة المحمية من VNET في خطة التقسيط المريح. في هذا التكوين، تشغّل Durable Functions بدء طلبات المقياس بدلاً من وحدة تحكم المقياس. لمزيد من المعلومات، راجع مراقبة مقياس وقت التشغيل.

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

استخدام المعالج

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

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

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

مهلات الدوال

تخضع دوال النشاط والمنسق والكيان لنفس مُهلات الدالة مثل جميع Azure Functions. كقاعدة عامة، تعامل Durable Functions مُهلات الدالة بنفس الطريقة التي تعامل بها الاستثناءات غير المعالجة التي تم طرحها بواسطة التعليمات البرمجية للتطبيق.

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

تجميع عمليات الكيان

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

بشكل افتراضي، الحد الأقصى لحجم الدُفعة هو 50 لخطط الاستهلاك و 5000 لجميع الخطط الأخرى. يمكن أيضاً تكوين الحد الأقصى لحجم الدفعة في ملف host.json. إذا كان الحد الأقصى لحجم الدفعة هو 1، يتم تعطيل الدفعات بشكلٍ فعال.

إشعار

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

التخزين المؤقت للمثيل

وبشكل عام، لمعالجة عنصر عمل تزامن، يجب على العامل كليهما

  1. يزيل تاريخ التزامن.
  2. وأعد تشغيل التعليمات البرمجية للمنسق باستخدام المحفوظات.

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

يتم تقليل التأثير النموذجي للتخزين المؤقت للإدخال/ الإخراج مقابل خدمة التخزين الأساسية، وتحسين الإنتاجية ومعدل النقل بشكل عام. ومن ناحية أخرى، يزيد التخزين المؤقت من استهلاك الذاكرة على العامل.

يتم دعم التخزين المؤقت للمثيلات حاليًا بواسطة موفر Azure Storage وموفر التخزين Netherite. يوفر الجدول أدناه مقارنة.

موفر Azure Storage موفر تخزين Netherite موفر تخزين MSSQL
تخزين مؤقت فوري مدعوم
(عامل .NET قيد المعالجة فقط)
مدعوم غير مدعوم
الإعداد الافتراضي مُعطل مُمَكّن غير متوفر
آلِيَّة جلسات موسعة ذاكرة تخزين مؤقت لمثيل غير متوفر
الوثائق راجع جلسات موسعة راجع ذاكرة تخزين مؤقت لمثيل غير متوفر

تلميح

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

مقارنة آليات التخزين المؤقت

ويستخدم الموفرون آليات مختلفة لتنفيذ التخزين المؤقت، ويقدمون معلمات مختلفة لتكوين سلوك التخزين المؤقت.

  • جلسات العمل الموسعة، كما يستخدمها موفر Azure Storage، بمنسقي منتصف التنفيذ في الذاكرة حتى تصبح خامدة لبعض الوقت. المعلمات للتحكم في هذه الآلية هي extendedSessionsEnabled وextendedSessionIdleTimeoutInSeconds. ولمزيد من التفاصيل، راجع القسم جلسات عمل موسعة من وثائق موفر Azure Storage.

إشعار

ويتم دعم جلسات العمل الموسعة فقط في عامل .NET قيد المعالجة.

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

إشعار

كما تعمل ذاكرة التخزين المؤقت للمثيل لجميع حزم SDK للغة، ولكن CacheOrchestrationCursors الخيار متاح فقط للعامل قيد المعالجة .NET.

تقييدات التزامن

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

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

إشعار

تنطبق قيود التزامن محليًا فقط، للحد مما تتم معالجته حالياً على عامل واحد. وبالتالي، لا تحد هذه التقييدات من إجمالي معدل النقل للنظام.

تلميح

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

تكوين التقييدات

يمكن تكوين حدود التزامن لدوال النشاط والمنسق والكيان في ملف host.json. الإعدادات ذات الصلة هي durableTask/maxConcurrentActivityFunctions لدوال النشاط وdurableTask/maxConcurrentOrchestratorFunctions لكل من دوال المنسق والكيان. تتحكم هذه الإعدادات في الحد الأقصى لعدد وظائف المنسق أو الكيان أو النشاط التي يتم تحميلها في الذاكرة لعامل واحد.

إشعار

لا يتم تحميل التنظيمات والكيانات إلا في الذاكرة عندما تقوم بمعالجة الأحداث أو العمليات بنشاط، أو إذا تم تمكين التخزين المؤقت للمثيل. وبعد تنفيذ منطقها والانتظار (أي إدخال عبارة await (C#) أو yield (JavaScript، Python) في التعليمات البرمجية لدالة المنسق)، يتم إلغاء تحميلها من الذاكرة. لا تُحسب التنسيقات والكيانات التي تم إلغاء تحميلها من الذاكرة باتجاه تقييد maxConcurrentOrchestratorFunctions. حتى إذا كانت ملايين التنسيقات أو الكيانات في الحالة "قيد التشغيل"، فإنها تُحسب فقط نحو حد التقييد عند تحميلها في الذاكرة النشطة. لا يُحسب التنسيق الذي يجدول دالة نشاط بشكل مشابه باتجاه التقييد إذا كان التنسيق ينتظر انتهاء تنفيذ النشاط.

الدوال 2.0

{
  "extensions": {
    "durableTask": {
      "maxConcurrentActivityFunctions": 10,
      "maxConcurrentOrchestratorFunctions": 10
    }
  }
}

دالات 1.x

{
  "durableTask": {
    "maxConcurrentActivityFunctions": 10,
    "maxConcurrentOrchestratorFunctions": 10
  }
}

اعتبارات وقت تشغيل اللغة

قد يفرض وقت تشغيل اللغة الذي تحدده قيودًا صارمة على التزامن أو على الدوال. على سبيل المثال، يجوز لتطبيقات Durable Function المكتوبة بلغات Python أو PowerShell أن تدعم فقط تشغيل دالة واحدة في المرة على جهاز ظاهري واحد. يمكن أن يؤدي هذا إلى مشاكل أداء كبيرة إذا لم يتم أخذه بعين الاعتبار بعناية. على سبيل المثال، إذا تم توزيع المنسق على 10 أنشطة ولكن وقت تشغيل اللغة يقيد التزامن لدالة واحدة فقط، فإن 9 من 10 دوال نشاط ستكون عالقة في انتظار فرصة لتشغيلها. علاوة على ذلك، لن يكون بالإمكان تحميل هذه الأنشطة التسعة العالقة بشكل متوازن على أي عامل آخر لأن وقت تشغيل Durable Functions سيكون قد حمّلها بالفعل في الذاكرة. يصبح هذا مشكلة بصفة خاصة إذا كانت دوال النشاط طويلة الأمد.

إذا كان وقت تشغيل اللغة الذي تستخدمه يضع قيدا على التزامن، فيجب تحديث إعدادات تزامن Durable Functions لمطابقة إعدادات التزامن لوقت تشغيل اللغة. وهذا يضمن أن وقت تشغيل Durable Functions لن يحاول تشغيل المزيد من الدوال بشكل متزامن أكثر مما يسمح به وقت تشغيل اللغة، مما يسمح لأية أنشطة معلقة أن تكون متوازنة التحميل على الأجهزة الظاهرية الأخرى. وعلى سبيل المثال، إذا كان لديك تطبيق Python يقيد التزامن على 4 دوال (ربما تم تكوينها باستخدام 4 مؤشرات ترابط فقط على عملية عامل لغة واحدة أو مؤشر ترابط واحد على 4 عمليات عامل لغة)، فيجب عليك تكوين كل من maxConcurrentOrchestratorFunctions وmaxConcurrentActivityFunctions على 4.

لمزيد من المعلومات وتوصيات الأداء لـ Python، راجع تحسين أداء معدل النقل لتطبيقات Python في Azure Functions. إن التقنيات المذكورة في الوثائق المرجعية لمطور Python يمكن أن يكون لها تأثيرًا كبيرًا على أداء Durable Functions وقابليتها التوسع.

عدد الأقسام

كما يستخدم بعض موفري التخزين آلية تقسيم ويسمحون بتحديد معلمة partitionCount.

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

إشعار

ويتم توسيع حدود التقسيم لأنه في معظم العاملين partitionCount يمكنهم معالجة عناصر العمل من قائمة انتظار مقسمة.

ويوضح الجدول التالي، لكل موفر تخزين، قوائم الانتظار المقسمة، والنطاق المسموح به والقيم الافتراضية للمعلمة partitionCount.

موفر Azure Storage موفر تخزين Netherite موفر تخزين MSSQL
رسائل مثيل مقسم مقسم غير مقسم
رسائل نشاط غير مقسم مقسم غير مقسم
افتراضي partitionCount 4 12 غير متوفر
حد أقصى partitionCount 16 32 غير متوفر
الوثائق راجع توسيع نطاق المنسق راجع اعتبارات عدد القسم غير متوفر

تحذير

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

تكوين عدد الأقسام

يمكن تحديد المعلمة partitionCount في ملف host.json. المثال التالي لقصاصات host.json البرمجية يعيّن خاصية durableTask/storageProvider/partitionCount (أو durableTask/partitionCount في Durable Functions 1.x) على 3.

الدوال الدائمة 2.x

{
  "extensions": {
    "durableTask": {
      "storageProvider": {
        "partitionCount": 3
      }
    }
  }
}

Durable Functions 1.x

{
  "extensions": {
    "durableTask": {
      "partitionCount": 3
    }
  }
}

اعتبارات لتقليل زمن انتقال استدعاء

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

أهداف الأداء

عند التخطيط لاستخدام Durable Functions لتطبيق إنتاج، من المهم مراعاة متطلبات الأداء في وقت مبكر من عملية التخطيط. وتتضمن بعض سيناريوهات الاستخدام الأساسية ما يلي:

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

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

تلميح

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

الخطوات التالية