بدون فصل الأحمال ذي الأولوية، ينخفض التوفر الذي يبدأه المستخدم والجلب المسبق عند إضافة زمن الاستجابة. ومع ذلك، بعد إضافة أولوية توزيع الأحمال، تحافظ الطلبات التي يبدأها المستخدم على التوفر بنسبة 100% ويتم تقييد طلبات الجلب المسبق فقط.
لقد كنا مستعدين لطرح هذا المنتج في مرحلة الإنتاج ورؤية مدى أدائه في البرية!
التطبيق والنتائج في العالم الحقيقي
يعمل مهندسو Netflix بجد للحفاظ على أنظمتنا متاحة، وقد مر وقت طويل قبل أن نتعرض لحادث إنتاج يختبر مدى فعالية الحل الذي نقدمه. بعد بضعة أشهر من نشر فصل الأحمال ذي الأولوية، واجهنا انقطاعًا في البنية التحتية في Netflix مما أثر على البث للعديد من مستخدمينا. بمجرد إصلاح الانقطاع، حصلنا على ارتفاع بمقدار 12 ضعفًا في طلبات الجلب المسبق في الثانية من أجهزة Android، ربما بسبب تراكم الطلبات المتراكمة في قائمة الانتظار.
كان من الممكن أن يؤدي ذلك إلى انقطاع الخدمة للمرة الثانية حيث لم يتم تطوير أنظمتنا للتعامل مع هذا الارتفاع الكبير في عدد الزيارات. هل ساعدنا هنا تحديد أولويات فصل الأحمال في PlayAPI؟
نعم! على الرغم من انخفاض مدى توفر طلبات الجلب المسبق إلى 20%، إلا أن مدى توفر الطلبات التي بدأها المستخدم كان > 99.4% بسبب تقسيم الأحمال ذات الأولوية.
في مرحلة ما، كنا نتحكم في أكثر من 50% من جميع الطلبات، لكن توفر الطلبات التي بدأها المستخدم ظل أكثر من 99.4%.
استنادًا إلى نجاح هذا النهج، قمنا بإنشاء مكتبة داخلية لتمكين الخدمات من تنفيذ فصل الأحمال ذات الأولوية استنادًا إلى مقاييس الاستخدام القابلة للتوصيل، مع مستويات أولوية متعددة.
على عكس بوابة واجهة برمجة التطبيقات (API)، التي تحتاج إلى التعامل مع عدد كبير من الطلبات ذات الأولويات المختلفة، تتلقى معظم الخدمات الصغيرة عادةً طلبات ذات أولويات قليلة مميزة فقط. للحفاظ على الاتساق عبر الخدمات المختلفة، قدمنا أربع مجموعات ذات أولوية محددة مسبقًا مستوحاة من مستويات Linux tc-prio:
- شديد الأهمية: التأثير على الوظائف الأساسية – لن يتم التخلص منها أبدًا إذا لم نكن في حالة فشل كامل.
- متدهورة: التأثير على تجربة المستخدم – سيتم التخلص منها تدريجيًا مع زيادة الحمل.
- أفضل مجهود: لا تؤثر على المستخدم – سيتم الرد عليها بأفضل جهد ممكن وقد يتم التخلص منها تدريجيًا في التشغيل العادي.
- حجم كبير: العمل في الخلفية، توقع أن يتم التخلص منها بشكل روتيني.
يمكن للخدمات إما اختيار أولوية العميل الرئيسي أو قم بتعيين الطلبات الواردة إلى إحدى هذه المجموعات ذات الأولوية من خلال فحص سمات الطلب المختلفة، مثل رؤوس HTTP أو نص الطلب، لمزيد من التحكم الدقيق. فيما يلي مثال لكيفية قيام الخدمات بتعيين الطلبات لمجموعات الأولوية:
ResourceLimiterRequestPriorityProvider requestPriorityProvider() {
return contextProvider -> {
if (contextProvider.getRequest().isCritical()) {
return PriorityBucket.CRITICAL;
} else if (contextProvider.getRequest().isHighPriority()) {
return PriorityBucket.DEGRADED;
} else if (contextProvider.getRequest().isMediumPriority()) {
return PriorityBucket.BEST_EFFORT;
} else {
return PriorityBucket.BULK;
}
};
}
فصل الأحمال العامة المستندة إلى وحدة المعالجة المركزية
تعمل معظم الخدمات في Netflix تلقائيًا على استخدام وحدة المعالجة المركزية، لذلك يعد ربط النظام بإطار عمل فصل الأحمال ذي الأولوية مقياسًا طبيعيًا لحمل النظام. بمجرد تعيين الطلب إلى مجموعة ذات أولوية، يمكن للخدمات تحديد وقت التخلص من حركة المرور من مجموعة معينة بناءً على استخدام وحدة المعالجة المركزية. من أجل الحفاظ على إشارة القياس التلقائي التي تتطلب القياس، فإن الفصل ذي الأولوية يبدأ فقط في فصل الحمل بعد للوصول إلى الاستخدام المستهدف لوحدة المعالجة المركزية، ومع زيادة حمل النظام، يتم التخلص من حركة المرور الأكثر أهمية تدريجيًا في محاولة للحفاظ على تجربة المستخدم.
على سبيل المثال، إذا كانت المجموعة تستهدف استخدام وحدة المعالجة المركزية بنسبة 60% للقياس التلقائي، فيمكن تكوينها لبدء التخلص من الطلبات عندما يتجاوز استخدام وحدة المعالجة المركزية هذا الحد. عندما يؤدي ارتفاع حركة المرور إلى تجاوز استخدام وحدة المعالجة المركزية (CPU) للمجموعة بشكل ملحوظ هذا الحد، فإنه سيتم التخلص تدريجياً من حركة المرور ذات الأولوية المنخفضة للحفاظ على الموارد لحركة المرور ذات الأولوية العالية. يتيح هذا الأسلوب أيضًا مزيدًا من الوقت للقياس التلقائي لإضافة مثيلات إضافية إلى المجموعة. بمجرد إضافة المزيد من المثيلات، سينخفض استخدام وحدة المعالجة المركزية، وسيستأنف تقديم حركة المرور ذات الأولوية المنخفضة بشكل طبيعي.
تجارب مع فصل الأحمال على وحدة المعالجة المركزية
لقد أجرينا سلسلة من التجارب لإرسال حجم طلب كبير في خدمة تستهدف عادةً 45% من وحدة المعالجة المركزية (CPU) للقياس التلقائي ولكن تم منعها من التوسيع لغرض مراقبة فصل أحمال وحدة المعالجة المركزية (CPU) في ظل ظروف التحميل القصوى. تم تكوين المثيلات للتخلص من حركة المرور غير الهامة بعد 60% من وحدة المعالجة المركزية وحركة المرور الهامة بعد 80%.
نظرًا لأنه تم طلب RPS بما يتجاوز 6 أضعاف مستوى الصوت التلقائي، فقد تمكنت الخدمة من التخلص من الطلبات غير الحرجة أولاً ثم الطلبات الحرجة. ظل زمن الوصول ضمن الحدود المعقولة طوال الوقت، وظل إنتاجية RPS الناجحة مستقرة.
أنماط مضادة مع سفك الأحمال
نمط مضاد 1 – لا يتساقط
في الرسوم البيانية أعلاه، يقوم المحدد بعمل جيد في الحفاظ على زمن الاستجابة منخفضًا للطلبات الناجحة. إذا لم يكن هناك تساقط هنا، فسنرى زيادة في زمن الاستجابة لجميع الطلبات، بدلاً من الفشل السريع في بعض الطلبات التي يمكن إعادة تجربتها. علاوة على ذلك، يمكن أن يؤدي هذا إلى دوامة الموت حيث تصبح إحدى المثيلات غير سليمة، مما يؤدي إلى زيادة الحمل على المثيلات الأخرى، مما يؤدي إلى أن تصبح جميع المثيلات غير صحية قبل أن يبدأ القياس التلقائي.
النمط المضاد 2 – الفشل الاحتقاني
هناك نمط مضاد آخر يجب الانتباه إليه وهو الفشل الاحتقاني أو التساقط بقوة شديدة. إذا كان فصل الأحمال ناتجًا عن زيادة في حركة المرور، فيجب ألا ينخفض RPS الناجح بعد فصل الأحمال. فيما يلي مثال لما يبدو عليه الفشل الاحتقاني:
يمكننا أن نرى في تجارب مع فصل الأحمال على وحدة المعالجة المركزية القسم أعلاه يوضح أن تطبيقنا لفصل الأحمال يتجنب كلاً من هذه الأنماط المضادة من خلال الحفاظ على زمن الوصول منخفضًا والحفاظ على أكبر قدر ممكن من RPS الناجح أثناء فصل الأحمال كما كان من قبل.
بعض الخدمات ليست مرتبطة بوحدة المعالجة المركزية ولكنها بدلاً من ذلك مرتبطة بإدخال/إخراج من خلال دعم الخدمات أو مخازن البيانات التي يمكنها ممارسة الضغط الخلفي من خلال زمن الوصول المتزايد عندما تكون محملة بشكل زائد سواء في الحوسبة أو في سعة التخزين. بالنسبة لهذه الخدمات، نقوم بإعادة استخدام تقنيات فصل الأحمال ذات الأولوية، ولكننا نقدم إجراءات استخدام جديدة لتغذية منطق الفصل. يدعم تطبيقنا الأولي شكلين من التخفيض القائم على زمن الوصول بالإضافة إلى محددات التزامن التكيفية القياسية (في حد ذاتها مقياس لمتوسط زمن الوصول):
- يمكن للخدمة تحديد الهدف لكل نقطة نهاية والحد الأقصى لزمن الاستجابة، مما يسمح للخدمة بالتخلص عندما تكون الخدمة بطيئة بشكل غير طبيعي بغض النظر عن الواجهة الخلفية.
- تُرجع خدمات تخزين Netflix التي تعمل على بوابة البيانات هدف التخزين المرصود والحد الأقصى لاستخدام SLO لوقت الاستجابة، مما يسمح للخدمات بالتخلص من التحميل الزائد على سعة التخزين المخصصة لها.
توفر مقاييس الاستخدام هذه إشارات إنذار مبكر بأن الخدمة تولد الكثير من الحمل على الواجهة الخلفية، وتسمح لها بالتخلص من العمل ذي الأولوية المنخفضة قبل أن تطغى على تلك الواجهة الخلفية. الميزة الرئيسية لهذه التقنيات مقارنة بحدود التزامن وحدها هي أنها تتطلب ضبطًا أقل نظرًا لأن خدماتنا يجب أن تحافظ بالفعل على أهداف مستوى الخدمة (SLOs) لزمن الوصول المحكم، على سبيل المثال p50 < 10 مللي ثانية وp100 < 500 مللي ثانية. لذا، فإن إعادة صياغة أهداف مستوى الخدمة الحالية كاستخدامات تسمح لنا بالتخلص من العمل ذو الأولوية المنخفضة مبكرًا لمنع المزيد من تأثير زمن الاستجابة على العمل ذو الأولوية العالية. وفي الوقت نفسه النظام سيقبل أكبر قدر ممكن من العمل مع الحفاظ على SLO.
لإنشاء مقاييس الاستخدام هذه، نحسب عدد الطلبات التي تتم معالجتها أبطأ من هدفنا والحد الأقصى لأهداف زمن الاستجابة، وتصدر النسبة المئوية للطلبات التي فشلت في تحقيق أهداف زمن الاستجابة تلك. على سبيل المثال، توفر خدمة تخزين KeyValue هدفًا يبلغ 10 مللي ثانية مع زمن استجابة أقصى يبلغ 500 مللي ثانية لكل مساحة اسم، ويتلقى جميع العملاء مقاييس الاستخدام لكل مساحة اسم بيانات لتغذية عملية فصل الأحمال ذات الأولوية الخاصة بهم. تبدو هذه التدابير كما يلي:
utilization(namespace) = {
overall = 12
latency = {
slo_target = 12,
slo_max = 0
}
system = {
storage = 17,
compute = 10,
}
}
في هذه الحالة، تكون 12% من الطلبات أبطأ من هدف 10 مللي ثانية، و0% أبطأ من الحد الأقصى لزمن الاستجابة (المهلة) وهو 500 مللي ثانية، ويتم استخدام 17% من مساحة التخزين المخصصة. تشير حالات الاستخدام المختلفة إلى استخدامات مختلفة في فصل أولوياتها، على سبيل المثال، قد يتم التخلص من الدُفعات التي تكتب البيانات يوميًا عندما يقترب استخدام تخزين النظام من السعة لأن كتابة المزيد من البيانات قد يؤدي إلى مزيد من عدم الاستقرار.
أحد الأمثلة التي يكون فيها استخدام زمن الاستجابة مفيدًا هو إحدى خدمات أصل الملفات الهامة لدينا والتي تقبل كتابة الملفات الجديدة في سحابة AWS وتعمل كأصل (تخدم القراءات) لتلك الملفات إلى البنية التحتية لـ Open Connect CDN الخاصة بنا. تعد عمليات الكتابة هي الأكثر أهمية ولا يجب أن تتخلى عنها الخدمة أبدًا، ولكن عندما يصبح مخزن بيانات الدعم محملاً بشكل زائد، فمن المعقول التخلص تدريجيًا من القراءات إلى الملفات الأقل أهمية لـ CDN حيث يمكنها إعادة محاولة تلك القراءات ولا تؤثر تجربة المنتج.
ولتحقيق هذا الهدف، قامت الخدمة الأصلية بتكوين محدد يستند إلى زمن استجابة KeyValue والذي يبدأ في التخلص من القراءات للملفات الأقل أهمية لشبكة CDN عندما يبلغ مخزن البيانات عن استخدام زمن استجابة مستهدف يتجاوز 40%. قمنا بعد ذلك باختبار النظام من خلال توليد ما يزيد عن 50 جيجابت في الثانية من حركة مرور القراءة، بعضها إلى ملفات ذات أولوية عالية وبعضها إلى ملفات ذات أولوية منخفضة:
اكتشاف المزيد من هيدب فيديو
اشترك للحصول على أحدث التدوينات المرسلة إلى بريدك الإلكتروني.