تصميم وتسمية قوائم الانتظار

بعض القواعد حول كيفية تنظيم النقاط وقوائم الانتظار وكيفية تسميتها بشكل صحيح لجعلها مريحة.

| exchange | type | binding_queue | binding_key | |-------------------------------------------------------| | user.write | topic | user.created.app2 | user.created | 

المفاهيم
AMQP (بروتوكول وضع الرسائل في قائمة انتظار متقدمة) هو بروتوكول مفتوح لنقل الرسائل بين مكونات النظام.
المزود (الناشرون / المنتجون) - برنامج يرسل الرسائل.
المشترك (المستهلك) - برنامج يتلقى الرسائل. عادةً ما يكون المشترك في حالة انتظار للرسائل.
قائمة الانتظار - قائمة انتظار الرسائل.
نقطة التبادل (التبادل) - نقطة التبادل الأولية لقائمة الانتظار ، والتي تعمل في التوجيه.

القاعدة 1


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

المادة 2


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

المادة 3


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

أمثلة وحلول


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

 | object | event | |------------------| | user | created | | user | updated | | user | deleted | 

السؤال الأول الذي يتم طرحه عادة هو الأحداث المختلفة لكائن واحد (كائن "المستخدم" في هذا المثال) ، هل يجب أن أستخدم نقطة تبادل واحدة لنشر الأحداث الثلاثة ، أو استخدام 3 نقاط منفصلة لكل حدث؟ أو باختصار ، نقطة تبادل واحدة ، أم الكثير؟

قبل الإجابة على هذا السؤال ، أود أن أطرح سؤالًا آخر: هل نحن بحاجة حقًا إلى نقطة منفصلة لهذه الحالة؟ ماذا لو استخلصنا جميع أنواع الأحداث الثلاثة كحدث "الكتابة" الذي يتم فيه إنشاء "أنواع فرعية" و "تحديث" و "حذف"؟

 | object | event | sub-type | |-----------------------------| | user | write | created | | user | write | updated | | user | write | deleted | 

الحل 1


أبسط الحلول هو إنشاء قائمة انتظار "user.write" ، ونشر جميع الرسائل من أحداث تسجيل المستخدم إلى قائمة الانتظار هذه عبر نقطة التبادل العالمية.

القرار 2


لا يمكن أن يعمل الحل الأبسط عندما يكون هناك تطبيق ثانٍ (له منطق معالجة مختلف) يريد الاشتراك في أي رسائل منشورة في قائمة الانتظار. عندما يتم توقيع العديد من التطبيقات ، فنحن على الأقل بحاجة إلى نقطة واحدة بنوع "fanout" مع روابط لعدة قوائم انتظار. وبالتالي ، يتم إرسال الرسائل إلى النقطة ، ويقوم بتكرار الرسائل في كل قائمة انتظار. يمثل كل قائمة انتظار مهمة معالجة لكل تطبيق.

 | queue | subscriber | |-------------------------------| | user.write.app1 | app1 | | user.write.app2 | app2 | | exchange | type | binding_queue | |---------------------------------------| | user.write | fanout | user.write.app1 | | user.write | fanout | user.write.app2 | 

الحل الثاني يعمل بشكل جيد إذا كان كل مشترك يريد حقًا التعامل مع جميع الأنواع الفرعية لأحداث "user.write". على سبيل المثال ، إذا تم تصميم تطبيق المشترك لتخزين سجل المعاملات ببساطة.

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

القرار 3


لحل المشكلة أعلاه ، يجب علينا استخراج الحدث "user.created" من نوع "user.write". نقطة تبادل مع نوع الموضوع يمكن أن تساعدنا. عند نشر الرسائل ، سنستخدم user.created / user.updated / user.deleted كمفاتيح توجيه في نقطة ما ، حتى نتمكن من وضع مفتاح الاتصال "user. *" في قائمة الانتظار "user.write.app1" ومفتاح الاتصال "user.created" في قائمة الانتظار "user.created.app2".

 | queue | subscriber | |---------------------------------| | user.write.app1 | app1 | | user.created.app2 | app2 | | exchange | type | binding_queue | binding_key | |-------------------------------------------------------| | user.write | topic | user.write.app1 | user.* | | user.write | topic | user.created.app2 | user.created | 

القرار 4


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

 | queue | subscriber | |---------------------------------| | user.write.app1 | app1 | | user.created.app2 | app2 | | exchange | type | binding_queue | binding_key | |--------------------------------------------------------| | user.write | direct | user.write.app1 | user.created | | user.write | direct | user.write.app1 | user.updated | | user.write | direct | user.write.app1 | user.deleted | | user.write | direct | user.created.app2 | user.created | 

نعود إلى السؤال "نقطة واحدة ، أم الكثير؟". طالما أن جميع الحلول تستخدم نقطة واحدة فقط ، فهي تعمل بشكل جيد ، لا شيء سيء. في أي حالات يمكن أن نحتاج إلى عدة نقاط؟

القرار 5


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

 | queue | subscriber | |----------------------------------| | user.write.app1 | app1 | | user.created.app2 | app2 | | user.behavior.app3 | app3 | | exchange | type | binding_queue | binding_key | |--------------------------------------------------------------| | user.write | topic | user.write.app1 | user.* | | user.write | topic | user.created.app2 | user.created | | user.behavior | topic | user.behavior.app3 | user.* | 

ترجمة مجانية للمقال RabbitMQ وتبادل تصميم قائمة الانتظار .

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


All Articles