تطوير الويب

نشر cluster Apache Kafka 4.2 في وضع KRaft بلا ZooKeeper

3 min de lecture

السلسلة: هذا الدرس جزء من سلسلة Kafka 4.2. اقرأ المقال الرئيسي.

منذ صدور Apache Kafka 4.0 في مارس 2025، اختفى ZooKeeper تماماً من المحرّك. KRaft، بروتوكول الإجماع الداخلي المستلهَم من Raft، يدير الآن وحده metadata العنقود — انتخابات leader، ضبط topics، ACL، توزيع partitions. لفريق يكتشف Kafka 4.2 في 2026، هذا يُغيّر شيئين ملموسين: لم تعد عملية ZooKeeper لتثبيت ورصد وترقيع؛ وإجراء bootstrap للعنقود يمرّ بمعرّف cluster، عقد بأدوار صريحة (controller، broker أو الاثنان)، وquorum مخصّص للمتحكّمين.

المتطلبات

  • ثلاثة VPS Linux Ubuntu 24.04 LTS أو Debian 12 — 4 vCPU، 8 جيغا RAM، 80 جيغا SSD كل واحد (Hetzner CX32 أو Hostinger KVM 4)
  • OpenJDK 21 أو Java 25 — Kafka 4.2 يدعم رسمياً Java 17، 21 و25
  • وصول SSH root وfirewall يدع المنفذين 9092 (broker) و9093 (controller) بين الآلات الثلاث
  • المستوى: متوسط
  • 90 دقيقة

الخطوة 1 — تثبيت Java وتحميل Kafka 4.2

sudo apt update
sudo apt install -y openjdk-21-jdk wget
java -version

# تحميل Kafka 4.2.0 — Scala 2.13 ثنائي موصى به
cd /opt
sudo wget https://downloads.apache.org/kafka/4.2.0/kafka_2.13-4.2.0.tgz
sudo tar -xzf kafka_2.13-4.2.0.tgz
sudo mv kafka_2.13-4.2.0 kafka
sudo useradd -r -d /opt/kafka -s /bin/false kafka
sudo chown -R kafka:kafka /opt/kafka

مخرَج java -version يجب أن يعرض openjdk version "21" أو أحدث.

الخطوة 2 — توليد معرّف cluster

في KRaft، كل cluster له معرّف فريد بـ 22 حرفاً مُولَّد مرة واحدة. كل الآلات تتقاسم هذا المعرّف للتعرّف على بعضها، ويخدم أيضاً كتوقيع لمنع broker من تثبيت آخر بالخطأ.

sudo -u kafka /opt/kafka/bin/kafka-storage.sh random-uuid
# مثال مخرَج
# WJxR2KdLT_qV9bGq3oZc4w

الخطوة 3 — ضبط server.properties لـ KRaft مدمَج

ثلاث خصائص تقوم بكل العمل: process.roles الذي يُعرّف دور العقدة، node.id الذي يجب أن يكون فريداً لكل عقدة، وcontroller.quorum.voters الذي يسرد متحكّمي quorum.

# /opt/kafka/config/server.properties — العقدة kafka1
process.roles=controller,broker
node.id=1
controller.quorum.voters=1@kafka1.example.com:9093,2@kafka2.example.com:9093,3@kafka3.example.com:9093
listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
advertised.listeners=PLAINTEXT://kafka1.example.com:9092
controller.listener.names=CONTROLLER
inter.broker.listener.name=PLAINTEXT
log.dirs=/var/lib/kafka/data
num.partitions=3
default.replication.factor=3
min.insync.replicas=2
auto.create.topics.enable=false

دقائق مهمة: process.roles=controller,broker ما يُسمى نشر مدمج. التوثيق الرسمي يحدّد أن هذا الوضع مخصّص للتطوير والاختبار، لا للإنتاج الحرج. min.insync.replicas=2 مع default.replication.factor=3 الثنائي الذي يسمح بالديمومة (خسارة آلة = لا خسارة رسالة مؤكَّدة) وبتوفّر الكتابة. على kafka2، غيّر node.id=2؛ على kafka3، node.id=3. قائمة voters تبقى متطابقة على العقد الثلاث.

الخطوة 4 — تنسيق التخزين بمعرّف cluster

CLUSTER_ID="WJxR2KdLT_qV9bGq3oZc4w"

sudo mkdir -p /var/lib/kafka/data
sudo chown -R kafka:kafka /var/lib/kafka

sudo -u kafka /opt/kafka/bin/kafka-storage.sh format \
  --config /opt/kafka/config/server.properties \
  --cluster-id "$CLUSTER_ID"

المخرَج المنتظَر Formatting metadata directory /var/lib/kafka/data with metadata.version 4.2-IV0. لا تُعد أبداً هذا الأمر على cluster إنتاج تحت طائلة محو كل metadata.

الخطوة 5 — إنشاء خدمة systemd وإطلاق cluster

# /etc/systemd/system/kafka.service
[Unit]
Description=Apache Kafka 4.2 — KRaft mode
After=network.target

[Service]
Type=simple
User=kafka
Group=kafka
ExecStart=/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/server.properties
ExecStop=/opt/kafka/bin/kafka-server-stop.sh
Restart=on-failure
LimitNOFILE=100000
Environment="KAFKA_HEAP_OPTS=-Xms2G -Xmx2G"

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now kafka
sudo systemctl status kafka
sudo journalctl -u kafka -f --since "5 min ago"

السجل يجب أن يعرض بعد 15-30 ثانية «KafkaServer id=1 started» على كل عقدة. إن رأيت في حلقة «Timed out waiting for connection to quorum»، تقريباً دائماً firewall.

الخطوة 6 — التحقق من quorum وإنشاء أول topic

/opt/kafka/bin/kafka-metadata-quorum.sh \
  --bootstrap-server kafka1.example.com:9092 \
  describe --status

المخرَج المنتظَر ClusterId, LeaderId: 1, LeaderEpoch: 4, HighWatermark: 87, MaxFollowerLag: 0. MaxFollowerLag: 0 يعني المتحكّمين الثلاثة متزامنون تماماً.

/opt/kafka/bin/kafka-topics.sh \
  --bootstrap-server kafka1.example.com:9092 \
  --create --topic ventes-mobile-money \
  --partitions 6 --replication-factor 3 \
  --config min.insync.replicas=2

الخطوة 7 — نشر واستهلاك رسالة اختبار

# Terminal 1 — consumer
/opt/kafka/bin/kafka-console-consumer.sh \
  --bootstrap-server kafka1.example.com:9092 \
  --topic ventes-mobile-money \
  --from-beginning

# Terminal 2 — producer
/opt/kafka/bin/kafka-console-producer.sh \
  --bootstrap-server kafka1.example.com:9092 \
  --topic ventes-mobile-money
> {"client":"+966501234567","montant":150,"moyen":"Mada"}
> {"client":"+971501234568","montant":245,"moyen":"STC Pay"}

السطران JSON يجب أن يظهرا فوراً جانب consumer. إن لم يخرج شيء، تحقّق DNS وأن المنفذ 9092 مفتوح. هذا الخطأ رقم 1 لأول نشر: العميل يتصل بـ bootstrap، يستلم قائمة advertised.listeners، ولا يستطيع بلوغ brokers بالأسماء.

أخطاء شائعة

الخطأ السبب الحل
UnknownHostException DNS داخلي سيئ الإعداد أضف في /etc/hosts أو DNS خاص
InvalidClusterIdException UUID مختلف بين meta.properties و--cluster-id احذف log.dirs على العقدة الخاطئة وأعد التنسيق
Connection to node -1 could not be established منفذ 9092 أو 9093 محجوب افتح المنافذ بين العقد
NotEnoughReplicasException broker معطّل وmin.insync.replicas لا يمكن تلبيته تحقّق quorum وأعد تشغيل broker الناقص
InconsistentNodeIdException عقدتان بنفس node.id عدّل server.properties وأعد التنسيق

تأمين ورصد الباقي

Cluster يشتغل صريحاً على PLAINTEXT، يناسب بيئة pre-prod معزولة على VPC. للإنتاج، إضافتان جوهريتان: تفعيل SASL/SCRAM أو mTLS على listener client، وربط Prometheus مع kafka-exporter من Danielqsj لكشف مقاييس lag وthroughput وحالة المتحكّمين.

في منطقة MENA، cluster مستضاف ذاتياً على ثلاثة VPS Hetzner CX32 يكلّف ~20 يورو/شهر — throughput كافٍ لمنصة paiement متوسطة. لكن احسب كموناً 80-110 مللي ثانية من الرياض أو القاهرة، ما يستثني الاستخدامات الآنية الصارمة (trading) لكنه مقبول جداً لتدفق أحداث أعمال.

لماذا KRaft يغيّر المعادلة التشغيلية

طوال 12 سنة، Kafka فوّض إدارة metadata العنقود إلى ZooKeeper. مع الوقت، صار ازدواج الأدوار مكلفاً. فريق يريد إدارة Kafka كان يجب أن يفهم أيضاً تعقيدات ZooKeeper: znodes، observers، sessions، ACL خاصة، إصدار تسجيل snapshot، معاملات tickTime وinitLimit.

KRaft يحلّ هذا الاحتكاك بتدويل التنسيق داخل عملية Kafka. البروتوكول مبني على Raft، أبسط للاستدلال من ZAB، ويُخزّن سجلاته مباشرة في نفس بنية log الـ topics التجارية. لفرق MENA تبدأ مشروع event streaming في 2026، التبسيط جذري: ثنائي واحد للنشر، ملف إعداد واحد للفهم، مجموعة مقاييس واحدة للرصد. منحنى التعلّم الأولي ينخفض ~40% مقابل نشر Kafka 3.5 مع ZooKeeper.

فهم الأدوار: controller، broker أو مدمج

Controller يشارك في quorum يصون metadata cluster؛ يصوّت، يقترح، يصادق على تغييرات الحالة العالمية. Broker يستقبل المنتجين، يخدم المستهلكين، يخزّن وينسخ partitions topics تطبيقية. على عقدة مدمجة الدوران يتعايشان في نفس JVM.

لـ clusters أقل من 5 عقد، المدمج محتمل في pre-prod لكن التوثيق Apache Kafka يدلّ صراحة أن المدمج غير مدعوم لأحمال الإنتاج. ابتداء من 6 عقد أو لأي حمل إنتاج جدّي، فصل الدورين إلزامي.

اختيار replication factor وmin.insync.replicas

الثنائي الموصى به للأغلبية الساحقة من الاستخدامات — paiement موبايل، استيعاب logs، CDC — هو RF=3، min.isr=2. أفضل توازن بين الديمومة والتوفّر. لبيانات حساسة جداً، مثل journal معاملات wallet مالي، انتقل إلى RF=5، min.isr=3 عبر إعداد topic.

الاحتفاظ والنسخ

Kafka ليس قاعدة بيانات. الاحتفاظ الافتراضي 7 أيام (log.retention.hours=168). لـ topic أحداث أعمال يُمكن إعادة تشغيله، نضع نمطياً retention.ms 30 يوماً. لبيانات تنظيمية، نُحفظ segments في MinIO ونضبط topic على cleanup.policy=compact.

مقالات ذات صلة

Sponsoriser ce contenu

Cet emplacement est à vous

Position premium en fin d'article — c'est l'instant où les lecteurs sont le plus engagés. Réservez cet espace pour votre marque, votre formation ou votre offre.

Recevoir nos tarifs
Publicité