بناء العمارة الموجهة نحو الخدمة على القضبان + كافكا

مرحبا يا هبر! أقدم إليكم المنشور ، وهو عبارة عن تعديل نص لأداء ستيلا كوتون في RailsConf 2018 وترجمة لمقال "بناء بنية موجهة نحو الخدمة مع القضبان والكافكا" من تصميم ستيلا كوتون.

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

ما هو كافكا؟


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

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



تتمثل الميزة الرئيسية لـ Kafka في السرعة العالية لمعالجة الأحداث. تمتلك أنظمة الانتظار التقليدية ، مثل AMQP ، بنية تحتية تراقب الأحداث التي تتم معالجتها لكل مستهلك. عندما ينمو عدد المستهلكين إلى مستوى لائق ، بالكاد يبدأ النظام في مواجهة هذا العبء ، لأنه يتعين عليه مراقبة عدد متزايد من الشروط. أيضا ، هناك مشاكل كبيرة مع الاتساق بين المستهلك ومعالجة الأحداث. على سبيل المثال ، هل يستحق وضع علامة على الرسالة فور إرسالها فور معالجتها بواسطة النظام؟ وإذا وقع المستهلك على الطرف الآخر دون تلقي رسالة؟

كافكا لديها أيضا بنية آمنة من الفشل. يعمل النظام كمجموعة على واحد أو أكثر من الخوادم ، والتي يمكن تحجيمها أفقياً عن طريق إضافة أجهزة جديدة. تتم كتابة جميع البيانات على القرص ونسخها إلى العديد من الوسطاء. لفهم إمكانيات قابلية التوسع ، يجدر إلقاء نظرة على شركات مثل Netflix و LinkedIn و Microsoft. كلهم يرسلون تريليونات من الرسائل يوميًا عبر مجموعات كافكا!

إعداد كافكا في القضبان


يوفر Heroku إضافة كتلة Kafka الإضافية التي يمكن استخدامها في أي بيئة. بالنسبة إلى تطبيقات ruby ​​، ​​نوصي باستخدام جوهرة ruby-kafka . يبدو التطبيق الأدنى كالتالي:

# config/initializers/kafka_producer.rb require "kafka" # Configure the Kafka client with the broker hosts and the Rails # logger. $kafka = Kafka.new(["kafka1:9092", "kafka2:9092"], logger: Rails.logger) # Set up an asynchronous producer that delivers its buffered messages # every ten seconds: $kafka_producer = $kafka.async_producer( delivery_interval: 10, ) # Make sure to shut down the producer when exiting. at_exit { $kafka_producer.shutdown } 

بعد تكوين التكوين ، يمكنك استخدام الأحجار الكريمة لإرسال الرسائل. بفضل الإرسال غير المتزامن للأحداث ، يمكننا إرسال رسائل من أي مكان:

 class OrdersController < ApplicationController def create @comment = Order.create!(params) $kafka_producer.produce(order.to_json, topic: "user_event", partition_key: user.id) end end 

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

كافكا لخدماتك


بعض الميزات التي تجعل من Kafka أداة مفيدة تجعله أيضًا فشل RPC بين الخدمات. ألق نظرة على مثال لتطبيق التجارة الإلكترونية:

 def create_order create_order_record charge_credit_card # call to Payments Service send_confirmation_email # call to Email Service end 

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



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

على سبيل المثال:



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

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



دمج الأحداث في الهندسة الموجهة للخدمة


يناقش منشور بعنوان " ماذا تقصد بـ" مدفوعة بالأحداث "بقلم مارتن فاولر التشويش حول التطبيقات المدفوعة بالحدث. عندما يناقش المطورون مثل هذه الأنظمة ، فإنهم يتحدثون بالفعل عن عدد كبير من التطبيقات المختلفة. من أجل إعطاء فهم عام لطبيعة هذه الأنظمة ، حدد فاولر العديد من الأنماط المعمارية.

دعونا نلقي نظرة على ما هي هذه الأنماط. إذا كنت تريد معرفة المزيد ، أنصحك بقراءة تقريره في GOTO Chicago 2017.

إشعار الحدث


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

 { "event": "order_created", "published_at": "2016-03-15T16:35:04Z" } 

إذا احتاج المستهلكون إلى مزيد من المعلومات حول الحدث ، فإنهم يقدمون طلبًا للحصول على مزيد من البيانات والحصول عليها.

نقل الحالة المحمولة


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

 { "event": "order_created", "order": { "order_id": 98765, "size": "medium", "color": "blue" }, "published_at": "2016-03-15T16:35:04Z" } 

الحدث المصدر


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

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

استعلامات مسؤولية القيادة


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



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

المشاكل


دعنا نتحدث عن بعض المشاكل التي قد تواجهها عند دمج تطبيق كافكا في تطبيقك الموجه نحو الخدمة.

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

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

من المهم أيضًا وجود مقاييس وتنبيهات لمراقبة سرعة معالجة الأحداث. يمكن لـ ruby-kafka العمل مع تنبيهات ActiveSupport ، كما أنه يحتوي على وحدات StatsD و Datadog ، والتي يتم تمكينها افتراضيًا. بالإضافة إلى ذلك ، يوفر جوهرة قائمة المقاييس الموصى بها للمراقبة.

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

تنسيقات البيانات


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

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

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

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

avro-builder عبارة عن جوهرة تم إنشاؤها بواسطة Salsify والتي توفر DSL شبيه بالياقوت لإنشاء مخططات. يمكنك قراءة المزيد عن Avro في هذه المقالة .

معلومات اضافية


إذا كنت مهتمًا بكيفية استضافة Kafka أو كيفية استخدامه في Heroku ، فهناك العديد من التقارير التي قد تهمك.

جيف تشاو في DataEngConf SF '17 " ما يزيد عن 50000 قسم: كيف تعمل هيروكو وتدفع حدود كافكا على نطاق واسع "

بافل برافوسود في دريم فورس 16 بعنوان " دودج فودينغ كافكا: كيف صممنا مؤتمر هيروكو لحدث الأحداث في الوقت الحقيقي "

لديك منظر جميل!

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


All Articles