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

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

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

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

معماری کلاستر Kafka با حالت KRaft روی چند سرور

از نسخه ۳.۳ به بعد، 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 modeKRaft mode
تعداد سرویس‌های جداگانهKafka + Zookeeperفقط Kafka
زمان failover هنگام تغییر controllerچند ثانیهزیر یک ثانیه
محدودیت تعداد partition در کلاسترعملاً محدود (metadata در Zookeeper)قابلیت مقیاس‌پذیری بیشتر
سادگی نصب و نگهداریدو سیستم برای مانیتورینگ و آپدیتیک سیستم واحد
پشتیبانی در نسخه‌های جدیداز Kafka 4.0 حذف شدهپیش‌فرض از Kafka 4.0

از Kafka نسخه ۴.۰ به بعد، پشتیبانی از Zookeeper کاملاً حذف شده است؛ بنابراین راه‌اندازی کلاستر جدید با KRaft عملاً تنها مسیر رو به جلو است.

مقایسه معماری Zookeeper (ارتباط ستاره‌ای نودها با یک سرویس مرکزی Z) با معماری KRaft (ارتباط مستقیم نودها با یکدیگر از طریق اجماع Raft)

پیش‌نیازها

برای این راهنما به حداقل سه سرور نیاز داریم؛ می‌توانند سرور مجازی (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 سنگین‌تر، سرور اختصاصی گزینه مناسب‌تری است.

مشاهده پلن‌های سرور مجازی آریانت