البرمجة وتطوير البرمجيات

كيف تبني خط معالجة Kafka يحافظ على ترتيب الجلسات باستخدام Go

يوضح Joshua Oluikpe تصميماً عملياً لمعالجة رسائل Kafka بترتيب صارم داخل كل جلسة، مع إبقاء الجلسات المستقلة قادرة على العمل بالتوازي. يعتمد التصميم على التجزئة المتسقة، وعامل Go لكل جلسة، وإعادة المحاولة داخل المسار نفسه، وإدارة نقاط الالتزام المتجاورة لتفادي فقدان الرسائل بعد التعطل.

07 أكتوبر 2026
4 دقائق قراءة
3 قراءة
certi.news Editorial Team
كيف تبني خط معالجة Kafka يحافظ على ترتيب الجلسات باستخدام Go

لا يكفي الاعتماد على ترتيب Kafka داخل القسم (partition) عندما تتشارك آلاف الجلسات القسم نفسه. ففي أنظمة المحادثة والمهام المتسلسلة، قد تصل رسالة تصحيحية مثل «اجعل الوجهة باريس» بعد رسالة «احجز رحلة إلى لندن»، لكن تنفيذها قبل الرسالة الأولى يفسد السياق. الحل الذي يصفه Joshua Oluikpe في InfoQ ينقل جزءاً من مسؤولية الترتيب إلى طبقة التطبيق المكتوبة بلغة Go.

ترتيب داخل الجلسة وتوازٍ بين الجلسات

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

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

إعادة المحاولة من دون تجاوز الرسائل

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

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

الالتزام الآمن والتعافي بعد التعطل

عندما تعالج جلسات متعددة رسائلها بالتوازي، لا يجوز الالتزام بأعلى offset مكتمل فقط. فإذا اكتمل offset 104 قبل 102 ثم جرى الالتزام بـ104، فقد يؤدي تعطل المستهلك إلى تجاوز 102 نهائياً. لذلك يتتبع النظام، لكل قسم، offsets قيد المعالجة وتلك التي اكتملت، ولا يحرك نقطة الالتزام إلا حتى أعلى offset مكتمل بصورة متجاورة.

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

ما الذي يلزم للإنتاج الفعلي؟

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

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

النتائج والقيود

في اختبار اصطناعي شمل 50,000 رسالة و10 جلسات مع حقن أخطاء مؤقتة في 10% من الرسائل، سجل النظام 14,027 رسالة في الثانية من دون مخالفات ترتيب، مع زمن وسيط 11.7 مللي ثانية. وفي اختبار تحميل على 1,000 جلسة، بلغ معدل الإرسال الفعلي 48,805 رسالة في الثانية من أصل هدف 50,000، من دون أخطاء إرسال، لكن زمن الذيل تجاوز ميزانية 200 مللي ثانية بسبب حصة معدل الرسائل في API Gateway، لا بسبب آلية ترتيب الجلسات.

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

مصدر الخبر
InfoQ - Architecture Articles
فتح المصدر الأصلي ↗
كيف أعددنا هذا الخبر؟

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

c
كاتب المقال

certi.news Editorial Team

certi.news Editorial Team

The certi.news editorial team monitors technical sources and reconstructs news, verifying facts and context prior to publication.

من نفس التصنيف

مقالات قد تهمك

عرض كل الأخبار