حالت تاریک
فصل ۶ — Brokerها
این فصل شامل:
- نقش brokerها و وظایف آنها
- ارزیابی گزینهها برای برخی مقادیر پیکربندی broker
- توضیح replicaها و نحوهٔ بهروز ماندن آنها
تا اینجا در بحثهایمان، Kafka را از دیدگاه توسعهدهندهٔ برنامهای که از برنامهها و فرآیندهای خارجی تعامل میکند دیدهایم. اما Kafka سیستم توزیعشدهای است که شایستهٔ توجه به خودش است. در این فصل، به بخشهایی که brokerهای Kafka را کار میاندازند نگاه میکنیم.
۶.۱ معرفی broker
اگرچه تا اینجا روی سمت کلاینت Kafka تمرکز کردیم، تمرکزمان حالا به بخش قدرتمند دیگر اکوسیستم میرود: brokerها. Brokerها با brokerهای دیگر همکاری میکنند تا هستهٔ سیستم را تشکیل دهند.
با شروع کشف Kafka، کسانی که با مفاهیم big data آشنا هستند یا قبلاً با Hadoop کار کردهاند، اصطلاحاتی آشنا مانند rack awareness (دانستن اینکه ماشین روی کدام rack فیزیکی سرور میزبانی میشود) و پارتیشنها میبینند. Kafka ویژگی rack awareness دارد که replicaهای یک پارتیشن را فیزیکی روی rackهای جدا قرار میدهد [1]. استفاده از اصطلاحات دادهای آشنا باید احساس خانهبودن بدهد و موازیهای جدید بین آنچه قبلاً کار کردهایم و آنچه Kafka برایمان میکند بکشیم. هنگام راهاندازی کلاستر Kafka خودمان، مهم است بدانیم کلاستر دیگری هم داریم: Apache ZooKeeper. پس از آنجا شروع میکنیم.
۶.۲ نقش ZooKeeper
ZooKeeper بخش کلیدی نحوهٔ کار brokerهاست و برای اجرای Kafka الزامی است. چون Kafka باید قبل از brokerها در حال اجرا و موجود باشد، بحث را از آنجا شروع میکنیم.
یادداشت همانطور که در فصل ۲ گفتیم، برای سادهسازی نیازمندیهای اجرای Kafka، پیشنهادی برای جایگزینی ZooKeeper با quorum مدیریتشدهٔ خودش [2] وجود داشت. چون این کار هنگام انتشار کتاب هنوز کامل نشده بود، ZooKeeper در این اثر بحث میشود. اما به دنبال انتشار early access quorum مدیریتشده در نسخه ۲.۸.۰ باشید.
چون ZooKeeper برای انتخاب leader و رسیدن به تصمیم به حداقل تعداد نیاز دارد، این کلاستر برای brokerهای ما واقعاً مهم است [3]. خود ZooKeeper اطلاعاتی مانند topicها در کلاستر ما را نگه میدارد [4]. ZooKeeper با هماهنگی تخصیصها و اعلانها به brokerها کمک میکند [5].
با همهٔ این تعامل با brokerها، مهم است ZooKeeper را قبل از شروع brokerها اجرا کنیم. سلامت کلاستر ZooKeeper بر سلامت brokerهای Kafka ما تأثیر میگذارد. مثلاً اگر نمونههای ZooKeeper آسیب ببینند، metadata و پیکربندی topic ممکن است از دست برود.
معمولاً لازم نیست جزئیات (آدرس IP و پورت) کلاستر ZooKeeper را به برنامههای producer و consumer نشان دهیم. برخی فریمورکهای legacy که استفاده میکنیم هم ممکن است راهی برای اتصال برنامهٔ کلاینت با کلاستر ZooKeeper بدهند. یکی از مثالها نسخه ۳.۱.x Spring Cloud Stream است که اجازه میداد property zkNodes را تنظیم کنیم [6]. مقدار پیشفرض localhost بود و در بیشتر موارد باید دست نخورده بماند تا وابستگی به ZooKeeper اجتناب شود. property zkNodes بهعنوان deprecated علامتگذاری شده، اما هرگز نمیدانید با کد قدیمیتر برای نگهداری مواجه میشوید، پس چشمتان را باز نگه دارید. چرا این الان و در آینده لازم نیست؟ علاوه بر اینکه Kafka همیشه به ZooKeeper نیاز نخواهد داشت، مهم است از وابستگیهای خارجی غیرضروری در برنامههایمان اجتناب کنیم. همچنین پورتهای کمتری برای expose کردن داریم اگر با firewall کار میکنیم تا Kafka و کلاینت مستقیماً ارتباط برقرار کنند.
با ابزار Kafka zookeeper-shell.sh که در پوشهٔ bin نصب Kafka قرار دارد، میتوانیم به host ZooKeeper در کلاستر متصل شویم و ببینیم داده چگونه ذخیره میشود [7]. یکی از راههای یافتن مسیرهایی که Kafka استفاده میکند، نگاه به کلاس ZkData.scala [8] است. در این فایل مسیرهایی مانند /controller، /controller_epoch، /config و /brokers را پیدا میکنید. اگر به مسیر /brokers/topics نگاه کنیم، لیست topicهایی که ساختهایم را میبینیم. در این نقطه امیدواریم حداقل topic kinaction_helloworld در لیست باشد.
یادداشت میتوانیم از ابزار Kafka دیگر
kafka-topics.shهم برای دیدن لیست topicها استفاده کنیم و همان نتیجه را بگیریم! دستورات در لیستینگهای بعد برای دادههایشان به ZooKeeper و Kafka متصل میشوند اما با رابط دستور متفاوت. خروجی باید topicی که در فصل ۲ ساختیم،[kinaction_helloworld]را شامل شود.
لیستینگ ۶-۱. فهرست topicهای ما
shell
bin/zookeeper-shell.sh localhost:2181 # Connects to our local
ls /brokers/topics # Lists all the topics # ZooKeeper instance
# with the ls command
# OR
bin/kafka-topics.sh --list \ # Using kafka-topics,
➥ --bootstrap-server localhost:9094 # connects to ZooKeeper
# and lists the topicsحتی وقتی ZooKeeper دیگر Kafka را قدرت ندهد، ممکن است با کلاسترهایی که هنوز migrate نشدهاند کار کنیم و احتمالاً ZooKeeper را در مستندات و منابع مرجع مدتی میبینیم. بهطور کلی، آگاهی از وظایفی که Kafka قبلاً به ZooKeeper وابسته بود و گذار به مدیریت آنها داخل کلاستر Kafka با nodeهای metadata داخلی، بینش در قطعات متحرک کل سیستم میدهد.
broker بودن در Kafka یعنی توانایی هماهنگی با brokerهای دیگر و صحبت با ZooKeeper. در تست یا کار با کلاسترهای proof-of-concept، ممکن است فقط یک node broker داشته باشیم. اما در production تقریباً همیشه چند broker داریم.
فعلاً از ZooKeeper دور میشویم. شکل ۶-۱ نشان میدهد brokerها در کلاستر چگونه وجود دارند و خانهٔ logهای دادهٔ Kafka هستند. کلاینتها برای ورود و خروج اطلاعات به و از Kafka به brokerها مینویسند و میخوانند و توجه broker را میطلبند [9].
شکل ۶-۱. Brokerها
Producer clients JVM application-message broker Examples Kafka core Like our Data in kinaction_alert • Databases (to partition) • IOT events OS page cache (memory) producer • Browser/user web events • Logs Flushed to disk Messages can be replayed Topic from the beginning of the Replay log and consumed again. Partition 0 0 1 2 3 4 Consumer clients Examples Data out • Logs are append only. Like our • HDFS (from partition) • New entries added to the end. kinaction_alert • S3 consumer • No database storage, just disk. • Web applications • Each log is made up of entries • Metrics labeled with offset numbers. • Analytics engines ZooKeeper ensemble Message brokers (cluster) + Expanded ZooKeeper used for One of the brokers distributed configuration will be a controller. and management
۶.۳ گزینهها در سطح broker
پیکربندی بخش مهمی از کار با کلاینتها، topicها و brokerهای Kafka است. اگر به مراحل راهاندازی برای ساخت اولین brokerهایمان در پیوست A نگاه کردهاید، فایل server.properties را آنجا تغییر دادیم و سپس بهعنوان آرگومان خط فرمان به shell script راهاندازی broker پاس دادیم. این فایل راه رایجی برای پاس دادن پیکربندی مشخص به نمونهٔ broker است. مثلاً property پیکربندی log.dirs در آن فایل همیشه باید به محل logای تنظیم شود که برای راهاندازی شما منطقی است.
این فایل هم با پیکربندیهای مربوط به listenerها، محل log، retention log، ZooKeeper و تنظیمات group coordinator سروکار دارد [10]. مانند پیکربندیهای producer و consumer، در مستندات http://mng.bz/p9p2 به دنبال برچسب Importance با مقدار «high» بگردید.
لیستینگ ۶-۲. ساخت topic با یک replica
shell
bin/kafka-topics.sh --create \
--bootstrap-server localhost:9094 \ # Creates a topic with only one
--topic kinaction_one_replica # partition and one replica
bin/kafka-topics.sh --describe --bootstrap-server localhost:9094 \
--topic kinaction_one_replica
Topic: one-replica PartitionCount: 1 ReplicationFactor: 1 Configs:
Topic: kinaction_one_replica Partition: 0
Leader: 2 Replicas: 2 Isr: 2 # Describes the kinaction_one_replica
# topic with all the data located
# on the broker with ID 2وقتی دستورات لیستینگ ۶-۲ را برای ساخت و describe کردن topic kinaction_one_replica اجرا میکنیم، فقط یک مقدار در فیلدهای Partition، Leader، Replicas و Isr (in-sync replicas) میبینیم. علاوه بر این، broker همان مقدار ID را استفاده میکند. یعنی کل topic به آن یک broker که روشن و در حال کار است وابسته است.
اگر broker با ID ۲ در این مثال را terminate کنیم و سپس سعی کنیم پیامی از آن topic مصرف کنیم، پیامی مانند «1 partitions have leader brokers without a matching listener» میگیریم. چون کپی replica برای پارتیشن topic نیست، راه آسان برای ادامهٔ تولید یا مصرف آن topic بدون بازیابی آن broker نیست. اگرچه فقط یک مثال است، اهمیت پیکربندی broker را هنگام ساخت دستی topicها مانند لیستینگ ۶-۲ نشان میدهد.
property پیکربندی مهم دیگری که باید تعریف شود، محل logهای برنامه و خطاها در عملکرد عادی را مشخص میکند. این را بعداً میبینیم.
۶.۳.۱ logهای دیگر Kafka: logهای برنامه
مانند بیشتر برنامهها، Kafka logهایی برای اطلاع از آنچه داخل برنامه میگذرد فراهم میکند. در بحثی که میآید، اصطلاح logهای برنامه به logهایی اشاره دارد که معمولاً هنگام کار با هر برنامه، چه برای debugging چه auditing، به آن فکر میکنیم. این logهای برنامه به logهای رکوردی که ستون فقرات ویژگیهای Kafka را تشکیل میدهند مربوط نیستند.
محل ذخیرهٔ این logهای برنامه هم کاملاً با logهای رکورد متفاوت است. وقتی broker را شروع میکنیم، پوشهٔ log برنامه را در پوشهٔ logs/ زیر دایرکتوری پایهٔ نصب Kafka پیدا میکنیم. میتوانیم این محل را با ویرایش فایل config/log4j.properties و مقدار kafka.logs.dir تغییر دهیم [11].
۶.۳.۲ Server log
بسیاری از خطاها و رفتارهای غیرمنتظره به مسائل پیکربندی در راهاندازی برمیگردند. فایل server log یعنی server.log جایی است که اگر خطای راهاندازی یا استثنایی که broker را متوقف میکند باشد نگاه میکنیم. طبیعیترین جا برای بررسی اول هر مشکلی به نظر میرسد. به دنبال عنوان Kafka-Config values بگردید (یا از دستور grep استفاده کنید).
اگر هنگام نگاه اول به پوشهای که این فایل را نگه میدارد گیج شدید، توجه کنید احتمالاً فایلهای دیگری مانند controller.log (اگر broker آن نقش را داشته) و فایلهای قدیمیتر با همان نام میبینید. یکی از ابزارهایی که برای چرخش و فشردهسازی log میتوانید استفاده کنید logrotate (https://linux.die.net/man/8/logrotate) است، اما ابزارهای زیاد دیگری هم برای مدیریت server logهای قدیمیتر هست.
چیز دیگری که دربارهٔ این logها باید گفت این است که روی هر broker قرار دارند. بهطور پیشفرض در یک مکان جمع نمیشوند. پلتفرمهای مختلف ممکن است این کار را برای ما انجام دهند، یا میتوانیم با ابزاری مانند Splunk™ (https://www.splunk.com/) جمعآوری کنیم. بهویژه هنگام تحلیل logها مهم است بدانیم، بهویژه در محیط ابری که نمونهٔ broker ممکن است وجود نداشته باشد.
۶.۳.۳ مدیریت state
همانطور که در فصل ۲ بحث کردیم، هر پارتیشن یک replica leader دارد. replica leader در هر زمان روی یک broker قرار دارد. یک broker میتواند replica leader چند پارتیشن را میزبانی کند و هر broker در کلاستر میتواند replica leader میزبانی کند. اما فقط یک broker در کلاستر بهعنوان controller عمل میکند. نقش controller مدیریت کلاستر را بر عهده دارد [12]. controller هم اقدامات اداری دیگری مانند reassignment پارتیشن انجام میدهد [13].
وقتی rolling upgrade کلاستر را در نظر میگیریم، خاموش و راهاندازی مجدد یک broker در هر زمان، بهتر است controller را آخر انجام دهیم [14]. وگرنه ممکن است controller چند بار restart شود.
برای فهمیدن کدام broker controller فعلی است، میتوانیم از اسکریپت zookeeper-shell برای جستجوی ID broker استفاده کنیم، همانطور که لیستینگ ۶-۳ نشان میدهد. مسیر /controller در ZooKeeper وجود دارد و در لیستینگ یک دستور برای دیدن مقدار فعلی اجرا میکنیم. اجرای آن دستور برای کلاستر من broker با ID ۰ را بهعنوان controller نشان داد.
لیستینگ ۶-۳. فهرست controller فعلی
shell
bin/zookeeper-shell.sh localhost:2181 # Connects to your
get /controller # ZooKeeper instance
# Uses get against
# the controller pathشکل ۶-۲ همهٔ خروجی ZooKeeper را نشان میدهد، از جمله مقدار brokerid، "brokerid":0. اگر این کلاستر را migrate یا upgrade کنیم، بهخاطر این نقش این broker را آخر upgrade میکنیم.
شکل ۶-۲. نمونهٔ خروجی controller
همچنین فایل controller log با نام controller.log را روی broker ۰ در این مورد پیدا میکنیم که بهعنوان log برنامه عمل میکند. این فایل log هنگام نگاه به اقدامات و شکستهای broker مهم است.
۶.۴ Leaderهای replica پارتیشن و نقش آنها
بهعنوان یادآوری سریع، topicها از پارتیشنها ساخته میشوند و پارتیشنها میتوانند replica برای تحمل خطا داشته باشند. همچنین پارتیشنها روی دیسک brokerهای Kafka نوشته میشوند. یکی از replicaهای پارتیشن وظیفهٔ leader را دارد. leader مسئول مدیریت نوشتنها از کلاینتهای producer خارجی برای آن پارتیشن است. چون فقط leader دادهٔ تازهنوشتهشده را دارد، وظیفهٔ منبع داده برای replica followerها را هم دارد [15]. و چون لیست ISR توسط leader نگهداری میشود، میداند کدام replicaها بهروز هستند و همهٔ پیامهای فعلی را دیدهاند. Replicaها مانند consumerهای replica leader عمل میکنند و پیامها را fetch میکنند [15].
شکل ۶-۳ کلاستر سهگرهای را با broker ۳ بهعنوان leader و broker ۲ و ۱ بهعنوان follower نشان میدهد، با kinaction_helloworld بهعنوان topicای که ممکن است اینطور ساخته شده باشد.
شکل ۶-۳. Leader
Broker 1 Broker 2 Broker 3 Leader for Follower Follower kinaction_helloworld Partition 2 Partition 2 Partition 2 Broker 2 fetches from leader Broker 1 fetches from leader ISR = [3, 2, 1]
Broker ۳ replica leader پارتیشن ۲ را نگه میدارد. بهعنوان leader، broker ۳ همهٔ خواندنها و نوشتنها از producer و consumerهای خارجی را مدیریت میکند. همچنین درخواستهایی که از broker ۲ و broker ۱ میگیرد را هنگام pull کردن پیامهای جدید به کپیهایشان مدیریت میکند. لیست ISR [3,2,1] leader را در موقعیت اول (۳) و سپس followerهای باقیمانده (۲,۱) که با کپی پیامهای leader بهروز میمانند شامل میشود.
در برخی موارد، brokerی که شکست خورده ممکن است replica leader پارتیشنی را میزبانی کرده باشد. در شکل ۶-۴، مثال قبلی شکل ۶-۳ شکست را تجربه میکند. چون broker ۳ در دسترس نیست، leader جدید انتخاب میشود. شکل ۶-۴ leader جدید broker ۲ را نشان میدهد. قبلاً follower بود، بهعنوان replica leader انتخاب شد تا Kafka برای آن پارتیشن سرویس و دریافت داده ادامه دهد. لیست ISR حالا [2,1] است با موقعیت اول نشاندهندهٔ replica leader جدید روی broker ۲.
شکل ۶-۴. Leader جدید انتخاب شد
Broker 3 fails and broker 2 becomes the new leader. Broker 1 reads from broker 2 Broker 1 Broker 2 Broker 3 Follower New leader for Follower Leader kinaction_helloworld Partition 2 Partition 2 Partition 2 Broker 2 fetches from leader Broker 1 fetches from leader ISR = [3, 2, 1] [2, 1]
یادداشت در فصل ۵ KIP-392 را بحث کردیم که به کلاینتهای consumer اجازه میدهد از نزدیکترین replica fetch کنند [16]. خواندن از follower ترجیحی بهجای replica leader ممکن است معنا داشته باشد اگر brokerها مراکز دادهٔ فیزیکی را در بر بگیرند. اما هنگام بحث leader و follower در این کتاب، مگر خلافش گفته شود، روی رفتار پیشفرض خواندن و نوشتن leader تمرکز میکنیم.
In-sync replicaها (ISRها) قطعهٔ کلیدی برای درک واقعی Kafka هستند. برای topic جدید، تعداد مشخصی replica ساخته و به لیست ISR اولیه اضافه میشوند [17]. این تعداد میتواند از پارامتر یا بهعنوان پیشفرض از پیکربندی broker باشد.
جزئیاتی که باید با Kafka بدانید این است که replicaها بهطور پیشفرض خودشان را ترمیم نمیکنند. اگر brokerی که یکی از کپیهای پارتیشن روی آن بود از دست برود، Kafka (فعلاً) کپی جدید نمیسازد. این را میگوییم چون برخی کاربران به filesystemهایی مانند HDFS عادت دارند که تعداد replication را (self-heal) اگر block خراب یا شکستخورده دیده شود حفظ میکنند. مورد مهمی که هنگام مانیتورینگ سلامت سیستمها باید ببینیم این است که چند ISR از تعداد مطلوب ما واقعاً مطابقت دارند.
چرا مراقبت از این عدد مهم است؟ خوب است قبل از رسیدن به ۰ بدانید چند کپی دارید! فرض کنید topicی با یک پارتیشن داریم که آن پارتیشن سهبار replicate شده. در بهترین حالت، دو کپی از دادهٔ replica leader پارتیشن اصلی را داریم. یعنی replica followerها با leader همگاماند. اما اگر ISR دیگری از دست برود چه؟
همچنین مهم است بدانید اگر replica در کپی پیامها از leader خیلی عقب بیفتد، میتواند از لیست ISR حذف شود. leader متوجه میشود اگر follower خیلی طول بکشد و آن را از لیست followerها حذف میکند [17]. سپس leader با لیست ISR جدید ادامه میدهد. نتیجهٔ این «کندی» برای لیست ISR همان شکل ۶-۴ است که broker شکست خورده.
۶.۴.۱ از دست دادن داده
اگر ISR نداشته باشیم و replica اصلی را بهخاطر شکست از دست بدهیم چه؟ وقتی unclean.leader.election.enable برابر true است، controller حتی اگر بهروز نباشد leader پارتیشن را انتخاب میکند تا سیستم به کار ادامه دهد [15]. مشکل این است که داده ممکن است از دست برود چون هیچ replicaای همهٔ داده را در زمان شکست leader ندارد.
شکل ۶-۵. Unclean leader election
Unclean leader for kinaction_helloworld. Message 3 never In sync but both fail made it to broker 1. Broker 1 Broker 2 Broker 3 Follower Follower Leader Leader Partition 2 Partition 2 Partition 2 Message 1 Message 1 Message 1 Message 2 Message 2 Message 2 Message 3 Message 3
شکل ۶-۵ از دست رفتن داده را در مورد پارتیشنی با سه replica نشان میدهد. در این مورد، هر دو broker ۳ و ۲ شکست خوردند و آنلاین نیستند. چون unclean leader election فعال بود، broker ۱ leader جدید میشود حتی اگر با brokerهای دیگر همگام نباشد. broker ۱ هرگز پیام ۳ را نمیبیند، پس نمیتواند آن داده را به کلاینتها ارائه دهد. به قیمت از دست دادن داده، این گزینه به ما اجازه میدهد به سرویسدهی به کلاینتها ادامه دهیم.
۶.۵ نگاهی به درون Kafka
ابزارهای زیادی برای capture و مشاهدهٔ داده از برنامههایمان داریم. Grafana® (https://grafana.com/) و Prometheus® (https://prometheus.io/) را بهعنوان مثال ابزارهایی میبینیم که برای راهاندازی stack مانیتورینگ ساده برای Confluent Cloud [18]¹ میتوانند استفاده شوند. از Prometheus برای استخراج و ذخیرهٔ دادهٔ metrics Kafka استفاده میکنیم. سپس آن داده را به Grafana میفرستیم تا نماهای گرافیکی مفید تولید کند. برای درک کامل چرا همهٔ این ابزارها را راهاندازی میکنیم، اجزا و کار هر کدام را سریع مرور کنیم (شکل ۶-۶).
شکل ۶-۶. جریان گراف
Info from topics like kinaction_alert Kafka brokers dashboard JMX exporter UI charts 1 Scrapes Data source Prometheus data store JMX exporter 2
در شکل ۶-۶ از JMX برای نگاه به درون برنامههای Kafka استفاده میکنیم. Kafka exporter اعلانهای JMX را export و به قالب Prometheus تبدیل میکند. Prometheus دادهٔ exporter را scrape و دادهٔ metrics را ذخیره میکند. ابزارهای مختلف میتوانند اطلاعات Prometheus را بگیرند و در داشبورد بصری نمایش دهند.
Docker™ imageها و فایلهای Docker Compose زیادی همهٔ این ابزارها را bundle میکنند، یا میتوانید هر ابزار را روی ماشین محلی نصب کنید تا این فرایند را عمیقتر کاوش کنید.
برای Kafka exporter، گزینهٔ عالی در https://github.com/danielqsj/kafka_exporter وجود دارد. سادگی این ابزار را ترجیح میدهیم چون فقط اجرا میکنیم و یک یا لیستی از سرورهای Kafka را برای watch دادن میدهیم. شاید برای use caseهای شما هم خوب کار کند. توجه کنید metrics زیاد مخصوص کلاینت و broker میگیریم چون گزینههای زیادی برای مانیتور هست. با این حال، این لیست کامل metrics در دسترس ما نیست.
شکل ۶-۷ query علیه data store محلی، مانند نمونهٔ محلی Prometheus که metrics را از ابزار Kafka exporter جمع میکند را نشان میدهد. همانطور که دربارهٔ پارتیشنها گفتیم، replicaهای Kafka خودشان را خودکار ترمیم نمیکنند، پس یکی از چیزهایی که میخواهیم مانیتور کنیم پارتیشنهای under-replicated است. اگر این عدد بیشتر از ۰ باشد، شاید بخواهیم ببینیم در کلاستر چه میگذرد تا علت مشکل replica را پیدا کنیم. میتوانیم دادهٔ این query را در نمودار یا داشبورد نمایش دهیم، یا بالقوه alert بفرستیم.
شکل ۶-۷. نمونهٔ query metric
Metric name: Query Data Alert kafka_topic_partition_under_replicated_partition store Results Dashboard Value: 0 kafka_topic_partition_under_replicated_partition{instance="localhost:9308",job="kafka_exporter",partition="0",topic=kinaction_helloworld)0
همانطور که گفته شد، Kafka exporter همهٔ metricهای JMX را expose نمیکند. برای metrics JMX بیشتر میتوانیم متغیر محیطی JMX_PORT هنگام شروع فرآیندهای Kafka تنظیم کنیم [19]. ابزارهای دیگری هم هستند که از Java agent برای تولید metrics به endpoint یا پورت استفاده میکنند که Prometheus میتواند scrape کند.
لیستینگ ۶-۴ نشان میدهد چگونه متغیر JMX_PORT هنگام شروع broker تنظیم میکنیم [19]. اگر broker در حال اجرا داریم و این پورت expose نشده، باید broker را restart کنیم تا تغییر اعمال شود. شاید بخواهیم تنظیم این متغیر را خودکار کنیم تا در همهٔ restartهای آینده broker فعال باشد.
لیستینگ ۶-۴. شروع broker با پورت JMX
shell
# Adds the JMX_PORT variable
JMX_PORT=$JMX_PORT bin/kafka-server-start.sh \ # when starting the cluster
➥ config/server0.properties۶.۵.۱ نگهداری کلاستر
با حرکت به production، میخواهیم بیش از یک سرور پیکربندی کنیم. نکتهٔ دیگر این است که بخشهای مختلف اکوسیستم مانند کلاینتهای Kafka و Connect، Schema Registry و REST Proxy معمولاً روی همان سرورهای broker اجرا نمیشوند. اگرچه ممکن است همهٔ اینها را روی لپتاپ برای تست اجرا کنیم (و میتوانیم این نرمافزار را روی یک سرور اجرا کنیم)، برای امنیت و کارایی، قطعاً نمیخواهیم همهٔ این فرآیندها روی یک سرور هنگام کار production باشند. برای موازی با ابزارهای اکوسیستم Hadoop، Kafka با سرورهای بیشتر بهخوبی بهصورت افقی مقیاس میگیرد. بیایید افزودن سرور به کلاستر را ببینیم.
۶.۵.۲ افزودن broker
شروع با کلاستر کوچک راه عالی است، چون همیشه میتوانیم broker اضافه کنیم تا footprint را بزرگتر کنیم. برای افزودن broker Kafka به کلاستر، فقط broker Kafka جدیدی با ID یکتا شروع میکنیم. این ID میتواند با پیکربندی broker.id یا با broker.id.generation.enable روی true ساخته شود [10]. تقریباً همین است. اما چیزی هست که باید بدانید — broker جدید به هیچ پارتیشنی اختصاص نمییابد! پارتیشنهای topicی که قبل از افزودن broker جدید ساختیم همچنان روی brokerهایی که هنگام ساخت وجود داشتند باقی میمانند [20]. اگر با اینکه broker جدید فقط topicهای جدید را مدیریت میکند مشکلی ندارید، کار دیگری لازم نیست.
۶.۵.۳ ارتقای کلاستر
مانند همهٔ نرمافزارها، بهروزرسانی و upgrade بخشی از زندگی است. همهٔ سیستمها را نمیتوان همزمان خاموش و upgrade کرد بهخاطر بار production یا تأثیر کسبوکار. یکی از تکنیکها برای اجتناب از downtime برای برنامههای Kafka، rolling restart [14] است. یعنی فقط یک broker در هر زمان upgrade شود. شکل ۶-۸ نشان میدهد هر broker یکی یکی قبل از رفتن به broker بعدی برای کلاستر upgrade میشود.
شکل ۶-۸. Rolling restart
The first broker completes Waiting for second broker and is back to complete before next Broker 0 online. Broker 1 broker upgrade. Broker 2 upgraded being old version Our 3 brokers for our upgraded Kafka in Action cluster would be online and offline at different times. Status: Online Status: Offline Status: Online
property پیکربندی broker مهمی برای rolling restart، controlled.shutdown.enable است. تنظیم این روی true انتقال leadership پارتیشن قبل از خاموش شدن broker را فعال میکند [21].
۶.۵.۴ ارتقای کلاینتها
همانطور که در فصل ۴ گفتیم، اگرچه Kafka بهترین تلاش را برای جدا کردن کلاینتها از broker میکند، دانستن نسخهٔ کلاینتها نسبت به brokerها مفید است. این ویژگی سازگاری دوطرفهٔ کلاینت در Kafka ۰.۱۰.۲ جدید بود و brokerهای نسخه ۰.۱۰.۰ یا بالاتر از آن پشتیبانی میکنند [22]. کلاینتها معمولاً پس از upgrade همهٔ brokerهای Kafka در کلاستر upgrade میشوند. اما مانند هر upgrade، به یادداشتهای نسخه نگاهی بیندازید تا مطمئن شوید نسخههای جدیدتر سازگارند.
۶.۵.۵ پشتیبانگیری
Kafka استراتژی backup مانند پایگاه داده ندارد؛ snapshot یا backup دیسک به معنای متداول نمیگیریم. چون logهای Kafka روی دیسک هستند، چرا کل دایرکتوریهای پارتیشن را کپی نکنیم؟ اگرچه چیزی مانع نیست، یک نگرانی ساخت کپی از همهٔ دایرکتوریهای داده در همهٔ مکانهاست. بهجای کپی دستی و هماهنگی بین brokerها، یکی از گزینههای ترجیحی این است که کلاستر توسط کلاستر دوم پشتیبانی شود [23]. بین دو کلاستر، رویدادها بین topicها replicate میشوند. یکی از اولین ابزارهایی که در محیط production دیدهاید MirrorMaker بود. نسخهٔ جدیدتر این ابزار (MirrorMaker 2.0) با Kafka نسخه ۲.۴.۰ منتشر شد [24]. در زیرپوشهٔ bin دایرکتوری نصب Kafka، shell script به نام kafka-mirror-maker و همچنین script جدید MirrorMaker 2.0 یعنی connect-mirror-maker را پیدا میکنیم.
گزینههای open source و enterprise دیگری هم برای mirroring داده بین کلاسترها هست. Confluent Replicator (http://mng.bz/Yw7K) و Cluster Linking (http://mng.bz/OQZo) هم گزینههایی هستند که باید بدانید [25].
۶.۶ نکتهای دربارهٔ سیستمهای stateful
Kafka برنامهای است که قطعاً با data storeهای stateful کار میکند. در این کتاب روی nodeهای خودمان کار میکنیم و با deployment ابری کار نمیکنیم. منابع عالی هست، از جمله سایت Confluent برای استفاده از Kubernetes Confluent Operator API (https://www.confluent.io/confluent-operator/) و همچنین Docker imageهای موجود برای کارهای لازم. گزینهٔ جالب دیگر Strimzi™ (https://github.com/strimzi/strimzi-kafka-operator) است اگر به اجرای کلاستر روی Kubernetes فکر میکنید. هنگام نوشتن این کتاب، Strimzi پروژهٔ sandbox بنیاد Cloud Native Computing Foundation® (https://www.cncf.io/) است. اگر با این ابزارها آشنا هستید، ممکن است راه سریعی برای آزمایش راهاندازی PoC باشد اگر پروژههای جالبی در Docker Hub پیدا کنید. اما دستور یکاندازه برای همه برای زیرساخت ما وجود ندارد.
یکی از مزایای Kubernetes که برجسته است توانایی ساخت سریع کلاسترهای جدید با گزینههای ذخیرهسازی و ارتباط سرویس مختلف است که Gwen Shapira در مقالهٔ «Recommendations for Deploying Apache Kafka on Kubernetes» بیشتر بررسی میکند [26]. برای برخی شرکتها، دادن کلاستر جدا به هر محصول ممکن است از مدیریت یک کلاستر عظیم برای کل سازمان آسانتر باشد. توانایی راهاندازی سریع کلاستر بهجای افزودن سرور فیزیکی میتواند turnaround سریعی که محصولات نیاز دارند فراهم کند.
شکل ۶-۹ طرح کلی از چگونگی راهاندازی brokerهای Kafka در Kubernetes با operator pod را نشان میدهد، مشابه نحوهٔ کار operatorهای Confluent و Strimzi. اصطلاحات در شکل مخصوص Kubernetes است و اینجا توضیح زیادی نمیدهیم چون نمیخواهیم تمرکز از یادگیری خود Kafka منحرف شود. در عوض نمای کلی میدهیم. توجه کنید این نحوهٔ میتواند کار کند، نه توصیف راهاندازی خاص.
شکل ۶-۹. Kafka روی Kubernetes
Mock Kafka in Action Kubernetes cluster Operator These 3 brokers would replace pod our local 3 instances we are using for our examples. Manages components Kafka StatefulSet ZooKeeper StatefulSet Broker 0 Broker 1 Broker 2 ZooKeeper 0 ZooKeeper 1 ZooKeeper 2 Container Container Container Container Container Container pod pod pod pod pod pod Claim Claim Claim Claim Claim Claim Persistent Persistent Persistent Persistent Persistent Persistent volume volume volume volume volume volume
Operator Kubernetes pod خودش است که داخل کلاستر Kubernetes زندگی میکند. همچنین هر broker در pod خودش بهعنوان بخشی از گروه منطقی به نام StatefulSet است. هدف StatefulSet مدیریت podهای Kafka و کمک به تضمین ترتیب و هویت برای هر pod است. اگر pod میزبان broker (فرآیند JVM) با ID ۰ شکست بخورد، مثلاً pod جدیدی با آن هویت (نه ID تصادفی) ساخته میشود و به همان persistent storage volume قبلی متصل میشود. چون این volumeها پیامهای پارتیشنهای Kafka را نگه میدارند، داده حفظ میشود. این statefulness به غلبه بر عمر گاه کوتاه containerها کمک میکند. هر node ZooKeeper هم در pod خودش و بخشی از StatefulSet خودش خواهد بود.
برای کسانی که تازهکار Kubernetes هستند یا از گذار به چنین پلتفرمی نگراناند، یکی از استراتژیهای migration که میتواند مفید باشد اجرای کلاینتها و برنامههای Kafka روی کلاستر Kubernetes قبل از brokerهای Kafka است. علاوه بر stateless بودن، اجرای کلاینتهایمان اینطور میتواند در ابتدای مسیر یادگیری حس Kubernetes بدهد. اما نباید نیاز به درک خوب Kubernetes برای اجرای Kafka روی این پلتفرم را نادیده بگیریم.
یکی از تیمهای توسعهدهندهٔ چهارنفرهای که یکی از نویسندگان اخیراً با آن کار کرد، نیمی از تیم را روی Kubernetes و نیمی روی اجرای Kafka متمرکز کرد. البته این نسبت شاید برای هر تیم نباشد. زمان توسعهدهنده لازم برای تمرکز روی Kubernetes به تیم و تجربهٔ کلی شما بستگی دارد.
۶.۷ تمرین
چون اعمال برخی یادگیریهای جدید بهصورت hands-on سخت است و این فصل بیشتر روی دستورات است تا کد، شاید تمرین سریعی برای کاوش روش دیگری برای کشف metric پارتیشنهای under-replicated بهجای exporterی که قبلاً دیدیم مفید باشد. علاوه بر استفاده از داشبورد برای دیدن این داده، چه گزینههای خط فرمان میتوانیم برای کشف این اطلاعات استفاده کنیم؟
فرض کنید میخواهیم سلامت یکی از topicهایمان به نام kinaction_replica_test را تأیید کنیم. این topic را با سه replica برای هر پارتیشن ساختیم. میخواهیم مطمئن شویم سه broker در لیست ISR هست تا در صورت شکست broker آماده باشیم. چه دستوری باید اجرا کنیم تا آن topic را ببینیم و وضعیت فعلیاش را بدانیم؟ لیستینگ ۶-۵ مثالی از describe آن topic [27] است. توجه کنید ReplicationFactor برابر ۳ است و لیست Replicas هم سه ID broker نشان میدهد. اما لیست ISR فقط دو مقدار نشان میدهد در حالی که باید سه تا باشد!
لیستینگ ۶-۵. Describe topic replica: تست تعداد ISR
shell
# Note the topic parameter
# and the describe flag in use.
$ bin/kafka-topics.sh --describe --bootstrap-server localhost:9094 \
--topic kinaction_replica_test
Topic:kinaction_replica_test PartitionCount:1 ReplicationFactor:3 Configs:
Topic: kinaction_replica_test Partition: 0
Leader: 0 Replicas: 1,0,2 Isr: 0,2 # Topic-specific information about leader,
# partition, and replicasاگرچه میتوانیم مشکل پارتیشنهای under-replicated را با نگاه به جزئیات خروجی دستور متوجه شویم، میتوانستیم از پرچم --under-replicated-partitions هم برای دیدن سریع مشکلات استفاده کنیم [27]. لیستینگ ۶-۶ نحوهٔ استفاده از این پرچم را نشان میدهد که سریع دادهٔ ISR سختدیده را فیلتر میکند و فقط پارتیشنهای under-replicated را به ترمینال خروجی میدهد.
لیستینگ ۶-۶. استفاده از پرچم under-replicated-partitions
shell
bin/kafka-topics.sh --describe --bootstrap-server localhost:9094 \
--under-replicated-partitions # Note the under-replicated-
# partition flag in use.
Topic: kinaction_replica_test Partition: 0
➥ Leader: 0 Replicas: 1,0,2 Isr: 0,2 # The ISR only lists
# two brokers!لیستینگ ۶-۶ نشان میدهد وقتی از پرچم --describe استفاده میکنیم، لازم نیست بررسی پارتیشنهای under-replicated را به topic مشخص محدود کنیم. میتوانیم این دستور را برای نمایش مشکلات در همهٔ topicها و یافتن سریع مشکلات در کلاستر اجرا کنیم. ابزارهای out-of-the-box بیشتری که با Kafka همراه است را هنگام بحث ابزارهای مدیریت در فصل ۹ کاوش میکنیم.
نکته هنگام استفاده از هر یک از دستورات این فصل، همیشه ایدهٔ خوبی است دستور را بدون پارامتر اجرا کنید و گزینههای دستور موجود را برای troubleshooting بخوانید.
با بررسی بیشتر Kafka در این فصل، فهمیدیم سیستم پیچیدهای اجرا میکنیم. اما ابزارهای خط فرمان و metrics مختلف برای مانیتورینگ سلامت کلاستر داریم. در فصل بعد با دستورات برای تکمیل وظایف مشخص این سیستم پویا در طول عمرش ادامه میدهیم.
خلاصه
- Brokerها مرکز Kafka هستند و منطقی را فراهم میکنند که کلاینتهای خارجی با برنامههای ما تعامل دارند. کلاسترها نه فقط مقیاس بلکه قابلیت اطمینان هم میدهند.
- میتوانیم از ZooKeeper برای توافق در کلاستر توزیعشده استفاده کنیم. یک مثال انتخاب controller جدید بین brokerهای در دسترس است.
- برای مدیریت کلاستر میتوانیم پیکربندیها را در سطح broker تنظیم کنیم که کلاینتهای ما برای گزینههای مشخص میتوانند override کنند.
- Replicaها اجازه میدهند تعداد کپی داده در کلاستر پخش شود. این در صورت شکست broker که قابل دسترسی نیست کمک میکند.
- In-sync replicaها (ISRها) با دادهٔ leader بهروز هستند و میتوانند leadership پارتیشن را بدون از دست رفتن داده بر عهده بگیرند.
- میتوانیم از metrics برای تولید نمودارهای بصری مانیتورینگ کلاستر یا alert روی مشکلات بالقوه استفاده کنیم.
منابع
- "Post Kafka Deployment." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/kafka/post-deployment.html#balancing-replicas-across-racks (accessed September 15, 2019).
- "KIP-500: Replace ZooKeeper with a Self-Managed Metadata Quorum." Wiki for Apache Kafka. Apache Software Foundation (July 09, 2020). https://cwiki.apache.org/confluence/display/KAFKA/KIP-500%3A+Replace+ZooKeeper+with+a+Self-Managed+Metadata+Quorum (accessed August 22, 2020).
- F. Junqueira and N. Narkhede. "Distributed Consensus Reloaded: Apache ZooKeeper and Replication in Apache Kafka." Confluent blog (August 27, 2015). https://www.confluent.io/blog/distributed-consensus-reloaded-apache-zookeeper-and-replication-in-kafka/ (accessed September 15, 2019).
- "Kafka data structures in Zookeeper [sic]." Wiki for Apache Kafka. Apache Software Foundation (February 10, 2017). https://cwiki.apache.org/confluence/display/KAFKA/Kafka+data+structures+in+Zookeeper (accessed January 19, 2020).
- C. McCabe. "Apache Kafka Needs No Keeper: Removing the Apache ZooKeeper Dependency." Confluent blog. (May 15, 2020). https://www.confluent.io/blog/upgrading-apache-kafka-clients-just-got-easier (accessed August 20, 2021).
- Apache Kafka Binder (n.d.). https://docs.spring.io/spring-cloud-stream-binder-kafka/docs/3.1.3/reference/html/spring-cloud-stream-binder-kafka.html#_apache_kafka_binder (accessed July 18, 2021).
- "CLI Tools for Confluent Platform." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/installation/cli-reference.html (accessed August 25, 2021).
- "ZkData.scala." Apache Kafka GitHub. https://github.com/apache/kafka/blob/99b9b3e84f4e98c3f07714e1de6a139a004cbc5b/core/src/main/scala/kafka/zk/ZkData.scala (accessed August 27, 2021).
- "A Guide To The Kafka Protocol." Wiki for Apache Kafka. Apache Software Foundation (June 14, 2017). https://cwiki.apache.org/confluence/display/KAFKA/A+Guide+To+The+Kafka+Protocol (accessed September 15, 2019).
- "Kafka Broker Configurations." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/installation/configuration/broker-configs.html (accessed August 21, 2021).
- "Logging." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/kafka/post-deployment.html#logging (accessed August 21, 2021).
- "Controller." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/kafka/post-deployment.html#controller (accessed August 21, 2021).
- "Kafka Controller Internals." Wiki for Apache Kafka. Apache Software Foundation (January 26, 2014). https://cwiki.apache.org/confluence/display/KAFKA/Kafka+Controller+Internals (accessed September 15, 2019).
- "Post Kafka Deployment." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/kafka/post-deployment.html#rolling-restart (accessed July 10, 2019).
- "Replication." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/kafka/design.html#replication (accessed August 21, 2021).
- "KIP-392: Allow consumers to fetch from closest replica." Wiki for Apache Kafka. Apache Software Foundation (November 5, 2019). https://cwiki.apache.org/confluence/display/KAFKA/KIP-392%3A+Allow+consumers+to+fetch+from+closest+replica (accessed December 10, 2019).
- N. Narkhede. "Hands-free Kafka Replication: A lesson in operational simplicity." Confluent blog (July 1, 2015). https://www.confluent.io/blog/hands-free-kafka-replication-a-lesson-in-operational-simplicity/ (accessed October 02, 2019).
- "Observability Overview and Setup." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/tutorials/examples/ccloud-observability/docs/observability-overview.html (accessed August 26, 2021).
- "Kafka Monitoring and Metrics Using JMX". Confluent documentation. (n.d.). https://docs.confluent.io/platform/current/installation/docker/operations/monitoring.html (accessed June 12, 2020).
- "Scaling the Cluster (Adding a node to a Kafka cluster)." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/kafka/post-deployment.html#scaling-the-cluster-adding-a-node-to-a-ak-cluster (accessed August 21, 2021).
- "Graceful shutdown." Apache Software Foundation (n.d.). https://kafka.apache.org/documentation/#basic_ops_restarting (accessed May 11, 2018).
- C. McCabe. "Upgrading Apache Kafka Clients Just Got Easier." Confluent blog. (July 18, 2017). https://www.confluent.io/blog/upgrading-apache-kafka-clients-just-got-easier (accessed October 02, 2019).
- "Backup and Restoration." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/kafka/post-deployment.html#backup-and-restoration (accessed August 21, 2021).
- Release Notes, Kafka Version 2.4.0. Apache Software Foundation (n.d.). https://archive.apache.org/dist/kafka/2.4.0/RELEASE_NOTES.html (accessed May 12, 2020).
- "Multi-DC Solutions." Confluent documentation (n.d.). https://docs.confluent.io/platform/current/multi-dc-deployments/index.html#multi-dc-solutions (accessed August 21, 2021).
- G. Shapira. "Recommendations_for_Deploying_Apache_Kafka_on_Kubernetes." White paper (2018). https://www.confluent.io/resources/recommendations-for-deploying-apache-kafka-on-kubernetes (accessed December 15, 2019).
- "Replication tools." Wiki for Apache Kafka. Apache Software Foundation (February 4, 2019). https://cwiki.apache.org/confluence/display/kafka/replication+tools (accessed January 19, 2019).
¹ The Grafana Labs Marks are trademarks of Grafana Labs, and are used with Grafana Labs' permission. We are not affiliated with, endorsed or sponsored by Grafana Labs or its affiliates.