تستخدم العديد من الخدمات نمط التقييد للتحكم في الموارد التي تستهلكها، مع فرض قيود على معدل وصول التطبيقات أو الخدمات الأخرى إليها. يمكنك استخدام نمط تحديد المعدل لمساعدتك على تجنب أو تقليل أخطاء الازدحام المتعلقة بحدود التقييد هذه ولمساعدتك على التنبؤ بدقة أكبر بمعدل النقل.
يعد نمط تحديد المعدل مناسباً في العديد من السيناريوهات، ولكنه مفيد بشكل خاص للمهام الآلية المتكررة واسعة النطاق مثل معالجة دفعة من الملفات.
السياق والمشكلة
يمكن أن يؤدي إجراء عدد كبير من العمليات باستخدام خدمة مزدحمة إلى زيادة نسبة استخدام الشبكة ومعدل النقل، حيث ستحتاج إلى تتبع الطلبات المرفوضة ثم إعادة محاولة هذه العمليات. مع زيادة عدد العمليات، قد يتطلب حد الازدحام تمريرات متعددة لإعادة إرسال البيانات، ما يؤدي إلى تأثير أكبر على الأداء.
على سبيل المثال، ضع في اعتبارك إعادة المحاولة الساذجة التالية على عملية الخطأ لاستيعاب البيانات في Azure Cosmos DB:
- يحتاج تطبيقك إلى استيعاب 10000 سجل في Azure Cosmos DB. يتكلف كل سجل 10 وحدات طلب (RUs) لاستيعابها، وتتطلب ما مجموعه 100000 وحدة RU لإكمال المهمة.
- يحتوي مثيل Azure Cosmos DB الخاص بك على سعة توفير 20000 وحدة طلب/ وحدة طلب.
- ترسل جميع السجلات البالغ عددها 10000 سجل إلى Azure Cosmos DB. تتم كتابة 2000 سجل بنجاح ويتم رفض 8000 سجل.
- ترسل السجلات المتبقية البالغ عددها 8000 سجل إلى Azure Cosmos DB. تتم كتابة 2000 سجل بنجاح ويتم رفض 6000 سجل.
- ترسل السجلات المتبقية البالغ عددها 6000 سجل إلى Azure Cosmos DB. تتم كتابة 2000 سجل بنجاح ويتم رفض 4000 سجل.
- ترسل السجلات المتبقية البالغ عددها 4000 سجل إلى Azure Cosmos DB. تتم كتابة 2000 سجل بنجاح ويتم رفض 2000 سجل.
- ترسل السجلات المتبقية البالغ عددها 2000 سجل إلى Azure Cosmos DB. كلها مكتوبة بنجاح.
اكتملت مهمة الاستيعاب بنجاح، ولكن فقط بعد إرسال 30000 سجل إلى Azure Cosmos DB على الرغم من أن مجموعة البيانات بأكملها تتكون فقط من 10000 سجل.
هناك عوامل إضافية تجب مراعاتها في المثال أعلاه:
- يمكن أن يؤدي عدد كبير من الأخطاء أيضاً إلى عمل إضافي لتسجيل هذه الأخطاء ومعالجة بيانات السجل الناتجة. سيعالج هذا النهج الأصلي 20000 خطأ، وقد يؤدي تسجيل هذه الأخطاء إلى فرض تكلفة معالجة أو ذاكرة أو تخزين موارد.
- عدم معرفة حدود الازدحام لخدمة الاستيعاب، فإن النهج الساذج ليست لديه طريقة لتحديد توقعات للمدة التي ستستغرقها معالجة البيانات. يمكن أن يسمح لك تحديد السعر بحساب الوقت المطلوب للعرض.
حل
يمكن أن يؤدي تحديد المعدل إلى تقليل نسبة استخدام الشبكة الخاصة بك وتحسين معدل النقل عن طريق تقليل عدد السجلات المرسلة إلى خدمة خلال فترة زمنية معينة.
قد يتم ازدحام الخدمة بناءً على قياسات مختلفة بمرور الوقت، مثل:
- عدد العمليات (على سبيل المثال، 20 طلباً في الثانية).
- مقدار البيانات (على سبيل المثال، 2 جيجابايت في الدقيقة).
- التكلفة النسبية للعمليات (على سبيل المثال، 20000 طلب في الثانية).
بغض النظر عن المقياس المستخدم للاختناق، فإن تنفيذ الحد من المعدل الخاص بك سيشمل التحكم في عدد و/أو حجم العمليات المرسلة إلى الخدمة خلال فترة زمنية محددة، وتحسين استخدامك للخدمة مع عدم تجاوز قدرتها على التقييد.
في السيناريوهات التي يمكن فيها لواجهات برمجة التطبيقات معالجة الطلبات بشكل أسرع مما تسمح به أي خدمات استيعاب مقيدة، ستحتاج إلى إدارة مدى سرعة استخدامك للخدمة. ومع ذلك، فإن التعامل مع الازدحام على أنه مشكلة عدم تطابق معدل البيانات، وببساطة تخزين طلبات الاستيعاب مؤقتاً حتى تتمكن الخدمة المخنقة من اللحاق بالركب، يعد أمراً محفوفاً بالمخاطر. إذا تعطل تطبيقك في هذا السيناريو، فإنك تخاطر بفقدان أي من هذه البيانات المخزنة مؤقتاً.
لتجنب هذا الخطر، ضع في اعتبارك إرسال سجلاتك إلى نظام مراسلة دائم يمكنه التعامل مع معدل الاستيعاب الكامل. (يمكن لخدمات مثل مراكز الأحداث معالجة ملايين العمليات في الثانية). يمكنك بعد ذلك استخدام معالج مهام واحد أو أكثر لقراءة السجلات من نظام المراسلة بمعدل متحكم فيه ضمن حدود الخدمة المزدحمة. يمكن أن يؤدي إرسال السجلات إلى نظام المراسلة إلى توفير الذاكرة الداخلية من خلال السماح لك بإلغاء ترتيب السجلات التي يمكن معالجتها خلال فترة زمنية معينة فقط.
توفر Azure العديد من خدمات المراسلة الدائمة التي يمكنك استخدامها مع هذا النمط، بما في ذلك:
عند إرسال السجلات، قد تكون الفترة الزمنية التي تستخدمها لتحرير السجلات أكثر دقة من الفترة التي يتم فيها تقييد الخدمة. غالباً ما تضع الأنظمة قيوداً على فترات زمنية يمكنك فهمها والعمل معها بسهولة. ومع ذلك، بالنسبة للكمبيوتر الذي يقوم بتشغيل خدمة، قد تكون هذه الأطر الزمنية طويلة جداً مقارنة بالسرعة التي يمكن بها معالجة المعلومات. على سبيل المثال، قد يخنق النظام في الثانية أو في الدقيقة، ولكن عادةً ما تتم معالجة التعليمة البرمجية بترتيب النانوثانية أو الملّي ثانية.
رغم أنه ليس مطلوباً، يوصى غالباً بإرسال كميات أصغر من السجلات بشكل متكرر لتحسين معدل النقل. لذلك بدلا من محاولة تجميع الأشياء لإصدار مرة واحدة في الثانية أو مرة واحدة في الدقيقة، يمكنك أن تكون أكثر دقة من ذلك للحفاظ على استهلاك الموارد الخاصة بك (الذاكرة، وحدة المعالجة المركزية، والشبكة، وما إلى ذلك) تتدفق بمعدل أكثر التساوي، مما يمنع الاختناقات المحتملة بسبب اندفاعات مفاجئة من الطلبات. على سبيل المثال، إذا سمحت إحدى الخدمات بـ 100 عملية في الثانية، فقد يؤدي تنفيذ محدد المعدل إلى تجاوز الطلبات من خلال إصدار 20 عملية كل 200 ملّي ثانية، كما هو موضح في الرسم البياني التالي.
بالإضافة إلى ذلك، من الضروري في بعض الأحيان لعمليات متعددة غير منسقة مشاركة خدمة مزدحمة. لتنفيذ تحديد المعدل في هذا السيناريو، يمكنك تقسيم سعة الخدمة منطقياً ثم استخدام نظام الاستبعاد المتبادل الموزع لإدارة الأقفال الحصرية على تلك الأقسام. يمكن بعد ذلك أن تتنافس العمليات غير المنسقة للحصول على أقفال على تلك الأقسام متى احتاجت إلى سعة. لكل قسم تحتفظ العملية بقفل له، يتم منحها قدراً معيناً من السعة.
على سبيل المثال، إذا كان النظام الخانق يسمح بـ 500 طلب في الثانية، فيمكنك إنشاء 20 قسماً بقيمة 25 طلباً في الثانية لكل منها. إذا احتاجت العملية إلى إصدار 100 طلب، فقد تطلب من نظام الاستبعاد المتبادل الموزع لأربعة أقسام. قد يمنح النظام قسمين لمدة 10 ثوانٍ. ستقوم العملية بعد ذلك بتقييم الحد إلى 50 طلباً في الثانية، وإكمال المهمة في ثانيتين، ثم تحرير القفل.
تتمثل إحدى طرق تنفيذ هذا النمط في استخدام Azure Storage. في هذا السيناريو، تقوم بإنشاء blob واحد بحجم 0 بايت لكل قسم منطقي في الحاوية. يمكن لتطبيقاتك بعد ذلك الحصول على عقود إيجار حصرية مباشرة مقابل تلك النقاط الكبيرة لفترة زمنية قصيرة (على سبيل المثال، 15 ثانية). لكل عقد إيجار يتم منح تطبيق ما، سيكون قادراً على استخدام قيمة هذا القسم من السعة. يحتاج التطبيق بعد ذلك إلى تتبع وقت الإيجار بحيث يمكنه، عند انتهاء صلاحيته، التوقف عن استخدام السعة الممنوحة له. عند تنفيذ هذا النمط، ستحتاج غالباً إلى محاولة كل عملية تأجير قسم عشوائي عندما يحتاج إلى سعة.
لتقليل وقت الاستجابة بشكل أكبر، يمكنك تخصيص قدر صغير من السعة الحصرية لكل عملية. عندئذٍ، ستسعى العملية فقط إلى الحصول على عقد إيجار للقدرة المشتركة إذا احتاجت إلى تجاوز السعة المحجوزة لها.
كبديل ل Azure Storage، يمكنك أيضا تنفيذ هذا النوع من نظام إدارة التأجير باستخدام تقنيات مثل Zookeeper و Consul وما إلى ذلك وRedis/Redsync وغيرها.
المسائل والاعتبارات
ضع في اعتبارك ما يلي عند تحديد كيفية تنفيذ هذا النمط:
- بينما يمكن أن يقلل نمط تحديد المعدل من عدد أخطاء التقييد، سيظل تطبيقك بحاجة إلى معالجة أي أخطاء ازدحام قد تحدث بشكل صحيح.
- إذا كان التطبيق الخاص بك يحتوي على العديد من مسارات العمل التي تصل إلى نفس الخدمة المقيدة، فستحتاج إلى دمجها جميعاً في إستراتيجية تحديد الأسعار الخاصة بك. على سبيل المثال، قد تدعم تحميل السجلات المجمعة في قاعدة بيانات ولكن أيضاً تستعلم عن السجلات في نفس قاعدة البيانات. يمكنك إدارة السعة عن طريق التأكد من أن جميع مسارات العمل يتم إقرانها من خلال نفس آلية تحديد المعدل. بدلاً من ذلك، يمكنك حجز مجموعات منفصلة من السعة لكل مسار عمل.
- يمكن استخدام الخدمة المزدحمة في تطبيقات متعددة. في بعض الحالات - وليس جميعها - من الممكن تنسيق هذا الاستخدام (كما هو موضح أعلاه). إذا بدأت في رؤية عدد أكبر من المتوقع من أخطاء التقييد، فقد يكون هذا علامة على خلاف بين التطبيقات التي تصل إلى الخدمة. إذا كان الأمر كذلك، فقد تحتاج إلى التفكير مؤقتاً في تقليل معدل النقل الذي تفرضه آلية تحديد المعدل حتى ينخفض الاستخدام من التطبيقات الأخرى.
موعد استخدام النمط
استخدم هذا النمط من أجل:
- تقليل أخطاء التقييد التي تظهر بواسطة خدمة محدودة الخانق.
- تقليل نسبة استخدام الشبكة مقارنةً بإعادة المحاولة الساذجة عند نهج الخطأ.
- قم بتقليل استهلاك الذاكرة عن طريق إلغاء ترتيب السجلات فقط عندما تكون هناك قدرة على معالجتها.
تصميم حمل العمل
يجب على المهندس المعماري تقييم كيفية استخدام نمط تحديد المعدل في تصميم حمل العمل الخاص به لمعالجة الأهداف والمبادئ التي تغطيها ركائز Azure Well-Architected Framework. على سبيل المثال:
الركيزة | كيف يدعم هذا النمط أهداف الركيزة |
---|---|
تساعد قرارات تصميم الموثوقية حمل العمل الخاص بك على الصمود في وجه الخلل وضمان استرداده إلى حالة تعمل بشكل كامل بعد حدوث فشل. | يحمي هذا التكتيك العميل من خلال الاعتراف بتقييدات وتكاليف الاتصال بالخدمة والوفاء بها عندما ترغب الخدمة في تجنب الاستخدام المفرط. - RE:07 الحفاظ على الذات |
كما هو الحال مع أي قرار تصميم، ضع في اعتبارك أي مفاضلات ضد أهداف الركائز الأخرى التي يمكن إدخالها مع هذا النمط.
مثال
يتيح التطبيق المثال التالي للمستخدمين إرسال سجلات من أنواع مختلفة إلى API. يوجد معالج مهام فريد لكل نوع سجل يقوم بتنفيذ الخطوات التالية:
- التحقق من الصحة
- الإثراء
- إدراج السجل في قاعدة البيانات
جميع مكونات التطبيق (API، ومعالج الوظيفة A، ومعالج الوظيفة B) هي عمليات منفصلة يمكن تحجيمها بشكل مستقل. العمليات لا تتواصل مباشرة مع بعضها.
يتضمن هذا الرسم التخطيطي سير العمل التالي:
- يرسل المستخدم 10000 سجل من النوع أ إلى API.
- تقوم واجهة برمجة التطبيقات (API) بإدراج تلك الـ 10000 سجل في قائمة الانتظار أ.
- يرسل المستخدم 5000 سجل من النوع B إلى API.
- يقوم API بإدراج 5000 سجل في قائمة الانتظار B.
- يرى Job Processor A أن قائمة الانتظار A بها سجلات وتحاول الحصول على عقد إيجار حصري على blob 2.
- يرى Job Processor B أن قائمة الانتظار B بها سجلات وتحاول الحصول على عقد إيجار حصري على blob 2.
- فشل Job Processor A في الحصول على عقد الإيجار.
- تحصل Job Processor B على عقد إيجار في blob 2 لمدة 15 ثانية. يمكنه الآن تصنيف طلبات الحد إلى قاعدة البيانات بمعدل 100 في الثانية.
- يقوم Job Processor B بفصل 100 سجل من قائمة الانتظار B ويكتبها.
- ثانية واحدة تمر.
- يرى Job Processor A أن قائمة الانتظار A بها المزيد من السجلات وتحاول الحصول على عقد إيجار حصري على blob 6.
- يرى Job Processor B أن قائمة الانتظار B بها المزيد من السجلات وتحاول الحصول على عقد إيجار حصري على blob 3.
- تحصل Job Processor A على عقد إيجار في blob 6 لمدة 15 ثانية. يمكنه الآن تصنيف طلبات الحد إلى قاعدة البيانات بمعدل 100 في الثانية.
- تحصل Job Processor B على عقد إيجار في blob 3 لمدة 15 ثانية. يمكنه الآن تصنيف طلبات الحد إلى قاعدة البيانات بمعدل 200 في الثانية. (يحمل أيضاً عقد إيجار blob 2.)
- يقوم Job Processor A بإزالة 100 سجل من قائمة الانتظار A ويكتبها.
- يقوم Job Processor B بفصل 200 سجل من قائمة الانتظار B ويكتبها.
- ثانية واحدة تمر.
- يرى Job Processor A أن قائمة الانتظار A بها المزيد من السجلات وتحاول الحصول على عقد إيجار حصري على blob 0.
- يرى Job Processor B أن قائمة الانتظار B بها المزيد من السجلات وتحاول الحصول على عقد إيجار حصري على blob 1.
- تحصل Job Processor A على عقد إيجار في blob 0 لمدة 15 ثانية. يمكنه الآن تصنيف طلبات الحد إلى قاعدة البيانات بمعدل 200 في الثانية. (يحمل أيضاً عقد إيجار blob 6.)
- تحصل Job Processor B على عقد إيجار في blob 1 لمدة 15 ثانية. يمكنه الآن تصنيف طلبات الحد إلى قاعدة البيانات بمعدل 300 في الثانية. (كما أنه يحمل عقد إيجار النقطتين 2 و3)
- يقوم Job Processor A بإزالة 200 سجل من قائمة الانتظار A ويكتبها.
- يقوم Job Processor B بفصل 300 سجل من قائمة الانتظار B ويكتبها.
- وهلم جراً...
بعد 15 ثانية، لا تزال إحدى المهمتين أو كلتيهما غير مكتملة. مع انتهاء صلاحية عقود الإيجار، يجب على المعالج أيضاً تقليل عدد الطلبات التي يزيلها ويكتبها.
تتوفر تطبيقات هذا النمط بلغات برمجة مختلفة:
الموارد ذات الصلة
قد تكون الأنماط والتوجيهات التالية ذات صلة أيضًا عند تنفيذ هذا النمط:
- الخنق. عادةً ما يتم تنفيذ نمط تحديد المعدل الذي تمت مناقشته هنا استجابةً لخدمة مقيدة.
- أعد المحاولة. عندما تؤدي طلبات الخدمة المقيدة إلى حدوث أخطاء في التقييد، فمن المناسب عموماً إعادة المحاولة بعد فترة زمنية مناسبة.
تسوية الحِمل المعتمد على قائمة الانتظار مشابه ولكنه يختلف عن نمط تحديد المعدل من عدة نواحٍ رئيسية:
- لا يحتاج تحديد السعر بالضرورة إلى استخدام قوائم الانتظار لإدارة الحمل، ولكنه يحتاج إلى الاستفادة من خدمة رسائل دائمة. على سبيل المثال، يمكن لنمط تحديد المعدل الاستفادة من خدمات مثل Apache Kafka أو مراكز الأحداث.
- يقدم نمط تحديد المعدل مفهوم نظام الاستبعاد المتبادل الموزع على الأقسام، والذي يسمح لك بإدارة السعة لعمليات متعددة غير منسقة تتواصل مع نفس الخدمة المزدحمة.
- يمكن تطبيق نمط تسوية الحِمل المستند إلى قائمة الانتظار في أي وقت يوجد فيه عدم تطابق في الأداء بين الخدمات أو لتحسين المرونة. هذا يجعله نمطاً أوسع من تحديد المعدل، والذي يهتم بشكل أكثر تحديداً بالوصول الفعال إلى خدمة مزدحمة.