المشتقة · فصل ١١

الـ Streams: الداتا من غير نهاية

Kafka · CDC · event time · exactly-once
🎯 الهدف: تخلي الكاش والسيرش والداتابيز يتلحقوا ببعض من غير ما تكتب في الاتنين بإيدك.

الأحداث

الـ record هنا event صغير immutable: حاجة حصلت ووقتها. الـ producer يكتبه مرة، والـ consumers يقروا. الأحداث المرتبطة في topic. الـ polling على الداتابيز كل ما تقلل فترته الـ overhead بيزيد. الأحسن المستهلك يتبّلغ أول ما الحدث يحصل.

لو الـ producer أسرع من المستهلك: ترمي، أو تعمل buffer، أو backpressure توقف المنتج (زي Unix pipes). ولو نود وقعت، الرسايل تضيع ولا لأ؟ الـ durability ليها تمن. في قراءات سنسور ضياع شوية مقبول. في عداد، أي رسالة ضايعة رقم غلط.

Load balancing

كل رسالة لمستهلك واحد. توزيع شغل. الترتيب ممكن يتلخبط لو الرسالة رجعت لحد تاني بعد ما الأول مأكّدش.

Fan-out

كل رسالة لكل المستهلكين. كل واحد مهتم بحاجة: كاش، سيرش، إيميل.

Kafka قدام الطابور

الـ brokers التقليدية (RabbitMQ) بتمسح الرسالة بعد الـ ack. متقدرش ترجع تقرا القديم، والمستهلك الجديد يشوف الجديد بس.

الـ log المقسّم: الـ topic partitions، كل واحدة log مرتب، وكل رسالة ليها offset. المستهلك بيحفظ مكانه. الرسالة تفضل أيام أو أسابيع.

RabbitMQKafka
بعد المعالجةالرسالة تتمسحتفضل لحد الـ retention
التوزيعأي مستهلك فاضيالـ partition لمستهلك واحد
الترتيبممكن يتلخبطمضمون جوه الـ partition
القراءة من الأوللاأيوه، replay من غير ما تغيّر اللوج

مناسب لـ Kafka لما الترتيب والـ replay مهمين. الطابور العادي لما المهمة تقيلة والترتيب مش مهم.

الداتابيز والـ stream

الـ replication log أصلًا stream. الفكرة إن الكاش والسيرش والـ warehouse يتبنوا من نفس الأحداث.

الحل change data capture: اقرأ لوج الداتابيز (Debezium مثلًا) وابعته على Kafka. أو outbox: اكتب الحدث في جدول في نفس الـ transaction، وprocess يقرأه. المستهلكين لازم يبقوا idempotent لأن الرسالة ممكن تتبعت تاني.

Event sourcing: تخزن الأحداث نفسها مش آخر حالة بس. الحالة تتبنى بإعادة التشغيل. مع CQRS: طريق الكتابة أحداث، وطريق القراءة views جاهزة. مفيد لو محتاج audit وتاريخ. التمن إن الـ schema بتاع الأحداث بيعيش طول عمر الداتا.

وقت الحدث والشبابيك

المقاييس اللحظية بتتجمع على windows: كل دقيقة، أو جلسة، أو من أول ما شاف لحد ما قفل. Event time وقت ما الحاجة حصلت. Processing time وقت ما وصلت للمعالج. الحدث المتأخر (موبايل كان أوفلاين) لازم النافذة تستناه شوية، وبعد كده النتيجة تتصحح.

“Exactly-once” في الـ streams معناها العملي: الأثر على الحالة مرة واحدة، مش إن الرسالة اتبعتت مرة بحرفيتها. بيتظبط بـ idempotence و transactions على الـ offset مع الحالة. مش سحر، وبيتكسر لو فيه side effect برا السيستم (إيميل).

Checklist الـ streams

🧠 اختبر نفسك
١) ليه الكتابة في الداتابيز والسيرش ورا بعض خطر؟
لو التانية فشلت يفضلوا مختلفين، ومفيش لوج يعيد المحاولة. استخدم CDC أو outbox.
٢) إيه اللي Kafka بيسيبه و RabbitMQ بيمسحه؟
الرسالة بعد المعالجة. Kafka بيحتفظ بيها فتعيد التشغيل من offset قديم.
٣) حدث وصل متأخر خمس دقايق. أنهي ساعة تهم التقرير؟
Event time: وقت ما حصل. النافذة لازم تستنى المتأخرين أو تتصحح.
٤) exactly-once تضمن إيه؟
إن تحديث الحالة يتحسب مرة. الإيميل اللي اتبعت برا السيستم مش داخل الضمان.