توضح هذه المقالة كيف استخدم فريق التطوير القياسات للعثور على الازدحام وتحسين أداء النظام الموزَّع. تستند المقالة إلى اختبار التحميل الفعلي الذي تم إجراؤه لتطبيق نموذجي. التطبيق من خط الأساس لخدمة Azure Kubernetes (AKS) للخدمات المصغرة، إلى جانب مشروع اختبار تحميل Visual Studio المستخدم لإنشاء النتائج.
هذا المقال جزء من سلسلة مقالات. اقرأ الجزء الأول هنا.
السيناريو: اتصل بخدمات خلفية متعددة لاسترداد المعلومات ثم تجميع النتائج.
يتضمن هذا السيناريو تطبيق توصيل بدون طيار. يمكن للعملاء الاستعلام عن REST API للحصول على أحدث معلومات الفاتورة. تتضمن الفاتورة ملخصاً لتسليمات العميل، وحزمه، واستخدامه الكلي للطائرة بدون طيار. يستخدم هذا التطبيق بنية الخدمات المصغرة التي تعمل على AKS، ويتم نشر المعلومات المطلوبة للفاتورة عبر العديد من الخدمات المصغرة.
بدلاً من استدعاء العميل لكل خدمة مباشرةً، يقوم التطبيق بتنفيذ نمط بوابة Aggregation. باستخدام هذا النمط، يقوم العميل بتقديم طلب واحد لخدمة البوابة. تقوم البوابة بدورها باستدعاء خدمات الواجهة الخلفية بالتوازي، ثم تقوم بتجميع النتائج في حمولة استجابة واحدة.
الاختبار الأول: الأداء الأساسي
لإنشاء خط أساس، بدأ فريق التطوير باختبار تحميل متدرج، ما أدى إلى زيادة التحميل من مستخدم تمت محاكاته إلى 40 مستخدماً، على مدار مدة إجمالية قدرها 8 دقائق. يظهر الرسم البياني التالي المأخوذ من Visual Studio النتائج. يُظهر الخط الأرجواني حمل المستخدم، ويعرض الخط البرتقالي معدل النقل (متوسط الطلبات في الثانية).
يُظهر الخط الأحمر على طول الجزء السفلي من الرسم البياني أنه لم يتم إرجاع أي أخطاء إلى العميل، وهو أمر مشجع. ومع ذلك، يبلغ متوسط معدل النقل ذروته في منتصف الاختبار تقريباً، ثم ينخفض للباقي، حتى مع استمرار زيادة التحميل. يشير ذلك إلى أن النهاية الخلفية غير قادرة على الاستمرار. يعتبر النمط الموضح هنا شائعاً عندما يبدأ النظام في الوصول إلى حدود الموارد - بعد الوصول إلى الحد الأقصى، ينخفض معدل النقل بشكل كبير. يمكن أن يساهم التنازع على الموارد أو الأخطاء العابرة أو زيادة معدل الاستثناءات في هذا النمط.
دعنا نتعمق في بيانات المراقبة لمعرفة ما يحدث داخل النظام. الرسم البياني التالي مأخوذ من Application Insights. يعرض متوسط مدد مكالمات HTTP من البوابة إلى خدمات الواجهة الخلفية.
يوضح هذا الرسم البياني أن عملية واحدة على وجه الخصوص، GetDroneUtilization
، تستغرق وقتاً أطول في المتوسط - بترتيب من حيث الحجم. تقوم البوابة بإجراء هذه المكالمات بالتوازي، لذا فإن أبطأ عملية تحدد المدة التي يستغرقها الطلب بأكمله.
من الواضح أن الخطوة التالية هي الخوض في عملية GetDroneUtilization
والبحث عن أي ازدحام. أحد الاحتمالات هو استنفاد الموارد. ربما تنفد وحدة المعالجة المركزية أو الذاكرة من خدمة الواجهة الخلفية هذه. بالنسبة إلى مجموعة AKS، تتوفر هذه المعلومات في مدخل Microsoft Azure من خلال ميزة رؤى حاوية Azure Monitor. توضح الرسوم البيانية التالية استخدام الموارد على مستوى نظام المجموعة:
في لقطة الشاشة هذه، يتم عرض كل من القيم المتوسطة والحد الأقصى. من المهم النظر إلى أكثر من مجرد المتوسط، لأن المتوسط يمكن أن يخفي طفرات في البيانات. هنا، يظل متوسط استخدام وحدة المعالجة المركزية أقل من 50%، ولكن هناك بعض الارتفاع إلى 80%. هذا قريب من السعة ولكن لا يزال ضمن التفاوتات المسموح بها. شيء آخر يسبب الاختناق.
الرسم البياني التالي يكشف الجاني الحقيقي. يعرض هذا المخطط رموز استجابة HTTP من قاعدة بيانات الواجهة الخلفية لخدمة التسليم، والتي في هذه الحالة هي Azure Cosmos DB. يمثل الخط الأزرق أكواد النجاح (HTTP 2xx)، بينما يمثل الخط الأخضر أخطاء HTTP 429. تعني التعليمات البرمجية لإرجاع HTTP 429 أن Azure Cosmos DB هو طلبات تقييد مؤقتة، لأن المتصل يستهلك وحدات موارد (RU) أكثر من المتوفرة.
للحصول على مزيد من المعلومات، استخدم فريق التطوير Application Insights لعرض القياسي عن بُعد من طرف إلى طرف لعينة تمثيلية من الطلبات. هنا مثال واحد:
يُظهر هذا العرض المكالمات المتعلقة بطلب عميل واحد، إلى جانب معلومات التوقيت والتعليمة البرمجية للاستجابة. تأتي مكالمات المستوى الأعلى من البوابة إلى خدمات الواجهة الخلفية. يتم توسيع الاستدعاء GetDroneUtilization
إلى لإظهار الاستدعاءات إلى التبعيات الخارجية — في هذه الحالة، إلى Azure Cosmos DB. عرضت المكالمة باللون الأحمر خطأ HTTP 429.
لاحظ الفجوة الكبيرة بين خطأ HTTP 429 والاستدعاء التالي. عندما تتلقى مكتبة عميل Azure Cosmos DB خطأ HTTP 429، فإنها تتراجع تلقائيا وتنتظر لإعادة محاولة العملية. ما يظهره هذا العرض هو أنه خلال 672 مللي ثانية استغرقتها هذه العملية، تم قضاء معظم ذلك الوقت في انتظار إعادة محاولة Azure Cosmos DB.
إليك رسماً بيانياً آخر مثيراً للاهتمام لهذا التحليل. يُظهر استهلاك RU لكل قسم مادي مقابل وحدات RU المتوفرة لكل قسم مادي:
لفهم هذا الرسم البياني، تحتاج إلى فهم كيفية إدارة Azure Cosmos DB للأقسام. يمكن أن تحتوي المجموعات في Azure Cosmos DB على مفتاح قسم. تحدد كل قيمة مفتاح ممكنة قسماً منطقياً للبيانات داخل المجموعة. يوزع Azure Cosmos DB هذه الأقسام المنطقية عبر قسم فعلي واحد أو أكثر. تتم معالجة إدارة الأقسام المادية تلقائيا بواسطة Azure Cosmos DB. أثناء تخزين المزيد من البيانات، قد ينقل Azure Cosmos DB الأقسام المنطقية إلى أقسام فعلية جديدة، من أجل نشر الحمل عبر الأقسام المادية.
بالنسبة لاختبار التحميل هذا، تم تزويد مجموعة Azure Cosmos DB ب 900 وحدة طلب. يعرض الرسم البياني 100 وحدة طلب لكل قسم مادي، ما يعني إجمالي تسعة أقسام فعلية. على الرغم من أن Azure Cosmos DB يعالج تلقائيا تقسيم الأقسام المادية، فإن معرفة عدد الأقسام يمكن أن يعطي نظرة ثاقبة على الأداء. سيستخدم فريق التطوير هذه المعلومات لاحقاً، حيث يواصلون التحسين. عندما يتقاطع الخط الأزرق مع الخط الأفقي الأرجواني، يكون استهلاك RU قد تجاوز وحدات RU المتوفرة. هذه هي النقطة التي سيبدأ فيها Azure Cosmos DB في تقييد المكالمات.
الاختبار 2: زيادة وحدات الموارد
بالنسبة لاختبار التحميل الثاني، تحجيم الفريق لمجموعة Azure Cosmos DB من 900 RU إلى 2500 RU. زاد معدل النقل من 19 طلباً / ثانية إلى 23 طلباً / ثانية، وانخفض متوسط وقت الاستجابة من 669 مللي ثانية إلى 569 مللي ثانية.
قياس | اختبار 1 | اختبار 2 |
---|---|---|
معدل النقل (طلب/ثانية) | 19 | 23 |
متوسط زمن الوصول (مللي ثانية) | 669 | 569 |
طلبات ناجحة | 9.8 K | 11 K |
هذه ليست مكاسب ضخمة، لكن النظر إلى الرسم البياني بمرور الوقت يظهر صورة أكثر اكتمالاً:
في حين أظهر الاختبار السابق ارتفاعاً أولياً متبوعاً بانخفاض حاد، يُظهر هذا الاختبار معدل نقل أكثر اتساقاً. ومع ذلك، فإن الحد الأقصى لمعدل النقل ليس أعلى بكثير.
أرجعت جميع الطلبات إلى Azure Cosmos DB حالة 2xx، وذهبت أخطاء HTTP 429 بعيدا:
يوضح الرسم البياني لاستهلاك RU مقابل وحدات RU المقدمة أن هناك الكثير من الارتفاع. يوجد حوالي 275 وحدة طلب لكل قسم مادي، وبلغ اختبار التحميل ذروته عند حوالي 100 وحدة طلب مستهلكة في الثانية.
مقياس آخر مثير للاهتمام هو عدد الاستدعاءات إلى Azure Cosmos DB لكل عملية ناجحة:
قياس | اختبار 1 | اختبار 2 |
---|---|---|
المكالمات لكل عملية | 11 | 9 |
بافتراض عدم وجود أخطاء، يجب أن يتطابق عدد المكالمات مع خطة الاستعلام الفعلية. في هذه الحالة، تتضمن العملية استعلام تقسيم مشترك يصل إلى جميع الأقسام المادية التسعة. تعكس القيمة الأعلى في اختبار التحميل الأول عدد المكالمات التي أرجع الخطأ 429.
تم حساب هذا المقياس عن طريق تشغيل استعلام تحليلات سجل مخصص:
let start=datetime("2020-06-18T20:59:00.000Z");
let end=datetime("2020-07-24T21:10:00.000Z");
let operationNameToEval="GET DroneDeliveries/GetDroneUtilization";
let dependencyType="Azure DocumentDB";
let dataset=requests
| where timestamp > start and timestamp < end
| where success == true
| where name == operationNameToEval;
dataset
| project reqOk=itemCount
| summarize
SuccessRequests=sum(reqOk),
TotalNumberOfDepCalls=(toscalar(dependencies
| where timestamp > start and timestamp < end
| where type == dependencyType
| summarize sum(itemCount)))
| project
OperationName=operationNameToEval,
DependencyName=dependencyType,
SuccessRequests,
AverageNumberOfDepCallsPerOperation=(TotalNumberOfDepCalls/SuccessRequests)
للتلخيص، يُظهر اختبار التحميل الثاني التحسن. ومع ذلك، لا تزال العملية GetDroneUtilization
تستغرق وقتاً أطول بمقدار الترتيب من العملية التالية الأبطأ. يساعد النظر إلى العمليات الشاملة على توضيح السبب:
كما ذكرنا سابقا، GetDroneUtilization
تتضمن العملية استعلاما عبر الأقسام إلى Azure Cosmos DB. وهذا يعني أن عميل Azure Cosmos DB يجب أن يقوم بتهييج الاستعلام لكل قسم فعلي وجمع النتائج. كما يظهر في عرض العملية من طرف إلى طرف، يتم تنفيذ هذه الاستعلامات في تسلسلي. تستغرق العملية ما دام مجموع جميع الاستعلامات - وستزداد هذه المشكلة سوءاً مع نمو حجم البيانات وإضافة المزيد من الأقسام المادية.
الاختبار 3: الاستعلامات الموازية
استناداً إلى النتائج السابقة، تتمثل إحدى الطرق الواضحة لتقليل وقت الاستجابة في إصدار الاستعلامات بشكل متوازٍ. يحتوي SDK لعميل Azure Cosmos DB على إعداد يتحكم في الحد الأقصى لدرجة التوازي.
القيمة | الوصف |
---|---|
0 | بلا توازٍ (افتراضي) |
> 0 | الحد الأقصى لعدد المكالمات الموازية |
-1 | يحدد العميل SDK درجة مثالية من التوازي |
بالنسبة لاختبار التحميل الثالث، تم تغيير هذا الإعداد من 0 إلى -1. يلخص الجدول التالي النتائج:
قياس | اختبار 1 | اختبار 2 | اختبار 3 |
---|---|---|---|
معدل النقل (طلب/ثانية) | 19 | 23 | 42 |
متوسط زمن الوصول (مللي ثانية) | 669 | 569 | 215 |
طلبات ناجحة | 9.8 K | 11 K | 20 K |
طلبات مقيدة | 2.72 K | 0 | 0 |
من الرسم البياني لاختبار التحميل، ليس فقط معدل النقل الإجمالي أعلى بكثير (الخط البرتقالي)، ولكن أيضاً معدل النقل يتماشى مع التحميل (الخط الأرجواني).
يمكننا التحقق من أن عميل Azure Cosmos DB يقوم بإجراء استعلامات بالتوازي من خلال النظر إلى طريقة عرض المعاملة الشاملة:
ومن المثير للاهتمام أن أحد الآثار الجانبية لزيادة معدل النقل هو زيادة عدد وحدات RU المستهلكة في الثانية أيضاً. على الرغم من أن Azure Cosmos DB لم يقيد أي طلبات أثناء هذا الاختبار، إلا أن الاستهلاك كان قريبا من حد RU المتوفر:
قد يكون هذا الرسم البياني إشارة لتوسيع نطاق قاعدة البيانات. ومع ذلك، اتضح أنه يمكننا تحسين الاستعلام بدلاً من ذلك.
الخطوة 4: تحسين الاستعلام
أظهر اختبار التحميل السابق أداءً أفضل من حيث وقت الاستجابة ومعدل النقل. تم تقليل متوسط وقت استجابة الطلب بنسبة 68% وزيادة معدل النقل بنسبة 220%. ومع ذلك، فإن استعلام التقسيم المشترك هو مصدر قلق.
تكمن مشكلة الاستعلامات عبر الأقسام في أنك تدفع مقابل RU عبر كل قسم. إذا تم تشغيل الاستعلام فقط من حين لآخر - على سبيل المثال، مرة واحدة في الساعة - فقد لا يكون ذلك مهماً. ولكن عندما ترى حمل عمل ثقيل القراءة يتضمن استعلاماً متعدد الأقسام، يجب أن ترى ما إذا كان يمكن تحسين الاستعلام عن طريق تضمين مفتاح القسم. (قد تحتاج إلى إعادة تصميم المجموعة لاستخدام مفتاح قسم مختلف.)
هذا هو الاستعلام عن هذا السيناريو بالذات:
SELECT * FROM c
WHERE c.ownerId = <ownerIdValue> and
c.year = <yearValue> and
c.month = <monthValue>
يحدد هذا الاستعلام السجلات التي تتطابق مع معرف مالك معين وشهر / سنة. في التصميم الأصلي، لا تكون أي من هذه الخصائص هي مفتاح القسم. يتطلب ذلك من العميل نشر الاستعلام لكل قسم فعلي وجمع النتائج. لتحسين أداء الاستعلام، قام فريق التطوير بتغيير التصميم بحيث يكون معرف المالك هو مفتاح القسم للمجموعة. بهذه الطريقة، يمكن أن يستهدف الاستعلام قسماً مادياً معيناً. (يعالج Azure Cosmos DB هذا تلقائيا؛ ليس عليك إدارة التعيين بين قيم مفتاح القسم والأقسام المادية.)
بعد تحويل المجموعة إلى مفتاح القسم الجديد، كان هناك تحسن كبير في استهلاك RU، والذي يترجم مباشرة إلى انخفاض التكاليف.
قياس | اختبار 1 | اختبار 2 | اختبار 3 | اختبار 4 |
---|---|---|---|---|
RUs لكل عملية | 29 | 29 | 29 | 3.4 |
المكالمات لكل عملية | 11 | 9 | 10 | 1 |
يُظهر عرض العملية من طرف إلى طرف أنه كما هو متوقع، يقرأ الاستعلام قسماً مادياً واحداً فقط:
يُظهر اختبار التحميل تحسين معدل النقل ووقت الاستجابة:
قياس | اختبار 1 | اختبار 2 | اختبار 3 | اختبار 4 |
---|---|---|---|---|
معدل النقل (طلب/ثانية) | 19 | 23 | 42 | 59 |
متوسط زمن الوصول (مللي ثانية) | 669 | 569 | 215 | 176 |
طلبات ناجحة | 9.8 K | 11 K | 20 K | 29 K |
طلبات مقيدة | 2.72 K | 0 | 0 | 0 |
نتيجة لتحسين الأداء هو أن استخدام وحدة المعالجة المركزية للعقدة يصبح مرتفعاً جداً:
قرب نهاية اختبار التحميل وصل متوسط وحدة المعالجة المركزية إلى حوالي 90%، ووصل الحد الأقصى لوحدة المعالجة المركزية إلى 100%. يشير هذا المقياس إلى أن وحدة المعالجة المركزية هي الازدحام التالي في النظام. إذا كانت هناك حاجة إلى معدل نقل أعلى، فقد تكون الخطوة التالية هي توسيع نطاق خدمة التسليم لتشمل المزيد من الحالات.
الملخص
بالنسبة لهذا السيناريو، تم تحديد الازدحام التالية:
- طلبات تقييد Azure Cosmos DB بسبب عدم كفاية وحدات الطلب المتوفرة.
- وقت الاستجابة مرتفع ناتج عن الاستعلام عن أقسام قاعدة بيانات متعددة في التسلسل.
- استعلام التقسيم المشترك غير الفعال، لأن الاستعلام لا يتضمن مفتاح القسم.
بالإضافة إلى ذلك، تم تحديد استخدام وحدة المعالجة المركزية باعتباره الازدحام المحتمل على نطاق أعلى. لتشخيص هذه المشكلات، نظر فريق التطوير إلى:
- وقت الاستجابة ومعدل النقل من اختبار التحميل.
- أخطاء Azure Cosmos DB واستهلاك RU.
- عرض العملية من طرف إلى طرف في Application Insight.
- استخدام وحدة المعالجة المركزية والذاكرة في نتائج تحليلات حاوية Azure Monitor.