راهاندازی کلاستر Apache Kafka با KRaft (بدون Zookeeper) روی چند سرور مجازی و اختصاصی

از نسخه ۳.۳ به بعد، Apache Kafka میتواند بدون Zookeeper اجرا شود. این حالت KRaft (Kafka Raft) نام دارد و از نسخه ۳.۵ به عنوان گزینه پایدار برای محیط production معرفی شده است. در این مقاله راهاندازی کلاستر Kafka با KRaft را روی چند سرور مجازی و اختصاصی، از نصب تا تست نهایی Producer و Consumer، مرحله به مرحله انجام میدهیم.
چرا KRaft و نه Zookeeper؟
در معماری قدیمی Kafka، یک کلاستر جداگانه از Zookeeper مسئول نگهداری metadata کلاستر، انتخاب controller و مدیریت پیکربندی topicها بود. این یعنی برای هر کلاستر Kafka باید یک کلاستر Zookeeper مجزا هم نصب، مانیتور و آپدیت میشد.
در KRaft این metadata درون خود Kafka، با استفاده از الگوریتم اجماع Raft، بین چند نود controller مدیریت میشود. نتیجه این است که به سرور جداگانهای برای Zookeeper نیاز نیست.
| ویژگی | Zookeeper mode | KRaft mode |
|---|---|---|
| تعداد سرویسهای جداگانه | Kafka + Zookeeper | فقط Kafka |
| زمان failover هنگام تغییر controller | چند ثانیه | زیر یک ثانیه |
| محدودیت تعداد partition در کلاستر | عملاً محدود (metadata در Zookeeper) | قابلیت مقیاسپذیری بیشتر |
| سادگی نصب و نگهداری | دو سیستم برای مانیتورینگ و آپدیت | یک سیستم واحد |
| پشتیبانی در نسخههای جدید | از Kafka 4.0 حذف شده | پیشفرض از Kafka 4.0 |
از Kafka نسخه ۴.۰ به بعد، پشتیبانی از Zookeeper کاملاً حذف شده است؛ بنابراین راهاندازی کلاستر جدید با KRaft عملاً تنها مسیر رو به جلو است.

پیشنیازها
برای این راهنما به حداقل سه سرور نیاز داریم؛ میتوانند سرور مجازی (VPS) یا سرور اختصاصی باشند، یا ترکیبی از هر دو، چون KRaft محدودیتی در این زمینه اعمال نمیکند (اگر هنوز سروری ندارید، مراحل خرید و راهاندازی سرور مجازی را ببینید). مشخصات پیشنهادی:
- ۲ هسته CPU و ۴ گیگابایت RAM بهازای هر نود، حداقل برای محیط تست
- دیسک SSD (ترجیحاً NVMe روی سرور اختصاصی برای throughput بالاتر)
- Java 17 یا جدیدتر (OpenJDK)
- دسترسی root یا sudo روی هر سه سرور
- اتصال شبکه پایدار بین سرورها؛ اگر از سرور مجازی و اختصاصی بهصورت ترکیبی استفاده میکنید، تأخیر (latency) بین آنها را از قبل اندازه بگیرید و در صورت نیاز شبکه سرور لینوکس را با TCP BBR و تنظیم sysctl بهینه کنید
در این راهنما IP سه سرور را به این صورت فرض میکنیم:
node-1: 10.0.0.11
node-2: 10.0.0.12
node-3: 10.0.0.13
معماری پیشنهادی کلاستر
برای یک کلاستر کوچک تا متوسط، سادهترین و رایجترین حالت این است که هر سه نود هم نقش broker و هم نقش controller را داشته باشند (combined mode). این حالت نیاز به سرور جداگانه برای controller را حذف میکند و برای اکثر بارهای کاری کافی است.
برای کلاسترهای بزرگتر یا با ترافیک بسیار سنگین، جداسازی نودهای controller از broker (dedicated controller) توصیه میشود، اما موضوع این مقاله نیست و در ادامه سراغ حالت combined میرویم که هر سه سرور واقعی همیشه صرف broker میشوند.
نصب Kafka روی هر سرور
مراحل زیر را روی هر سه سرور تکرار کنید.
sudo apt update
sudo apt install -y openjdk-17-jre-headless wget
wget https://downloads.apache.org/kafka/3.7.1/kafka_2.13-3.7.1.tgz
tar -xzf kafka_2.13-3.7.1.tgz
sudo mv kafka_2.13-3.7.1 /opt/kafka
sudo useradd -r -s /bin/false kafka
sudo mkdir -p /var/lib/kafka-logs
sudo chown -R kafka:kafka /opt/kafka /var/lib/kafka-logs
نسخه Kafka را با آخرین نسخه پایدار موجود در آرشیو رسمی Apache جایگزین کنید.
پیکربندی server.properties برای KRaft
فایل پیکربندی هر نود در /opt/kafka/config/kraft/server.properties قرار دارد. مقادیر زیر باید روی هر سه سرور تنظیم شوند، با تغییر node.id برای هر سرور.
process.roles=broker,controller
node.id=1
controller.quorum.voters=1@10.0.0.11:9093,2@10.0.0.12:9093,3@10.0.0.13:9093
listeners=PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093
advertised.listeners=PLAINTEXT://10.0.0.11:9092
controller.listener.names=CONTROLLER
inter.broker.listener.name=PLAINTEXT
log.dirs=/var/lib/kafka-logs
num.partitions=3
default.replication.factor=3
min.insync.replicas=2
روی سرور دوم node.id=2 و advertised.listeners=PLAINTEXT://10.0.0.12:9092 میشود؛ روی سرور سوم به همین ترتیب. مقدار controller.quorum.voters روی هر سه سرور دقیقاً یکسان و شامل هر سه نود باشد.
نکته مهم: default.replication.factor=3 روی کلاستر سهنودی یعنی هر پیام روی هر سه سرور کپی میشود؛ در صورت از دست رفتن یک سرور، داده از دست نمیرود.
تولید Cluster ID و فرمتبندی storage
پیش از اولین اجرا، باید یک شناسه یکتا برای کلاستر بسازید و همان یک شناسه را روی هر سه سرور استفاده کنید.
/opt/kafka/bin/kafka-storage.sh random-uuid
خروجی این دستور یک رشته مانند xtzWWN4bTjitpL3kfd9s5g است. همین مقدار را روی هر سه سرور برای فرمتبندی storage به کار ببرید:
sudo -u kafka /opt/kafka/bin/kafka-storage.sh format \
-t xtzWWN4bTjitpL3kfd9s5g \
-c /opt/kafka/config/kraft/server.properties
اگر این دستور را روی سرورها با UUID متفاوت اجرا کنید، هر نود فکر میکند به کلاستر دیگری تعلق دارد و اتصال controller شکل نمیگیرد.
راهاندازی به عنوان سرویس systemd
اجرای Kafka بهصورت مستقیم در ترمینال برای production مناسب نیست؛ سرویس systemd زیر را روی هر سه سرور در مسیر /etc/systemd/system/kafka.service بسازید.
[Unit]
Description=Apache Kafka (KRaft mode)
After=network.target
[Service]
Type=simple
User=kafka
Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"
ExecStart=/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.properties
ExecStop=/opt/kafka/bin/kafka-server-stop.sh
Restart=on-failure
LimitNOFILE=100000
[Install]
WantedBy=multi-user.target
سپس روی هر سرور:
sudo systemctl daemon-reload
sudo systemctl enable --now kafka
sudo systemctl status kafka
اگر systemctl status وضعیت active (running) را نشان ندهد، لاگ سرویس را با journalctl -u kafka -n 100 بررسی کنید؛ رایجترین علت، مغایرت controller.quorum.voters بین سرورها یا فرمت نشدن storage با UUID یکسان است.
اگر میخواهید مصرف CPU و RAM سرویس Kafka را روی هر نود محدود کنید تا با سرویسهای دیگر همان سرور تداخل نکند، از cgroups در تعریف systemd کمک بگیرید؛ روش کار در محدود کردن مصرف CPU و RAM سرویسها با systemd و cgroups در سرور لینوکس شرح داده شده است.
تست کلاستر با Producer و Consumer
پس از بالا آمدن هر سه نود، ابتدا یک topic با replication factor سه بسازید (این دستور را فقط روی یکی از سرورها اجرا کنید):
/opt/kafka/bin/kafka-topics.sh --create \
--topic test-topic \
--bootstrap-server 10.0.0.11:9092,10.0.0.12:9092,10.0.0.13:9092 \
--partitions 3 \
--replication-factor 3
وضعیت توزیع partition و replica را بررسی کنید:
/opt/kafka/bin/kafka-topics.sh --describe \
--topic test-topic \
--bootstrap-server 10.0.0.11:9092
سپس یک producer برای ارسال پیام باز کنید:
/opt/kafka/bin/kafka-console-producer.sh \
--topic test-topic \
--bootstrap-server 10.0.0.11:9092,10.0.0.12:9092,10.0.0.13:9092
و در ترمینال یا سروری دیگر، یک consumer برای دریافت همان پیامها:
/opt/kafka/bin/kafka-console-consumer.sh \
--topic test-topic \
--bootstrap-server 10.0.0.12:9092,10.0.0.13:9092 \
--from-beginning
اگر پیامهایی که در producer تایپ میکنید در consumer نمایش داده شوند، کلاستر بهدرستی کار میکند. برای تست واقعی failover، یکی از سرورها را با sudo systemctl stop kafka متوقف کنید و ببینید producer و consumer روی دو نود باقیمانده بدون قطعی ادامه کار میدهند یا نه.
نکات امنیتی و شبکه
- پورتهای ۹۰۹۲ (broker) و ۹۰۹۳ (controller) را در فایروال فقط بین IP سه سرور کلاستر باز کنید، نه رو به اینترنت عمومی؛ برای این کار میتوانید از راهاندازی فایروال nftables روی سرور لینوکس کمک بگیرید.
- اگر سرورها ترکیبی از سرور مجازی و سرور اختصاصی هستند و در دیتاسنتر یا شبکه یکسانی قرار ندارند، از یک شبکه خصوصی (Private Network) یا VPN بین آنها استفاده کنید تا ترافیک replication رمزنگارینشده Kafka از اینترنت عمومی عبور نکند.
- برای محیط production، فعالسازی SASL/SSL روی listenerها را در نظر بگیرید؛ پیکربندی پیشفرض بالا صرفاً برای راهاندازی و تست داخلی است.
مانیتورینگ وضعیت کلاستر
پس از راهاندازی، وضعیت quorum کنترلرها را بهصورت دورهای بررسی کنید:
/opt/kafka/bin/kafka-metadata-quorum.sh \
--bootstrap-server 10.0.0.11:9092 \
describe --status
این دستور نشان میدهد کدام نود leader فعلی است و آیا هر سه نود در quorum حاضرند یا یکی از آنها عقب افتاده (lag) دارد. برای مانیتورینگ مداوم، Kafka متریکهای JMX استانداردی مثل UnderReplicatedPartitions و ActiveControllerCount را ارائه میدهد که با Prometheus و jmx_exporter قابل جمعآوری هستند؛ روش کامل این کار در راهاندازی مانیتورینگ سرور با Prometheus و Grafana توضیح داده شده است. اگر UnderReplicatedPartitions روی هیچ broker صفر نباشد، یعنی حداقل یک replica از topicها همسنگ نودهای دیگر نیست و باید بررسی شود.
جمعبندی
راهاندازی کلاستر Kafka با KRaft، در مقایسه با حالت قدیمی مبتنی بر Zookeeper، یک سرویس کمتر برای نصب و نگهداری و failover سریعتر برای تغییر controller به همراه دارد. با پیکربندی یکسان controller.quorum.voters روی هر نود، UUID یکسان هنگام فرمتبندی storage، و یک سرویس systemd پایدار، یک کلاستر سهنودی آماده تحمل خطا در کمتر از یک ساعت راه میافتد.
برای اجرای این معماری روی زیرساخت واقعی، به سرورهایی با دیسک NVMe و شبکه داخلی پایدار بین نودها نیاز دارید. سرورهای مجازی آریانت برای این کار پیکربندیهای آماده با دیسک NVMe و شبکه داخلی بین نودها ارائه میدهند؛ برای پروژههایی با ترافیک replication سنگینتر، سرور اختصاصی گزینه مناسبتری است.




