بنية التخزين المؤقت والمراسلة

تشغيل Kafka في بيئة الإنتاج

18 دقيقة الدرس 6 من 30

تشغيل Kafka في بيئة الإنتاج

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

تحديد حجم الأقسام

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

معادلة الإنتاجية. عدد الأقسام المستهدف = max(Tin / p, Tout / c)، حيث Tin هو الإنتاجية القصوى للاستيعاب بالميغابايت/ثانية، وp هو إنتاجية الكتابة لكل قسم (~10 MB/s على NVMe)، وc هو إنتاجية المستهلك لكل قسم. موضوع يستقبل 500 MB/s بـ5 خيوط مستهلك يحتاج 12 قسماً مع هامش نمو.

تكلفة معالجات الملفات. كل نسخة قسم تفتح معالجَي ملف (فهرس + مقطع). وسيط يستضيف 50 000 نسخة قسم يحتاج 100 000 معالج ملف على الأقل؛ اضبط ulimit -n 200000 في وحدة systemd وfs.file-max بالقدر المناسب.

إعادة توزيع الأقسام. عند الحاجة لإعادة التقسيم، استخدم kafka-reassign-partitions.sh مع معاملات خنق حركة البيانات حتى لا يُشبع إعادة التوازن شبكة الوسطاء. معدل خنق النسخ 50 MB/s محافظ لكن آمن للكلستر الخادم.

# إنشاء موضوع بعدد أقسام مدروس kafka-topics.sh --bootstrap-server kafka:9092 \ --create --topic payments.raw \ --partitions 24 \ --replication-factor 3 \ --config min.insync.replicas=2 \ --config retention.ms=604800000 # وصف الموضوع للتحقق من حالة ISR فور الإنشاء kafka-topics.sh --bootstrap-server kafka:9092 \ --describe --topic payments.raw # تنفيذ خطة إعادة توزيع (خنق عند 50 MB/s = 52428800 بايت/ثانية) kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \ --reassignment-json-file expand-plan.json \ --execute \ --replica-assignment-throttle 52428800 # التحقق من التقدم kafka-reassign-partitions.sh --bootstrap-server kafka:9092 \ --reassignment-json-file expand-plan.json \ --verify

سياسات الاحتفاظ بالبيانات

الاحتفاظ هو ميزانية تخزين، لا استراتيجية نسخ احتياطي. بُعدان يتحكمان فيه: زمني (retention.ms) وحجمي (retention.bytes). كلاهما يُطبَّق لكل قسم؛ الحد الأقصى لحجم الموضوع هو retention.bytes * عدد_الأقسام. يُطبَّق أيهما بلغ أولاً.

دوران المقاطع. يُطبَّق الاحتفاظ بدقة المقطع لا الرسالة. لا يُحذف المقطع إلا إذا كان أقدم من retention.ms وتوجد مقاطع أحدث. المقطع النشط (المفتوح) لا يُحذف أبداً. موضوع منخفض الحجم مع segment.ms كبير يمكن أن يحتفظ بالبيانات أطول بكثير مما يشير إليه retention.ms. لمواضيع التدقيق، اضبط segment.ms قريباً من retention.ms / 2.

التخزين المتدرج. تقدم كل من Confluent وAWS MSK تخزيناً متدرجاً حيث تُنقل المقاطع الأقدم من عتبة ما إلى تخزين الكائنات (S3/GCS)، مع إبقاء البيانات الحارة الأخيرة على NVMe محلي. هذا يفصل تكلفة التخزين عن توسيع الحوسبة وهو النمط الموصى به للمواضيع ذات الاحتفاظ بالأسابيع أو الأشهر.

# تجاوزات لكل موضوع لسجل تدقيق عالي الحجم kafka-configs.sh --bootstrap-server kafka:9092 \ --entity-type topics \ --entity-name audit.events \ --alter \ --add-config retention.ms=2592000000,\ retention.bytes=107374182400,\ segment.ms=86400000,\ segment.bytes=536870912 # التحقق من الإعدادات الفعلية (يُظهر التجاوزات الديناميكية مقابل الافتراضات) kafka-configs.sh --bootstrap-server kafka:9092 \ --entity-type topics \ --entity-name audit.events \ --describe

ضغط السجل (Log Compaction)

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

يعمل الضغط في خيوط خلفية تتحكم فيها log.cleaner.threads (الافتراضي 1، ارفع إلى 4-6 في الكلسترات الكبيرة). المنظف يستهدف الأقسام التي تتجاوز نسبة "القذارة" الخاصة بها (بايتات غير مضغوطة / إجمالي البايتات) القيمة min.cleanable.dirty.ratio. للضغط العدواني على مواضيع CDC المنخفضة الكمون، خفّض هذه القيمة إلى 0.1.

علامات الحذف (Tombstones). السجل ذو قيمة null هو علامة حذف — يُشير لحذف ذلك المفتاح. تُحفظ علامات الحذف لمدة لا تقل عن delete.retention.ms (الافتراضي 24 ساعة) حتى يلحق المستهلكون قبل اختفاء المفتاح كلياً.

فخ سياسة التنظيف المختلطة. ضبط cleanup.policy=compact,delete يطبق كليهما: يعمل الضغط وتُحذف المقاطع بعد retention.ms. هذا يعني أن حتى "أحدث" قيمة لمفتاح يمكن أن تختفي إذا كان الموضوع صغيراً بما يكفي ليسبق الحذفُ الضغطَ. للدلالات النقية للسجل، استخدم cleanup.policy=compact فقط.

مراقبة تأخر المستهلك

تأخر المستهلك هو الفرق بين إزاحة نهاية السجل (LEO) والإزاحة المُثبَّتة لكل قسم. تأخر يتزايد باستمرار هو أول علامة على مستهلك غير قادر على المواكبة؛ تأخر ذو تذبذب يشير إلى معالجة انفجارية. كلاهما يستدعي تدخلاً لكن الاستجابة تختلف.

الأدوات الأصلية. kafka-consumer-groups.sh --describe يُظهر التأخر لكل قسم وتعيين المستهلك. صحيح لكنه لقطة آنية؛ يفوته التأخر الذي يتذبذب ويتعافى بين الاستطلاعات.

تكامل Prometheus. نشر kafka-exporter أو مُصدِّر JMX من Confluent. المقياس الحرج هو kafka_consumergroup_lag لكل مجموعة/موضوع/قسم. يُنبَّه على: إجمالي التأخر يتجاوز 10× حالة الاستقرار الطبيعية، معدل تغيّر التأخر موجب لأكثر من 5 دقائق، أي قسم بتأخر > 0 ولا يوجد له مستهلك نشط.

Kafka Lag and ISR Monitoring Flow Kafka Broker Cluster Partition 0 LEO: 1 200 000 Partition 1 LEO: 980 000 ISR: [0, 1, 2] — healthy All replicas in sync ISR: [0] — degraded Replicas 1, 2 fell behind Log Segments seg-0 (deleted) seg-1 seg-2 (active) retention.ms enforced per segment Observability Stack JMX / kafka-exporter scrape :9308 Prometheus kafka_consumergroup_lag Alertmanager lag > threshold Grafana Dashboard lag / ISR / throughput Consumer Group: payments-svc committed offset tracked per partition Lag = LEO - Committed Offset alert when lag rate-of-change > 0 for 5 min metrics
تدفق مراقبة التأخر وISR في Kafka: تكشف الوسطاء عن المقاييس عبر JMX/المُصدِّر، يخزّنها Prometheus، يُطلق Alertmanager التنبيهات عند نمو التأخر، ويعرض Grafana الصورة التشغيلية الكاملة.

مراقبة ISR (النسخ المتزامنة)

مجموعة ISR هي المؤشر الحتمي لصحة النسخ المتماثل. عندما تسقط نسخة من ISR — لأنها متأخرة أكثر من replica.lag.time.max.ms (الافتراضي 30 ثانية) عن القائد — يعمل الكلستر دون ضمان المتانة. إذا كان موضوعك مع min.insync.replicas=2 وRF=3 يفقد نسختين من ISR، سيُحجب جميع المنتجين ذوي acks=all بخطأ NotEnoughReplicasException.

مقاييس JMX الرئيسية للتنبيه عليها:

  • kafka.server:type=ReplicaManager,name=UnderReplicatedPartitions — أي قيمة فوق 0 تنبيه من الأولوية الأولى في العمليات الطبيعية.
  • kafka.server:type=ReplicaManager,name=IsrShrinksPerSec — معدل موجب يعني أن النسخ تتأخر بنشاط؛ تحقق فوراً من الشبكة وإدخال/إخراج القرص وGC على الوسيط المتأخر.
  • kafka.controller:type=KafkaController,name=ActiveControllerCount — يجب أن يكون 1 بالضبط.
  • kafka.network:type=RequestMetrics,name=RequestsPerSec,request=Produce — أسِّس خطاً أساسياً للكشف عن ارتفاعات حركة المرور التي تسبق انكماش ISR.
فحص ISR قبل النشر. قبل أي إعادة تشغيل متدرجة للوسيط (تحديث متدرج على Kubernetes، استبدال AMI، تطبيق تصحيحات النواة)، تحقق من أن UnderReplicatedPartitions = 0 وأن جميع مجموعات المستهلكين لا تعاني من تأخر في المواضيع الحرجة. أدمج هذه الفحوصات في خط أنابيب النشر كما تدمج فحوصات جاهزية حاويات Kubernetes.
# التحقق من الأقسام الناقصة النسخ عبر الكلستر kafka-topics.sh --bootstrap-server kafka:9092 \ --describe \ --under-replicated-partitions # التحقق من تأخر مجموعة مستهلكين محددة kafka-consumer-groups.sh --bootstrap-server kafka:9092 \ --group payments-svc \ --describe # إعادة ضبط إزاحة المستهلك إلى الأحدث (في حالات الطوارئ فقط) kafka-consumer-groups.sh --bootstrap-server kafka:9092 \ --group payments-svc \ --topic payments.raw \ --reset-offsets \ --to-latest \ --execute # انتخاب النسخة المفضلة (إصلاح قيادة الأقسام بعد إعادة التشغيل المتدرج) kafka-leader-election.sh --bootstrap-server kafka:9092 \ --election-type PREFERRED \ --all-topic-partitions

أنماط دفتر التشغيل

يُشفّر المهندسون المتقدمون ردود أفعالهم على انكماش ISR والتأخر المتصاعد كخطوات في دفتر التشغيل، لا كحدس:

  1. انكماش ISR على وسيط واحد. تحقق من iostat -xz 1 وسجلات GC على ذلك الوسيط. إذا تجاوز انتظار I/O القرص 80%، الوسيط يُفرغ السجل بشكل متسارع — تأكد من أن مسح ذاكرة التخزين المؤقت للصفحات يتولى المهمة.
  2. تأخر المستهلك يتزايد بثبات. أضف نسخ المستهلك حتى عدد الأقسام (أبعد من ذلك تكون خاملة). تحقق مما إذا كانت المعالجة مقيدة بالمعالج أو الإدخال/الإخراج. إذا كانت مقيدة بالإدخال/الإخراج (استدعاءات قاعدة بيانات خارجية)، افصل مع مجمّع عمال غير متزامن.
  3. استنزاف القرص. طارئ: خفّض retention.bytes على أكبر المواضيع، أو أطلق حذف مقاطع مبكراً عبر kafka-delete-records.sh. على المدى البعيد: أضف وسطاء وأعد توازن الأقسام.
Kafka يعمل على الثقة في عقد ISR. اللحظة التي تتجاوز فيها unclean.leader.election.enable=true (معطّل افتراضياً منذ Kafka 0.11)، تتبادل الاتساق بالتوافر — يمكن لنسخة متأخرة أن تصبح قائداً، مسببةً خسارة رسائل. هذا غير مقبول أبداً للمواضيع المالية أو موضوعات التدقيق. لأعباء العمل عالية التوافر التي تتحمل إعادة المعالجة (استيعاب المقاييس، تدفق النقرات)، يمكن تفعيله كملاذ أخير خلال حدث خسارة كاملة لـ ISR، لكن وثّق ذلك كقرار معماري صريح وعُد عنه فور التعافي.