كيف أصبح كافكا حقيقة واقعة

كيف أصبح كافكا حقيقة واقعة

يا هبر!

أعمل في فريق Tinkoff ، الذي يعمل على تطوير مركز الإخطار الخاص به. بالنسبة للجزء الأكبر ، أقوم بالتطوير في Java باستخدام Spring boot وحل المشكلات الفنية المختلفة التي تنشأ في المشروع.

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

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

تسليم مضمون وأكثر

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

هذا سيساعد معرف العميل للمنتج والمستهلك. للوهلة الأولى ، يمكنك استخدام اسم التطبيق كقيمة ، وسيعمل هذا في معظم الحالات. على الرغم من أن الموقف عندما يكون هناك العديد من المستهلكين في التطبيق ومنحهم نفس Client.id ، يؤدي إلى التحذير التالي:

org.apache.kafka.common.utils.AppInfoParser — Error registering AppInfo mbean javax.management.InstanceAlreadyExistsException: kafka.consumer:type=app-info,id=kafka.test-0

إذا كنت تريد استخدام JMX في تطبيق مع كافكا ، فقد تكون هذه مشكلة. في هذه الحالة ، من الأفضل استخدام مجموعة من اسم التطبيق ، على سبيل المثال ، اسم الموضوع كقيمة client.id. يمكن رؤية نتيجة التكوين لدينا في إخراج الأمر الكافكة-المستهلك-المجموعات من المرافق من Confluent:

كيف أصبح كافكا حقيقة واقعة

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

  • 0 - الإقرار لن يتم النظر فيه.
  • 1 - المعلمة الافتراضية ، يجب الاعتراف بنسخة متماثلة واحدة فقط.
  • −1 - الإقرار مطلوب من جميع النسخ المتماثلة المتزامنة (إعداد الكتلة الحد الأدنى من النسخ المتزامنة).

من القيم المدرجة ، يمكن ملاحظة أن acks التي تساوي -1 تعطي أقوى ضمان بأن الرسالة لن تضيع.

كما نعلم جميعًا ، لا يمكن الاعتماد على الأنظمة الموزعة. للحماية من الفشل العابر ، يوفر منتج كافكا المعلمة يعيد المحاولة، مما يسمح لك بتعيين عدد محاولات إعادة التقديم داخل Delivery.timeout.ms. نظرًا لأن معلمة إعادة المحاولة لها قيمة افتراضية هي Integer.MAX_VALUE (2147483647) ، يمكن ضبط عدد عمليات إعادة إرسال الرسالة عن طريق تغيير delivery.timeout.ms فقط.

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

تسمح هذه الإعدادات لمُنتِجنا بتسليم الرسائل بضمان عالي. لنتحدث الآن عن كيفية التأكد من كتابة نسخة واحدة فقط من الرسالة لموضوع كافكا؟ في أبسط الحالات ، لهذا ، تحتاج إلى تعيين معلمة Producer تمكين الى الحقيقة. تضمن Idempotency كتابة رسالة واحدة فقط إلى قسم معين لموضوع واحد. القيم هي الشرط المسبق لتمكين العاطفة acks = الكل ، أعد المحاولة> 0 ، max.in.flight.requests.per.connection 5. إذا لم يتم تعيين هذه المعلمات من قبل المطور ، فسيتم تعيين القيم أعلاه تلقائيًا.

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

  • إذا تم تحديد القسم بشكل صريح عند إرسال الرسالة ، فإننا نستخدمه.
  • إذا لم يتم تحديد القسم ، ولكن تم تحديد المفتاح ، فحدد القسم بواسطة التجزئة من المفتاح.
  • إذا لم يتم تحديد القسم والمفتاح ، فحدد الأقسام بدورها (round-robin).

أيضا ، باستخدام مفتاح و idempotent إرسال مع المعلمة max.in.flight.requests.per.connection = 1 يمنحك معالجة الرسائل المطلوبة على المستهلك. بشكل منفصل ، يجدر بنا أن نتذكر أنه إذا تم تكوين التحكم في الوصول على المجموعة الخاصة بك ، فستحتاج إلى حقوق الكتابة غير الفعالة في الموضوع.

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

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

org.apache.kafka.common.errors.ProducerFencedException: Producer attempted an operation with an old epoch. Either there is a newer producer with the same transactionalId, or the producer's transaction has been expired by the broker.

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

تم إعداد المُنتِج ، لكن معاملات كافكا تتحكم فقط في نطاق الرسالة. بغض النظر عن حالة المعاملة ، تدخل الرسالة على الفور في الموضوع ، ولكن لها سمات نظام إضافية.

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

ولكن هناك فارق بسيط آخر. المعاملات التي أعددناها أعلاه هي في الواقع بادئة المعاملة. في مدير المعاملات ، يتم إلحاق رقم تسلسلي به. يتم إصدار المعرف الناتج إلى المعاملات. id.expiration.ms، والذي تم تكوينه في مجموعة كافكا وله قيمة افتراضية 7 أيام. إذا لم يتلق التطبيق أي رسائل خلال هذا الوقت ، فعند محاولة إرسال المعاملة التالية ، ستتلقى InvalidPidMappingException. سيصدر منسق المعاملة بعد ذلك رقم تسلسل جديد للمعاملة التالية. ومع ذلك ، قد تُفقد الرسالة إذا لم تتم معالجة InvalidPidMappingException بشكل صحيح.

بدلا من المجاميع

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

المنتج:

  1. أكس = الكل
  2. يعيد المحاولة> 0
  3. enable.idempotence = صحيح
  4. max.in.flight.quests.per.connection ≤ 5 (1 للإرسال المطلوب)
  5. transaction.id = $ {application-name} - $ {hostname}

مستهلك:

  1. Isolation.level = read_committed

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

وإليك بعض المواد للدراسة الذاتية:

المصدر: www.habr.com

إضافة تعليق