موثوقية كافكا وسيناريوهات الكوارث
موثوقية كافكا وسيناريوهات الكوارث
نموذج موثوقية كافكا بسيط في ظاهره: نسخ البيانات عبر وسطاء متعددين، وانتخاب قائد لكل قسم، والإقرار بالكتابات لعدد كافٍ من النسخ. لكن الدقة الحقيقية — ومصدر كل الانقطاعات في بيئات الإنتاج — تكمن في الفجوات بين هذه الخطوات. يتناول هذا الدرس السيناريوهات الثلاثة الأكثر تسبباً في فقدان البيانات وانعدام التوافر على نطاق الإنتاج الفعلي: انتخابات القادة غير النظيفة، والمسارات المتعددة لفقدان البيانات المُقرّة، وتعقيدات نسخ البيانات عبر مراكز البيانات.
انتخابات القائد غير النظيفة: المقايضة بين الأمان والتوافر
لكل قسم في كافكا قائد واحد بالضبط في أي لحظة. عند فشل هذا القائد، يجب على وحدة التحكم انتخاب قائد جديد. المسار الآمن: الانتخاب فقط من مجموعة النسخ المتزامنة (ISR) — وهي المجموعة الفرعية من النسخ التي لحقت بالقائد بالكامل. تضمن هذه النسخ احتواءها على جميع الرسائل التي أقرها القائد السابق، فلا يوجد فجوة في البيانات عند انتخاب قائد جديد منها.
المسار الخطير هو الانتخاب غير النظيف: انتخاب نسخة ليست في مجموعة ISR لأنه لا توجد نسخة متزامنة متاحة. يحدث هذا عندما يفشل القائد بينما تكون نسخه التابعة متأخرة — سيناريو يحدث بشكل أكثر مما تتوقع، خاصةً أثناء إعادة التشغيل المتدرجة أو أعطال الشبكة التي تتجاوز مدة replica.lag.time.max.ms (الافتراضي: 30 ثانية).
unclean.leader.election.enable=true هو الافتراضي في بعض توزيعات كافكا السابقة للإصدار 3.x. عند تفعيله، يمكن لوسيط متأخر كثيراً أن يفوز بانتخاب القيادة، ليصبح مرجعاً نهائياً مع التخلص الدائم من كل رسالة أقرها القائد السابق لكن هذه النسخة لم تستلمها قط. المنتجون لا يتلقون أي خطأ. المستهلكون يتجاوزون الرسائل في صمت. هذا فقدان دائم وصامت للبيانات.اضبط unclean.leader.election.enable=false على مستوى الكلستر بالكامل لأي حمل عمل لا يُقبل فيه فقدان البيانات. المقايضة: إذا تقلصت مجموعة ISR إلى صفر (فشلت جميع النسخ المتزامنة في وقت واحد)، يصبح القسم غير متاح حتى يتعافى أحد أعضاء ISR. هذا هو السلوك الصحيح — عدم التوافر قابل للتعافي؛ أما فقدان البيانات فلا. احتفظ بالقيمة true فقط لمواضيع التسجيل ذات الإنتاجية العالية حيث تقبل صراحةً بالخسارة مقابل التوافر المستمر.
سيناريوهات فقدان البيانات: التصنيف الكامل
الانتخابات غير النظيفة ليست سوى مسار واحد لفقدان البيانات. يحتفظ المشغلون المتمرسون بخريطة ذهنية لجميع المسارات، لأن كلاً منها يستلزم تخفيفاً مختلفاً:
- acks=0 أو acks=1: مع
acks=0، يُرسل المنتج الرسالة وينسى — أي فشل للوسيط قبل الكتابة على القرص يؤدي إلى فقدان الرسالة. معacks=1، يُقرّ القائد بعد الكتابة في سجله الخاص لكن قبل نسخ أي تابع؛ إذا انهار القائد في تلك الفترة، تُفقد الرسالة رغم تلقي المنتج استجابة نجاح. استخدمacks=all(مكافئ لـacks=-1) لأي موضوع مهم. - تقلص ISR دون min.insync.replicas: مع
acks=allوmin.insync.replicas=2، تستلزم الكتابة إقراراً من نسختين على الأقل. إذا كانت نسخة واحدة فقط في ISR (بسبب فشل وسيط أو تأخر)، يتلقى المنتج استثناءNotEnoughReplicasException. هذا هو السلوك الصحيح — يرفض الكلستر الكتابة بدلاً من قبولها بشكل غير آمن. راقب حجم ISR عبر مقياس JMX:kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions. - اقتطاع السجل عند ترقية التابع: عند انتخاب تابع قائداً، يقتطع سجله إلى آخر إزاحة ملتزمة — علامة الحد الأعلى للمياه. تُهمل أي رسائل كتبها القائد القديم بعد هذه العلامة. مع
acks=allلا يحدث هذا بحكم التعريف، لكن معacks=1هو سيناريو خسارة حقيقي. - إيداع إزاحات المستهلك قبل اكتمال المعالجة: يمكن للمستهلك إيداع إزاحة قبل معالجة الرسالة المقابلة بالكامل أو تخزينها بشكل دائم. إذا انهارت العملية بعد الإيداع لكن قبل اكتمال الأثر الجانبي، تُفقد الرسالة فعلياً من منظور المستهلك. أودع الإزاحات فقط بعد أن يصبح أثرك الجانبي دائماً.
- انتهاء صلاحية علامات الحذف في المواضيع المضغوطة: تحذف المواضيع المضغوطة سجلات الحذف بعد
delete.retention.ms(الافتراضي: 24 ساعة). المستهلك الذي كان غير متصل لمدة أطول من هذا الحد يفوته الحذف ويحتفظ بحالة قديمة إلى أجل غير مسمى.
acks=all مع min.insync.replicas=N-1 (حيث N هو عامل النسخ) مع unclean.leader.election.enable=false تمنحك أقوى ضمان للمتانة يمكن لكافكا تقديمه. هذا هو الخط الأساسي لأي موضوع مالي أو تعاقدي حساس على نطاق كبير. شركات مثل Stripe وLinkedIn وكلسترات كافكا الداخلية لـ Confluent تعمل جميعها بهذه التهيئة.نسخ الكلستر المتعدد: MirrorMaker 2 في بيئة الإنتاج
كلستر كافكا المنفرد، مهما كان مضبوطاً جيداً، هو نطاق فشل واحد. تستلزم أعطال الشبكة وأعطال مناطق التوافر والأحداث على مستوى مركز البيانات توبولوجيا متعددة الكلسترات. الحل الأصلي لكافكا هو MirrorMaker 2 (MM2)، المُقدَّم في KIP-382 والمبني على إطار عمل Kafka Connect. يحل MM2 محل MirrorMaker الأصلي — الذي كانت لديه ثغرات خطيرة في ترسيم الإزاحات ونسخ مجموعات المستهلكين — وهو الأداة المعيارية في بيئة الإنتاج لدى LinkedIn وConfluent وAWS MSK.
يوفر MM2 ثلاث قدرات رئيسية افتقر إليها سلفه:
- ترجمة الإزاحات: تُنسخ إزاحات مجموعات المستهلكين بين الكلسترات مع طبقة ترجمة تأخذ في الحسبان أن نفس الرسالة المنطقية قد تحمل إزاحات مختلفة في الكلسترات المصدر والهدف. هذا ضروري للتعافي من الأعطال — يمكن للمستهلكين الاستئناف من الموضع الصحيح في الكلستر الهدف دون إعادة تشغيل الموضوع بأكمله.
- عزل مساحات أسماء المواضيع: تُضاف بادئة اسم الكلستر المصدر إلى المواضيع (مثل
us-east.paymentsفي كلسترeu-west)، مما يمنع التعارضات ويجعل التوبولوجيا صريحة. - مواضيع النبضات والنقاط التفتيشية: يكتب MM2 سجلات اصطناعية في
mm2-heartbeatsوmm2-checkpoints— تستخدمها أدوات التعافي من الأعطال (مثل API الخاص بـRemoteClusterUtils) لحساب ترجمة إزاحات المستهلك عند الطلب.
النشط/السلبي مقابل النشط/النشط: المقايضة التشغيلية
يدعم MM2 كلا التوبولوجيتين، والاختيار له تداعيات تشغيلية كبيرة:
النشط/السلبي أبسط تشغيلياً. كلستر واحد هو مرجع الحقيقة؛ والآخر نسخة احتياطية دافئة. التعافي من الأعطال إجراء تشغيلي متعمد: إعادة توجيه المنتجين إلى الكلستر الاحتياطي، والتحقق من ترجمة إزاحات المستهلكين، وقطع DNS. الخطر أن الكلستر الاحتياطي لا يُختبر أبداً تحت حمل الإنتاج الفعلي، مما يجعل التعافي أبطأ وأكثر عرضة للأخطاء عند الحاجة الفعلية. استهدف إجراء تمرين تعافٍ من الكوارث بانتظام — بحد أدنى ربع سنوي — للتحقق من صحة دليل التشغيل.
النشط/النشط يوجه مساحات أسماء المواضيع المختلفة إلى كلسترات مختلفة ويسمح لكل كلستر بنسخ مساحات الأسماء الخاصة بالآخر. يمنحك هذا صفر RPO للقراءات والتوزيع التلقائي، لكنه يُدخل أصعب مشكلة في الأنظمة الموزعة: تجنب حلقات الرسائل. يستخدم MM2 بادئات المواضيع وإعداد replication.policy.class لكسر الحلقات، لكن هذا يجب اختباره صراحةً.
kafka.connect:type=MirrorSourceConnector,target=(*),topic=(*),name=replication-latency-ms. أنشئ تنبيهاً عند تجاوز التأخر ميزانية RTO الخاصة بك. على نطاق LinkedIn (تريليونات الرسائل يومياً عبر مراكز البيانات)، هذا المقياس موجود على كل لوحة تحكم SRE. ارتفاع التأخر المستمر هو عادةً أول علامة على انهيار شبكي بطيء أو فشل وسيط في الكلستر الهدف قبل أن يُبلغ الكلستر نفسه عن تدهور.دليل تشغيل التعافي من الكوارث: الخمس عشرة دقيقة الأولى
عند توقف الكلستر الأساسي، تسلسل القرارات لا يقل أهمية عن الميكانيكا التقنية:
- تأكيد النطاق (الدقائق 0-2): هل هو وسيط واحد، أم الكلستر بأكمله، أم مسار الشبكة بين الكلسترات؟ افحص
ActiveControllerCountوOfflinePartitionsCountومقاييس تأخر MM2. فشل وسيط واحد في كلستر مُهيَّأ بشكل صحيح يُصلح نفسه — لا تُطلق التعافي من الكوارث. - إعلان الحادثة وتجميد الكتابات (الدقائق 2-5): إذا تأكد الفشل على مستوى الكلستر، نسّق مع المناوب لتجميد الكتابات على الكلستر الأساسي. يمنع هذا المنتجين من الاستمرار في الكتابة على كلستر مجهول المصير، مما يُعقّد تسوية الإزاحات لاحقاً.
- ترجمة إزاحات المستهلكين (الدقائق 5-10): استخدم
RemoteClusterUtils.translateOffsets()أو سير عملkafka-consumer-groups.sh --reset-offsetsلتعيين نقاط تفتيش مجموعات المستهلكين من الكلستر الأساسي إلى كلستر التعافي. هذه هي الخطوة التي تتدرب عليها معظم الفرق بشكل أقل والتي تُخطئ فيها أكثر تحت الضغط. - إعادة توجيه حركة المرور والتحقق (الدقائق 10-15): حدّث تهيئة خادم الإقلاع في عملاء المنتجين والمستهلكين (عادةً عبر اكتشاف الخدمات أو تهيئة البيئة)، وأعد تشغيل المستهلكين على كلستر التعافي، وتحقق من تقدم مجموعات المستهلكين واستعادة مقاييس الأعمال الرئيسية (مثل معدل معالجة المدفوعات).