اللبنات الأساسية للتطبيقات الموزعة. التقريب الثاني

إعلان


الزملاء ، في منتصف الصيف أخطط لإصدار سلسلة أخرى من المقالات حول تصميم أنظمة قائمة الانتظار: "تجربة VTrade" - محاولة لكتابة إطار للأنظمة التجارية. ستحلل الدورة نظرية وممارسة بناء التبادل ، والمزاد ، والمتجر. في نهاية المقال ، أقترح التصويت على الموضوعات التي تهمك أكثر.



هذه هي المقالة الأخيرة في دورة تطبيق رد الفعل الموزعة على Erlang / Elixir. في المقالة الأولى ، يمكنك العثور على الأسس النظرية للهندسة التفاعلية. يوضح المقال الثاني الأنماط والآليات الأساسية لبناء مثل هذه الأنظمة.


اليوم سنطرح قضايا تطوير قاعدة الكود والمشاريع بشكل عام.


منظمة الخدمة


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


يكون الموقف معقدًا عندما نحتاج إلى تطبيق خدمة موزعة تتحمل الأخطاء. افترض أن متطلبات المستخدمين قد تغيرت:


  1. الآن يجب على الخدمة معالجة الطلبات على 5 عقد من الكتلة ،
  2. تكون قادرة على أداء مهام معالجة الخلفية ،
  3. وتكون قادرة على إدارة قوائم الاشتراك تحديث ملف التعريف الخاص بك بشكل حيوي.

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


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


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


تتطلب النقطة 3 امتدادًا لقالب pub-sub. وللتنفيذ ، بعد إنشاء نقطة تبادل pub-sub ، نحتاج أيضًا إلى تشغيل وحدة التحكم في هذه النقطة كجزء من خدمتنا. وبالتالي ، يبدو أننا نأخذ منطق معالجة الاشتراك وإلغاء الاشتراك من طبقة المراسلة في تطبيق المستخدمين.


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


اختيار القائد


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


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


بعد بدء نقطة التبادل والاتصال بها ، تتلقى جميع الخدمات رسالة النظام #'$leader'{exchange = ?EXCHANGE, pid = LeaderPid, servers = Servers} . إذا تطابق LeaderPid مع pid العملية الحالي ، LeaderPid تعيينه كقائد ، وتتضمن قائمة Servers جميع العقد ومعلماتها.
عند ظهور عقدة نظام مجموعة جديدة وقطع الاتصال بها ، تتلقى جميع وحدات التحكم بالخدمة #'$slave_up'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} و #'$slave_down'{exchange = ?EXCHANGE, pid = SlavePid, options = SlaveOpts} على التوالي.


وبالتالي ، فإن جميع المكونات تدرك جميع التغييرات ، وفي المجموعة في أي وقت معين يتم ضمان قائد واحد.


وسطاء


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


مثال كلاسيكي لتحسين pub-sub هو تطبيق موزع مع جوهر أعمال ينشئ أحداث تحديث ، على سبيل المثال ، تغيير في سعر السوق ، وطبقة وصول - خوادم N توفر واجهات برمجة تطبيقات Websocket لعملاء الويب.
إذا قررت "الجبين" ، فإن خدمة العملاء تكون كما يلي:


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

تخيل أن لدينا 50000 مشترك في موضوع "الأخبار". يتم توزيع المشتركين بالتساوي عبر 5 خوادم. نتيجةً لذلك ، سيتم تكرار كل تحديث ، يصل إلى نقطة التبادل ، 50000 مرة: 10،000 مرة لكل خادم ، وفقًا لعدد المشتركين فيه. ليس تماما خطة فعالة ، أليس كذلك؟
لتحسين الموقف ، نقدم وكيلًا له نفس الاسم مع نقطة التبادل. يجب أن يكون مسجل الاسم العام قادرًا على إرجاع أقرب عملية بالاسم ، وهذا أمر مهم.


قم بتشغيل هذا الخادم الوكيل على خوادم طبقة الوصول ، وسوف تشترك فيه جميع عملياتنا التي تخدم واجهة برمجة تطبيقات websocket ، وليس في نقطة تبادل pub-sub الأصلية في النواة. يشترك الوكيل في النواة فقط في حالة اشتراك فريد ويكرر الرسالة الواردة لجميع المشتركين فيها.
نتيجة لذلك ، سيتم إرسال 5 رسائل بين kernel وخوادم الوصول ، بدلاً من 50000.


التوجيه والموازنة


مسا-التن


في تطبيق المراسلة الحالي ، هناك 7 استراتيجيات لتوزيع الاستعلام:


  • default . يتم تمرير الطلب إلى جميع وحدات التحكم.
  • round-robin . يتكرر خلال ويوزع بشكل دوري الطلبات بين وحدات التحكم.
  • consensus . وتنقسم وحدات التحكم التي تخدم الخدمة إلى قادة وأتباع. يتم تمرير الطلبات فقط إلى الزعيم.
  • consensus & round-robin . هناك قائد في المجموعة ، ولكن يتم توزيع الطلبات على جميع الأعضاء.
  • sticky . يتم حساب دالة التجزئة وتعيينها إلى معالج محدد. الطلبات اللاحقة مع هذا التوقيع تذهب إلى نفس المعالج.
  • sticky-fun . عند تهيئة نقطة التبادل ، يتم نقل وظيفة حساب التجزئة للتوازن sticky .
  • fun إنه مشابه للمتعة اللزجة ، فقط بالإضافة إلى ذلك يمكنك إعادة توجيهه أو رفضه أو تجهيزه مسبقًا.

يتم تعيين استراتيجية التوزيع عند تهيئة نقطة التبادل.


بالإضافة إلى موازنة الرسائل ، يسمح لك بوضع علامة على الكيانات. النظر في أنواع العلامات في النظام:


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

حانة الفرعية


بالنسبة إلى pub-sub ، فإن الأمور أسهل قليلاً. لدينا نقطة تبادل يتم فيها نشر الرسائل. تقوم نقطة التبادل بتوزيع الرسائل بين المشتركين الذين يشتركون في مفاتيح التوجيه التي يحتاجون إليها (يمكننا القول أن هذا يشبه هؤلاء).


قابلية التوسع والمرونة


تعتمد قابلية النظام ككل على درجة قابلية التحجيم للطبقات ومكونات النظام:


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

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


تحفظ


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


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


إنتاجية


دعونا نحاول على الأقل مقارنة أداء rabbitmq ورسائلنا المخصصة.
لقد وجدت نتائج اختبار rabbitmq الرسمية من فريق openstack.


في الفقرة 6.14.1.2.1.2.2. تعرض الوثيقة الأصلية نتيجة RPC CAST:


في السابق ، لن نجعل أي إعدادات إضافية لنظام التشغيل OS kernel أو erlang VM. شروط الاختبار:


  • خيارات erl: + A1 + sbtu.
  • يعمل الاختبار داخل عقدة erlang واحدة على كمبيوتر محمول مع i7 قديم في أداء المحمول.
  • تجري اختبارات المجموعة على الخوادم ذات شبكة 10G.
  • رمز يعمل في حاويات عامل ميناء. الشبكة في وضع NAT.

كود الاختبار:


 req_resp_bench(_) -> W = perftest:comprehensive(10000, fun() -> messaging:request(?EXCHANGE, default, ping, self()), receive #'$msg'{message = pong} -> ok after 5000 -> throw(timeout) end end ), true = lists:any(fun(E) -> E >= 30000 end, W), ok. 

السيناريو 1: يتم تشغيل الاختبار على جهاز كمبيوتر محمول مع تنفيذ المحمول القديم i7. يتم تنفيذ الاختبار والرسائل والخدمات على عقدة واحدة في حاوية عامل واحد:


 Sequential 10000 cycles in ~0 seconds (26987 cycles/s) Sequential 20000 cycles in ~1 seconds (26915 cycles/s) Sequential 100000 cycles in ~4 seconds (26957 cycles/s) Parallel 2 100000 cycles in ~2 seconds (44240 cycles/s) Parallel 4 100000 cycles in ~2 seconds (53459 cycles/s) Parallel 10 100000 cycles in ~2 seconds (52283 cycles/s) Parallel 100 100000 cycles in ~3 seconds (49317 cycles/s) 

السيناريو 2 : 3 العقد التي تعمل على أجهزة مختلفة تحت عامل ميناء (NAT).


 Sequential 10000 cycles in ~1 seconds (8684 cycles/s) Sequential 20000 cycles in ~2 seconds (8424 cycles/s) Sequential 100000 cycles in ~12 seconds (8655 cycles/s) Parallel 2 100000 cycles in ~7 seconds (15160 cycles/s) Parallel 4 100000 cycles in ~5 seconds (19133 cycles/s) Parallel 10 100000 cycles in ~4 seconds (24399 cycles/s) Parallel 100 100000 cycles in ~3 seconds (34517 cycles/s) 

في جميع الحالات ، لم يتجاوز استخدام وحدة المعالجة المركزية 250٪


النتائج


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


الصورة عن طريق chuttersnap

Source: https://habr.com/ru/post/ar446344/


All Articles