مرحبا يا هبر! أقدم إليكم ترجمة المقال
"نموذج ترابط Envoy" للمات كلاين.
بدت هذه المقالة مثيرة للاهتمام بدرجة كافية بالنسبة لي ، وبما أن المبعوث يستخدم غالبًا كجزء من "istio" أو ببساطة "kubernetes" للتحكم في الدخول ، وبالتالي فإن معظم الأشخاص ليس لديهم نفس التفاعل المباشر معها كما هو الحال على سبيل المثال مع تثبيتات Nginx أو Haproxy النموذجية. ومع ذلك ، إذا حدث شيء ما ، فسيكون من الجيد فهم كيفية عمله من الداخل. حاولت ترجمة أكبر قدر ممكن من النص إلى اللغة الروسية ، بما في ذلك الكلمات الخاصة ، لأولئك الذين يشعرون بالألم للنظر في هذا ، تركت النسخ الأصلية بين قوسين. مرحبا بكم في القط.
الوثائق الفنية ذات المستوى المنخفض في قاعدة كود Envoy نادرة جدًا في الوقت الحالي. لإصلاح ذلك ، أخطط لإنشاء سلسلة من مقالات المدونة حول النظم الفرعية المختلفة لـ Envoy. نظرًا لأن هذه هي المقالة الأولى ، فالرجاء إخبارنا برأيك وما قد تكون مهتمًا بالمقالات التالية.
أحد أكثر الأسئلة الفنية شيوعًا التي أحصل عليها حول Envoy هو طلب للحصول على وصف منخفض المستوى لنموذج الترابط المستخدم. في هذا المنشور ، سوف أصف كيف يقوم Envoy بتخطيط اتصالات الخيوط ، بالإضافة إلى وصف لنظام مؤشر ترابط التخزين المحلي ، والذي يتم استخدامه داخليًا لجعل الكود أكثر توازناً وعالية الأداء.
خيوط نظرة عامة
يستخدم المبعوث ثلاثة أنواع مختلفة من التدفقات:- الرئيسية: يتحكم مؤشر الترابط هذا في بداية ونهاية العملية ، وكل معالجة واجهة برمجة تطبيقات XDS (xDiscovery Service) ، بما في ذلك DNS ، والتحقق من الصحة ، وإدارة المجموعات والخدمات العامة (وقت التشغيل) ، وإعادة تعيين الإحصائيات ، والإدارة والإدارة العامة العمليات - إشارات Linux ، إعادة التشغيل السريع ، إلخ. كل ما يحدث في هذا الموضوع غير متزامن وغير محظور. بشكل عام ، ينسق مؤشر الترابط الرئيسي جميع العمليات الحيوية للوظائف ، والتي لا تتطلب عددًا كبيرًا من وحدات المعالجة المركزية (CPU) لإكمالها. يسمح هذا لمعظم كود التحكم أن يكون مكتوبًا كما لو كان مترابطًا.
- العامل: بشكل افتراضي ، يقوم Envoy بإنشاء مؤشر ترابط عامل لكل مؤشر ترابط الأجهزة في النظام ، ويمكن التحكم في ذلك باستخدام -
--concurrency
الخيار. يبدأ كل مؤشر ترابط عامل حلقة حدث "غير محظور" ، وهو المسؤول عن الاستماع إلى كل مستمع ، في وقت كتابة هذا التقرير (29 يوليو 2017) لا يوجد مشاركة المستمع ، وتلقي رسائل جديدة اتصالات ، إنشاء مثيل مكدس عامل التصفية للاتصال ومعالجة كافة عمليات الإدخال / الإخراج عبر عمر الاتصال. مرة أخرى ، يتيح هذا لمعظم كود معالجة الاتصال أن يكتب كما لو كان مترابطًا. - فلوشير الملف: كل ملف يكتبه Envoy ، بشكل أساسي سجلات الوصول ، يحتوي حاليًا على دفق حظر مستقل. هذا يرجع إلى حقيقة أن الكتابة إلى الملفات المخزنة مؤقتًا بواسطة نظام الملفات ، حتى عند استخدام
O_NONBLOCK
، يمكن أحيانًا حظرها ( O_NONBLOCK
). عندما تحتاج مؤشرات ترابط العامل إلى الكتابة إلى ملف ، يتم نقل البيانات فعليًا إلى مخزن مؤقت في الذاكرة ، حيث يتم في نهاية المطاف مسحها عبر تدفق تدفق الملفات . هذا مجال واحد من التعليمات البرمجية حيث تقنياً كافة مؤشرات ترابط العامل يمكن حظر نفس القفل أثناء محاولة ملء المخزن المؤقت للذاكرة.
التعامل مع اتصال
كما تمت مناقشته بإيجاز أعلاه ، فإن جميع مؤشرات ترابط العاملين تستمع لجميع المستمعين دون أي تجزئة. وبالتالي ، يتم استخدام kernel بشكل صحيح لإرسال مآخذ مستلمة إلى مؤشرات ترابط العامل. عادة ما تكون النوى الحديثة جيدة جدًا في هذا ، فهي تستخدم ميزات مثل زيادة أولوية المدخلات والمخرجات (IO) لمحاولة ملء الخيط بالعمل ، قبل البدء في استخدام الخيوط الأخرى التي تستمع أيضًا إلى نفس المقبس ، ولا تستخدم القفل الدائري أيضًا (Spinlock) للتعامل مع كل طلب.
بمجرد قبول الاتصال في سلسلة رسائل عامل ، فإنه لا يترك هذا الموضوع. تتم معالجة كل المعالجة الإضافية للاتصال بالكامل في مؤشر ترابط العامل ، بما في ذلك أي سلوك إعادة توجيه.
هذا له عدة عواقب مهمة:- جميع تجمعات الاتصال في Envoy في سير العمل. وبالتالي ، على الرغم من أن تجمعات اتصال HTTP / 2 تقوم بإجراء اتصال واحد فقط لكل مضيف upstream في وقت واحد ، إذا كان هناك أربعة مؤشرات ترابط عامل ، سيكون هناك أربعة اتصالات HTTP / 2 إلى المضيف upstream في حالة ثابتة.
- السبب الذي يجعل Envoy يعمل بهذه الطريقة هو أنه من خلال تخزين كل شيء في سير عمل واحد ، يمكن كتابة كل الشفرة تقريبًا دون حظر كما لو كانت مفردة الترابط. هذا التصميم يجعل كتابة الكثير من التعليمات البرمجية أسهل وميزانًا جيدًا بشكل لا يصدق لعدد غير محدود تقريبًا من مهام سير العمل.
- ومع ذلك ، فإن أحد الاستنتاجات الرئيسية هو أنه من وجهة نظر تجمع الذاكرة وكفاءة الاتصال ، من المهم للغاية في الواقع تكوين المعلمة -
--concurrency
. وجود مؤشرات ترابط عامل أكثر من اللازم سيؤدي إلى فقدان الذاكرة ، وخلق المزيد من الاتصالات غير النشطة وإبطاء سرعة الوصول إلى تجمع الاتصال. في Lyft ، تعمل حاويات المبعوثات الجانبية لدينا مع التزامن المنخفض للغاية ، وبالتالي فإن الأداء مكافئ تقريبًا للخدمات التي يجلسون بجانبها. نحن ندير Envoy كبديل (حافة) الوكيل فقط مع أقصى التزامن.
ماذا يعني عدم الحجب؟
تم استخدام المصطلح "non-blocking" حتى الآن عدة مرات في مناقشة كيفية عمل مؤشرات الترابط الرئيسية والعامل. تتم كتابة جميع التعليمات البرمجية بشرط ألا يتم حظر أي شيء على الإطلاق. ومع ذلك ، هذا ليس صحيحًا تمامًا (وهو ليس صحيحًا تمامًا؟).
يستخدم المبعوث عدة أقفال عملية طويلة:- كما ذكرنا سابقًا ، عند كتابة سجلات الوصول ، تحصل جميع مؤشرات ترابط العامل على نفس القفل قبل ملء مخزن السجل المؤقت في الذاكرة. يجب أن يكون وقت قفل القفل منخفضًا للغاية ، لكن من الممكن أن يتم تحدي هذا القفل من خلال التزامن العالي والإنتاجية العالية.
- يستخدم Envoy نظامًا متطورًا للغاية لمعالجة الإحصائيات المحلية للتيار. سيكون هذا موضوع منشور منفصل. ومع ذلك ، سأذكر بإيجاز أنه كجزء من المعالجة المحلية لإحصائيات التدفق ، فإنه يلزم في بعض الأحيان الحصول على قفل لـ "مخزن الإحصائيات" المركزي. هذا القفل لا ينبغي أبدا أن يكون مطلوبا.
- يحتاج الخيط الرئيسي دوريًا إلى التنسيق مع جميع مهام سير العمل. يتم ذلك عن طريق "النشر" من مؤشر الترابط الرئيسي إلى مؤشرات ترابط العامل ، وأحيانًا من مؤشرات ترابط العامل العودة إلى مؤشر الترابط الرئيسي. للإرسال ، يلزم الحظر حتى يمكن وضع الرسائل المنشورة في قائمة الانتظار للتسليم اللاحق. يجب ألا تتعرض هذه الأقفال لمنافسة جدية ، ولكن لا يزال من الممكن حظرها تقنيًا.
- عندما يكتب Envoy سجلًا إلى دفق خطأ النظام (خطأ قياسي) ، يتلقى قفلًا للعملية بأكملها. بشكل عام ، يعتبر تسجيل المبعوث المحلي أمرًا فظيعًا من حيث الأداء ، لذلك لا يوجد اهتمام كبير بتحسينه.
- هناك العديد من الأقفال العشوائية الأخرى ، لكن أياً منها ليس له أهمية في الأداء ويجب عدم التنازع عليه أبدًا.
خيط التخزين المحلي
نظرًا للطريقة التي يفصل بها Envoy مسؤوليات الخيط الرئيسي عن واجبات سير العمل ، هناك مطلب أنه يمكن إجراء معالجة معقدة على الخيط الرئيسي ثم توفيرها لكل سير عمل بدرجة عالية من التزامن. يصف هذا القسم نظام Envoy Thread Local Storage (TLS) بمستوى عالٍ. في القسم التالي ، سوف أصف كيف يتم استخدامه لإدارة الكتلة.

كما هو موضح بالفعل ، يعالج مؤشر الترابط الرئيسي جميع وظائف الإدارة ووظيفة مستوى التحكم في عملية Envoy تقريبًا. تكون وحدة التحكم محمّلة بعض الشيء هنا ، ولكن إذا نظرت إليها داخل عملية Envoy نفسها وقارنتها بإعادة التوجيه التي تؤديها مؤشرات ترابط العامل ، فإن هذا يبدو مناسبًا. كقاعدة عامة ، تؤدي عملية مؤشر الترابط الرئيسي بعض الأعمال ، ثم تحتاج إلى تحديث كل مؤشر ترابط عامل وفقًا لنتائج هذا العمل ،
بينما لا يحتاج مؤشر ترابط العامل إلى تعيين قفل على كل وصول .
يعمل نظام مبعوث TLS (التخزين المحلي للخيوط) على النحو التالي:- يمكن للكود الذي يعمل في السلسلة الرئيسية تخصيص فتحة TLS للعملية بأكملها. على الرغم من أن هذا مستخلص ، إلا أنه في الممارسة العملية مؤشر في ناقل يوفر وصول O (1).
- يمكن للتيار الرئيسي تعيين بيانات عشوائية في الفتحة الخاصة به. عند القيام بذلك ، يتم نشر البيانات في كل سير عمل كحدث حلقة حدث عادي.
- يمكن قراءة مؤشرات ترابط العامل من فتحة TLS الخاصة بهم واسترداد أي بيانات مؤشر ترابط محلي متوفرة هناك.
على الرغم من أن هذا النموذج بسيط للغاية وقوي بشكل لا يصدق ، إلا أنه يشبه إلى حد بعيد مفهوم حظر RCU (قراءة - تحديث - تحديث). في جوهرها ، لا ترى سير العمل أبدًا أي تغييرات في البيانات في فتحات TLS في وقت التشغيل. يحدث التغيير فقط خلال فترة الراحة بين أحداث العمل.
يستخدم المبعوث هذا بطريقتين مختلفتين:- من خلال تخزين البيانات المختلفة على كل سير عمل ، يتم الوصول إلى هذه البيانات دون أي حظر.
- عن طريق تخزين مؤشر عمومي على البيانات العمومية في وضع القراءة فقط على كل مؤشر ترابط عامل. وبالتالي ، يحتوي كل مؤشر ترابط عامل على عداد مرجع بيانات ، والذي لا يمكن تقليله أثناء تنفيذ العمل. فقط عند تهدئة جميع العمال وتحميل بيانات مشتركة جديدة ، سيتم تدمير البيانات القديمة. انها مطابقة ل RCU.
خيوط تحديث الكتلة
في هذا القسم ، سوف أصف كيفية استخدام TLS (التخزين المحلي لمؤشر الترابط) لإدارة الكتلة. تتضمن إدارة الكتلة معالجة xDS و / أو DNS API ، بالإضافة إلى التحقق من الصحة.
تتضمن إدارة تدفق الكتلة المكونات والخطوات التالية:- يعد Cluster Manager مكونًا داخل Envoy يقوم بإدارة كافة واجهات نظام المجموعة المعروفة ، واجهات برمجة التطبيقات (خدمة اكتشاف الكتلة) ، و SDS (خدمة الاكتشاف السري) و EDS (خدمة اكتشاف نقطة النهاية) ، DNS وعمليات الفحص الخارجية النشطة الصحة (فحص الصحة). وهو مسؤول عن إنشاء تمثيل "ثابت في نهاية المطاف" لكل مجموعة من مراحل المنبع تشمل المضيفين المكتشفين ، بالإضافة إلى الحالة الصحية.
- يقوم المدقق الصحي بإجراء فحص صحي نشط ويقدم تقارير حول التغييرات في الحالة الصحية إلى مدير نظام المجموعة.
- يتم إجراء CDS (خدمة اكتشاف الكتلة) / SDS (خدمة الاكتشاف السري) / EDS (خدمة اكتشاف نقطة النهاية) / DNS لتحديد عضوية الكتلة. يتم إرجاع تغيير الحالة إلى إدارة الكتلة.
- يدير كل سير عمل حلقة حدث باستمرار.
- عندما يقرر مدير الكتلة تغيير حالة الكتلة ، فإنه ينشئ لقطة كتلة للقراءة فقط ويرسلها إلى كل مؤشر ترابط عامل.
- أثناء فترة السكون التالية ، سيقوم سير العمل بتحديث اللقطة في فتحة TLS المخصصة.
- أثناء حدث I / O الذي يجب على المضيف تحديده لموازنة التحميل ، سيطلب موازن التحميل فتحة TLS (التخزين المحلي لمؤشر الترابط) للحصول على معلومات المضيف. لا توجد أقفال مطلوبة لهذا الغرض. لاحظ أيضًا أن TLS يمكنها أيضًا تشغيل الأحداث أثناء الترقية ، بحيث يمكن لموازنات التحميل والمكونات الأخرى إعادة تخزين ذاكرة التخزين المؤقت وهياكل البيانات ، إلخ. هذا خارج نطاق هذا المنشور ، لكنه يستخدم في أماكن مختلفة في الكود.
باستخدام الإجراء أعلاه ، يمكن لـ Envoy معالجة كل طلب دون أي أقفال (بخلاف تلك الموضحة سابقًا). إلى جانب تعقيد كود TLS نفسه ، فإن معظم الكود لا يحتاج إلى فهم كيفية عمل تعدد مؤشرات الترابط ، ويمكن كتابته في وضع مترابط واحد. هذا يجعل من السهل كتابة معظم الكود بالإضافة إلى الأداء المتفوق.
النظم الفرعية الأخرى التي تستخدم TLS
يتم استخدام TLS (التخزين المحلي لمؤشر الترابط) و RCU (قراءة نسخة التحديث) على نطاق واسع في Envoy.
أمثلة على الاستخدام:- آلية تغيير الوظيفة أثناء التنفيذ: يتم حساب القائمة الحالية للوظائف الممكّنة في سلسلة الرسائل الرئيسية. ثم يتم توفير كل سير عمل مع لقطة للقراءة فقط باستخدام دلالات RCU.
- استبدال جداول المسار : بالنسبة لجداول المسار التي توفرها RDS (خدمة اكتشاف الطريق) ، يتم إنشاء جداول المسار في سلسلة الرسائل الرئيسية. سيتم توفير لقطة للقراءة فقط لاحقًا لكل سير عمل باستخدام دلالات RCU (قراءة نسخة محدثة). هذا يجعل تعديل جداول التوجيه ذريًا فعالاً.
- التخزين المؤقت لرأس HTTP : كما اتضح ، فإن حساب رأس HTTP لكل طلب (عند تنفيذ ~ 25K + RPS لكل جوهر) يعد مكلفًا للغاية. يقوم المبعوث بحساب الرأس بشكل مركزي كل نصف ثانية تقريبًا ويوفره لكل موظف من خلال TLS و RCU.
هناك حالات أخرى ، ولكن يجب أن توفر الأمثلة السابقة فهماً جيدًا لما يتم استخدامه لـ TLS.
مطبات الأداء المعروفة
على الرغم من أن برنامج Envoy يعمل بشكل جيد بشكل عام ، إلا أن هناك بعض المناطق المعروفة التي تحتاج إلى اهتمام عند استخدامها مع التزامن وعرض النطاق الترددي العالي للغاية:
- كما هو موضح بالفعل في هذه المقالة ، يتم حاليًا تأمين كل مؤشرات ترابط العامل عند الكتابة إلى المخزن المؤقت لذاكرة سجل الوصول. مع التزامن العالي والإنتاجية العالية ، سيكون من الضروري تجميع سجلات الوصول لكل سير عمل بسبب التسليم غير المنظم عند الكتابة إلى الملف النهائي. بدلاً من ذلك ، يمكنك إنشاء سجل وصول منفصل لكل سير عمل.
- على الرغم من أن الإحصائيات مُحسَّنة للغاية ، مع التزامن والإنتاجية العالية للغاية ، فمن المحتمل أن تكون هناك منافسة ذرية على الإحصائيات الفردية. الحل لهذه المشكلة هو عدادات لكل سير عمل مع إعادة التعيين الدوري للعدادات المركزية. سيتم مناقشة هذا في منشور لاحق.
- لن تعمل البنية الحالية بشكل جيد إذا تم نشر Envoy في سيناريو يوجد فيه عدد قليل جدًا من الاتصالات التي تتطلب موارد معالجة كبيرة. ليس هناك ما يضمن توزيع الاتصالات بالتساوي بين سير العمل. يمكن حل ذلك عن طريق الموازنة بين اتصالات العمل ، والتي ستتحقق فيها القدرة على تبادل الاتصالات بين تدفقات العمل.
الاستنتاج (استنتاج)
تم تصميم نموذج ترابط Envoy لتوفير سهولة البرمجة والتزامن الهائل نظرًا لاحتمال الاستخدام المهدر للذاكرة والاتصالات إذا لم يتم تكوينها بشكل صحيح. هذا النموذج يسمح له بالعمل بشكل جيد للغاية مع عدد كبير جدا من المواضيع والإنتاجية.
كما ذكرت باختصار على Twitter ، يمكن أن يعمل التصميم أيضًا على حزمة مكدس شبكة تعمل بكامل طاقتها في وضع المستخدم ، مثل DPDK (مجموعة تطوير طائرة البيانات) ، والتي يمكن أن تسبب خوادم منتظمة لمعالجة ملايين الطلبات في الثانية مع معالجة L7 كاملة. سيكون من المثير للاهتمام رؤية ما سيتم بناؤه في السنوات القليلة المقبلة.
تعليق سريع أخير: لقد سئلت عدة مرات عن سبب اختيارنا C ++ لـ Envoy. السبب ، كما كان من قبل ، هو أنها لا تزال اللغة الوحيدة المنطوقة على المستوى الصناعي والتي تبني عليها البنية الموصوفة في هذا المنشور. C ++ هو بالتأكيد غير مناسب للجميع أو حتى للعديد من المشاريع ، ولكن بالنسبة لحالات استخدام معينة ، لا تزال الأداة الوحيدة لإنجاز المهمة (لإنجاز المهمة).
روابط إلى الكود
الروابط إلى الملفات ذات الواجهات وتطبيقات الرأس التي تمت مناقشتها في هذا المنشور: