حالت تاریک
فصل ۸ — ذخیرهسازی Kafka
این فصل شامل:
- چه مدت داده را نگه داریم
- جابهجایی داده به داخل و خارج از Kafka
- معماریهای دادهای که Kafka فعال میکند
- ذخیرهسازی برای instanceهای cloud و container
در فصلهای قبل با نحوهٔ ورود و ساختار داده در Kafka آشنا شدیم. این فصل بر تصمیمهای بلندمدتتر تمرکز دارد: چه مدت داده را نگه داریم، چگونه آن را به سیستمهای دیگر منتقل کنیم و چه معماریهایی این قابلیتها را فعال میکنند.
تا اینجا داده را عمدتاً بهصورت گذر از Kafka در نظر گرفتهایم — یعنی رویدادها وارد میشوند، مصرف میشوند و پس از مدتی retention حذف میشوند. تصمیم دیگری که باید در نظر بگیریم این است که دادهٔ بلندمدت کجا بماند. وقتی از پایگاههای دادهای مانند MySQL یا MongoDB® استفاده میکنید، شاید همیشه به انقضای داده فکر نکنید؛ میدانید داده (احتمالاً) برای بیشتر عمر کل برنامهٔ شما باقی میماند. در مقایسه، ذخیرهسازی Kafka از نظر منطقی جایی بین راهحلهای ذخیرهٔ بلندمدت یک پایگاه داده و ذخیرهٔ گذرای یک message broker قرار میگیرد — بهویژه اگر message broker را بهعنوان نگهداشتن پیام تا زمانی که توسط یک کلاینت مصرف شود در نظر بگیریم، همانطور که در message brokerهای دیگر رایج است. این موقعیت منحصربهفرد Kafka هم فرصت و هم چالش ایجاد میکند: میتوانید داده را هم برای پردازش real-time و هم برای نگهداری طولانیتر بهکار ببرید، اما باید صریحاً تصمیم بگیرید چه مدت و کجا آن را نگه دارید. بیایید چند گزینه برای ذخیره و جابهجایی داده در محیط Kafka خودمان ببینیم.
۸.۱ چه مدت داده را نگه داریم
فعلاً limit پیشفرض retention برای داده در topicهای Kafka هفت روز است، اما میتوانیم بهراحتی آن را با زمان یا اندازهٔ داده پیکربندی کنیم [1]. این مقدار پیشفرض برای بسیاری از use caseهای streaming کافی است، اما برای هر پروژه باید بپرسید: «دادهٔ من چه مدت برای کسبوکار ارزش دارد؟»
اما آیا Kafka میتواند خودش داده را برای مدتی در حد سالها نگه دارد؟ یک مثال دنیای واقعی نحوهٔ استفادهٔ New York Times از Kafka است. محتوای cluster آنها در یک پارتیشن واحد بود که در زمان نگارش کمتر از ۱۰۰ GB بود [2]. اگر از بحث فصل ۷ دربارهٔ پارتیشنها بهخاطر بیاورید، میدانید همهٔ این داده روی یک drive broker (و همچنین هر کپی replica روی driveهای خودش) وجود دارد، چون پارتیشنها بین brokerها split نمیشوند.
از آنجا که storage نسبتاً ارزان در نظر گرفته میشود و ظرفیت driveهای مدرن بسیار فراتر از صدها گیگابایت است، بیشتر شرکتها مشکل اندازه برای نگهداشتن آن داده نخواهند داشت. آیا این استفادهٔ معتبر از Kafka است یا سوءاستفاده از هدف و طراحی مورد نظر آن؟ تا زمانی که فضای رشد برنامهریزیشدهٔ آینده را روی دیسک برای استفادهٔ بعدی دارید، شاید الگوی خوبی برای مدیریت workload خاص خود پیدا کرده باشید.
retention را برای brokerها چگونه پیکربندی کنیم؟ ملاحظات اصلی اندازهٔ logها و مدت زمانی است که داده وجود دارد. میتوانید retention را در سطح broker (برای همهٔ topicها) یا در سطح topic (برای topicهای خاص) تنظیم کنید — topic-level override معمولاً برای topicهایی با نیازمندیهای متفاوت مفید است.
جدول ۸.۱ برخی از گزینههای پیکربندی broker را که برای retention مفیدند نشان میدهد [3].
جدول ۸.۱ — پیکربندی retention در broker
| کلید | هدف |
|---|---|
log.retention.bytes | بزرگترین آستانهٔ اندازه به byte برای حذف یک log |
log.retention.ms | مدت نگهداری log به millisecond قبل از حذف |
log.retention.minutes | مدت قبل از حذف به دقیقه. اگر هر دو تنظیم شوند، log.retention.ms هم استفاده میشود |
log.retention.hours | مدت قبل از حذف به ساعت. اگر log.retention.ms یا log.retention.minutes تنظیم شده باشند، قبل از این مقدار استفاده میشوند |
چگونه limitهای retention log را غیرفعال کنیم و اجازه دهیم داده برای همیشه بماند؟ با تنظیم هر دو log.retention.bytes و log.retention.ms روی -1، میتوانیم حذف داده را عملاً خاموش کنیم [4]. توجه داشته باشید که غیرفعال کردن retention به معنای نامحدود بودن فضای دیسک نیست — همچنان باید ظرفیت فیزیکی را monitor کنید.
نکتهٔ دیگری که باید در نظر بگیریم این است که چگونه میتوانیم retention مشابهی برای latest valueها با استفاده از رویدادهای keyed در یک topic فشردهشونده داشته باشیم (فصل ۷ را ببینید). اگرچه هنوز میتوانیم در طول compaction cleaning داده حذف کنیم، جدیدترین پیامهای keyed همیشه در log خواهند بود. این راه خوبی برای نگهداشتن داده در use caseهایی است که به هر رویداد (یا history نحوهٔ تغییر state یک key از مقدار فعلی) نیاز نداریم — مثلاً آخرین وضعیت حساب کاربری یا آخرین قیمت یک محصول.
اگر میخواهیم داده مدتی بماند، اما فضای دیسک کافی برای نگهداشتن داده روی brokerها نداریم چه؟ گزینهٔ دیگر برای ذخیرهٔ بلندمدت انتقال داده به خارج از Kafka و نگه نداشتن آن درون خود brokerهای Kafka است. قبل از اینکه داده توسط retention از Kafka حذف شود، میتوانیم آن را در یک پایگاه داده، در Hadoop Distributed File System (HDFS™) ذخیره کنیم، یا پیامهای رویداد را در چیزی مانند cloud storage آپلود کنیم. همهٔ این مسیرها گزینههای معتبری هستند و میتوانند راههای مقرونبهصرفهتری برای نگهداشتن داده پس از پردازش توسط consumerهای ما فراهم کنند. نکتهٔ کلیدی این است که این انتقال را قبل از حذف retention برنامهریزی کنید — ابزارهایی مانند Secor (بخش ۸.۳.۳) یا Kafka Connect sinkها میتوانند این کار را بهصورت خودکار انجام دهند.
۸.۲ جابهجایی داده
تقریباً همهٔ شرکتها به نظر میرسد نیاز به transform کردن دادهای که دریافت میکنند دارند. گاهی این موضوع مخصوص بخشی از شرکت است یا به دلیل integrationهای شخص ثالث. اصطلاح رایجی که بسیاری در فضای transform داده استفاده میکنند ETL (extract, transform, load) است.
میتوانیم از tooling یا code استفاده کنیم تا داده را در فرمت اصلی بگیریم، آن را transform کنیم و سپس در جدول یا data store دیگری قرار دهیم. Kafka میتواند نقش کلیدی در این pipelineهای داده داشته باشد — هم بهعنوان منبع دادهٔ خام و هم بهعنوان واسطهٔ بین مراحل مختلف transform.
۸.۲.۱ نگهداشتن رویداد اصلی
یک نکتهای که میخواهیم یادآوری کنیم ترجیح ما برای فرمت رویدادها داخل Kafka است. اگرچه قابل بحث و وابسته به نیازمندیهای use case شماست، ترجیح ما این است که پیامها را در فرمت اصلی در یک topic ذخیره کنیم.
این رویکرد با اصل «single source of truth» همراستا است: یک نسخهٔ خام از هر رویداد در Kafka وجود دارد و هر transform میتواند از همان منبع انجام شود.
چرا پیام اصلی را نگه داریم و فوراً قبل از قرار دادن در topic format نکنیم؟ داشتن پیام اصلی برگشت و شروع دوباره را آسانتر میکند اگر منطق transform را اشتباه کرده باشید. بهجای تلاش برای فهمیدن نحوهٔ اصلاح اشتباه روی دادهٔ تغییریافته، همیشه میتوانید به دادهٔ اصلی برگردید و دوباره شروع کنید. میدانیم که بیشتر ما معمولاً هنگام format کردن تاریخ یا اولین بار اجرای یک regular expression این تجربه را داریم. گاهی برای format کردن داده به شکلی که میخواهید به چند تلاش نیاز دارید.
مزیت دیگر گرفتن کل پیام اصلی این است که دادهای که امروز استفاده نمیکنید ممکن است در آینده استفاده شود. فرض کنید سال ۱۹۹۵ است و فیلدی از یک vendor به نام mobile دریافت میکنید. کسبوکار شما هرگز به آن فیلد نیاز نخواهد داشت، درست است؟ وقتی نیاز به راهاندازی اولین کمپین text marketing خود را ببینید، از خود گذشتهتان که آن دادهٔ اصلی و «بیفایده» را نگه داشتهاید تشکر خواهید کرد.
اگرچه فیلد mobile برای برخی مثال پیشپاافتادهای است، جالب است دربارهٔ استفاده برای تحلیل داده فکر کنیم. اگر مدلهای شما شروع به دیدن روند روی دادهای کنند که قبلاً فکر میکردید مهم نیست چه؟
با نگهداشتن همهٔ فیلدهای داده، ممکن است بتوانید به آن داده برگردید و insightهایی پیدا کنید که هرگز انتظارشان را نداشتید. این همان دلیلی است که schema evolution و نگهداشتن payload کامل در topic اهمیت دارد.
۸.۲.۲ دور شدن از ذهنیت batch
آیا موضوع کلی ETL یا pipelineهای داده اصطلاحاتی مانند batch، end of day، monthly یا حتی yearly را به ذهن میآورد؟ یکی از تغییرات نسبت به فرایندهای transform دادهٔ گذشته ایدهٔ این است که میتوانید بهطور مداوم داده را بدون تأخیر به سیستمهای مختلف stream کنید. با Kafka، مثلاً، میتوانید pipeline را در نزدیکی real-time اجرا نگه دارید و از platform stream-processing آن برای دیدن داده بهعنوان سری بینهایتی از رویدادها استفاده کنید.
این را بهعنوان یادآوری میگوییم که Kafka میتواند به تغییر نحوهٔ فکر شما به داده بهطور کلی کمک کند. لازم نیست منتظر اجرای job شبانه برای بهروزرسانی پایگاه داده باشید. همچنین لازم نیست منتظر پنجرهٔ شبانه با ترافیک کمتر برای انجام taskهای ETL سنگین باشید؛ میتوانید این کارها را همانطور که داده به سیستم stream میشود انجام دهید و pipelineهایی داشته باشید که بهطور مداوم برای برنامههای شما در real-time کار میکنند. این تغییر ذهنی از «پردازش دستهای در پایان روز» به «پردازش مداوم رویداد به رویداد» یکی از بزرگترین مزایای معماری event-driven است و Kafka ابزار اصلی برای تحقق آن محسوب میشود. بیایید ابزارهایی را ببینیم که ممکن است در آینده به استفاده از pipelineهای شما کمک کنند یا امروز از pipelineهایتان بهتر استفاده کنید.
۸.۳ ابزارها
جابهجایی داده کلید بسیاری از سیستمهاست، از جمله Kafka. اگرچه میتوانید در محدودهٔ پیشنهادهای open source Kafka و Confluent مانند Connect که در فصل ۳ بحث شد بمانید، ابزارهای دیگری هم هستند که ممکن است با infrastructure شما جور باشند یا از قبل در مجموعهٔ ابزار شما موجود باشند.
Kafka Connect (فصل ۳) پایهٔ خوبی برای بسیاری از سناریوهای ingest و egress است — connectorهای source داده را از سیستمهای خارجی به topicها میآورند و connectorهای sink داده را به مقصد خارجی میفرستند. ابزارهای این بخش مکمل یا جایگزین Connect در برخی محیطها هستند.
بسته به source یا sink دادهٔ خاص شما، گزینههای ذکرشده در بخشهای بعدی ممکن است به رسیدن به اهدافتان کمک کنند. توجه کنید که اگرچه برخی ابزارها در این بخش پیکربندی و دستور نمونه دارند، ممکن است setup بیشتری (که نشان داده نشده) قبل از اجرای این دستورها روی ماشینهای local لازم باشد. امیدواریم این بخش اطلاعات کافی برای جلب علاقه و شروع کاوش خودتان بدهد.
۸.۳.۱ Apache Flume
اگر نخستینبار از طریق کار در فضای big data با Kafka آشنا شدهاید، احتمال قوی دارد Flume را در ارتباط با cluster خود استفاده کرده باشید. اگر اصطلاح Flafka را شنیدهاید، قطعاً از این integration Kafka و Flume استفاده کردهاید. Flume میتواند مسیر آسانتری برای ورود داده به cluster فراهم کند و بیشتر به configuration وابسته است تا custom code. مثلاً اگر میخواهید داده را به Hadoop cluster خود ingest کنید و از قبل پشتیبانی vendor روی این اجزای مختلف دارید، Flume گزینهٔ محکمی برای ورود داده به Kafka cluster شماست.
شکل ۸.۱ مثالی از نحوهٔ اجرای agent Flume روی یک node بهعنوان process جداگانهٔ خودش را نشان میدهد. فایلهای local همان سرور را watch میکند و سپس از configuration agentی که ارائه دادهاید برای ارسال داده به sink استفاده میکند.
شکل ۸.۱. agent Flume
Topic: kinaction_flumetopic partition Kafka cluster Flume agent log line 1 Source: Memory channel log line 2 /var/log/kafkainactionlogs log line 3 . . . Sink destination Log server
بیایید دوباره به integration فایلهای log (source دادهٔ ما) با استفاده از agent Flume به یک Kafka topic (sink دادهٔ ما) نگاه کنیم. لیستینگ ۸.۱ فایل پیکربندی نمونهای را نشان میدهد که میتوانیم برای راهاندازی agent Flume محلی برای watch کردن یک دایرکتوری استفاده کنیم [5]. تغییرات در topic Kafka با عنوان kinaction_flumetopic قرار میگیرند. برای تصور این مثال، مقایسهای ارائه میدهیم: شبیه استفاده از دستور cat روی فایلی در یک دایرکتوری برای خواندن فایل و ارسال نتیجه به یک Kafka topic مشخص.
لیستینگ ۸.۱ — پیکربندی Flume برای watch کردن دایرکتوری
properties
ag.sources = logdir
# نامهای سفارشی برای source،
ag.sinks = kafkasink # sink و channel تعریف میکند
ag.channels = c1
# spooldir source مشخص به
#Configure the source directory to watch # Flume میگوید کدام دایرکتوری
ag.sources.logdir.type = spooldir # را برای log entryها watch کند
ag.sources.logdir.spoolDir = /var/log/kafkainactionlogs
...
ag.sinks.kafkasink.channel = c1
# این بخش topic و اطلاعات
ag.sinks.kafkasink.type = org.apache.flume.sink.kafka.KafkaSink # Kafka cluster را تعریف میکند
ag.sinks.kafkasink.kafka.topic = kinaction_flumetopic # جایی که میخواهیم داده
... # به آن برسد
# Bind both the sink and source to the same channel #
ag.sources.logdir.channels = c1
# source را با channel تعریفشده
ag.sinks.kafkasink.channel = c1 # به sink وصل میکندلیستینگ ۸.۱ نشان میدهد چگونه میتوانیم agent Flume در حال اجرا روی یک سرور را پیکربندی کنیم. باید متوجه شوید که پیکربندی sink شبیه propertyهایی است که قبلاً در کد Java producer client استفاده کردهایم. همانطور که در فصل ۴ دیدیم، propertyهایی مانند bootstrap.servers، acks و نام topic در پیکربندی Flume هم ظاهر میشوند — فقط اینبار در فایل configuration بهجای کد Java.
جالب است بدانید Flume میتواند Kafka را نه فقط بهعنوان source یا sink، بلکه بهعنوان channel هم استفاده کند. چون Kafka بهعنوان channel قابلاعتمادتر برای رویدادها دیده میشود، Flume میتواند از Kafka برای تحویل پیام بین sourceها و sinkهای مختلف استفاده کند. در deploymentهای بزرگ، استفاده از Kafka بهعنوان channel بهجای memory channel محلی پایداری بیشتری در برابر crash agent Flume فراهم میکند.
اگر پیکربندیهای Flume را بررسی میکنید و Kafka را میبینید، حتماً توجه کنید کجا و چگونه واقعاً استفاده شده است. لیستینگ بعدی پیکربندی agent Flume را نشان میدهد که میتوانیم برای فراهم کردن channel قابلاعتماد بین sourceها و sinkهایی که Flume پشتیبانی میکند استفاده کنیم [5].
لیستینگ ۸.۲ — پیکربندی channel Kafka در Flume
properties
# Flume از کلاس KafkaChannel
ag.channels.channel1.type = # بهعنوان نوع channel Kafka استفاده میکند
➥ org.apache.flume.channel.kafka.KafkaChannel
ag.channels.channel1.kafka.bootstrap.servers = # سرورهای اتصال ما
➥ localhost:9092,localhost:9093,localhost:9094
ag.channels.channel1.kafka.topic = kinaction_channel1_ch
# topicی که داده را
ag.channels.channel1.kafka.consumer.group.id = # بین source و sink نگه میدارد
➥ kinaction_flume # consumer group برای جلوگیری از
# تداخل با consumerهای دیگر۸.۳.۲ Red Hat® Debezium™
Debezium (https://debezium.io) خود را platform توزیعشدهای معرفی میکند که به تبدیل پایگاههای داده به event stream کمک میکند. بهعبارت دیگر، بهروزرسانیهای پایگاه دادهٔ ما میتوانند بهعنوان رویداد دیده شوند!
اگر پیشینهٔ پایگاه داده دارید (یا ندارید)، شاید اصطلاح change data capture (CDC) را شنیده باشید. همانطور که نامشان میگوید، تغییرات داده میتوانند track شوند و برای واکنش به آن تغییرات استفاده شوند. در زمان نگارش این فصل، Debezium از MySQL، MongoDB، PostgreSQL®، Microsoft SQL Server™، Oracle و IBM Db2 پشتیبانی میکند. Cassandra™ و Vitess™ هم در وضعیت incubating هستند [6]. لطفاً فهرست فعلی connectorها را در https://debezium.io/documentation/reference/connectors/ ببینید.
Debezium از connectorها و Kafka Connect برای ثبت رویدادهایی که برنامهٔ ما از Kafka بهعنوان یک کلاینت عادی مصرف میکند استفاده میکند. بهجای اینکه هر سرویس جداگانه پایگاه داده را poll کند، همهٔ تغییرات از یک جریان رویداد واحد در Kafka خوانده میشوند. شکل ۸.۲ مثالی از Debezium را نشان میدهد وقتی بهعنوان connector در ارتباط با Kafka Connect ثبت شده است.
شکل ۸.۲. Kafka Connect و Debezium با پایگاه داده MySQL
Kafka Connect process Kafka cluster Delete event Debezium MySQL {delete event} bin log Insert event {insert event} MySQL : Delete from users where users = 1,000 Client CLI
در سناریوی ما، یک developer از رابط خط فرمان (CLI) یک کاربر را از instance MySQL که برای تغییرات monitor میشود حذف میکند. Debezium رویداد نوشتهشده در log داخلی پایگاه داده را capture میکند و آن رویداد از طریق سرویس connector به Kafka میرود. اگر رویداد دومی، مانند insert کاربر جدید، در پایگاه داده insert شود، رویداد جدیدی capture میشود.
هر تغییر در پایگاه داده — چه INSERT، چه UPDATE و چه DELETE — میتواند بهصورت رویداد Kafka در دسترس قرار گیرد و consumerهای شما بدون polling مستقیم پایگاه داده بهروز بمانند. این الگو برای سناریوهایی که چندین سرویس باید از تغییرات یک پایگاه دادهٔ مشترک مطلع شوند بسیار ارزشمند است.
بهعنوان یادداشت اضافه، اگرچه مخصوص Kafka نیست، مثالهای دیگری از استفاده از تکنیکهایی مانند CDC برای ارائهٔ رویدادها یا تغییرات بهموقع در داده وجود دارد که ممکن است به درک هدف کلی Debezium کمک کند. ایدهٔ مشترک این است که بهجای کشیدن دورهای (polling) پایگاه داده برای یافتن تغییرات، تغییرات خودشان بهصورت stream به سیستمهای downstream اعلام میشوند.
۸.۳.۳ Secor
Secor (https://github.com/pinterest/secor) پروژهٔ جالبی از Pinterest است که از ۲۰۱۴ وجود دارد. هدف آن کمک به persist کردن دادهٔ log Kafka در گزینههای مختلف storage، از جمله S3 و Google Cloud Storage™ است [7].
گزینههای خروجی هم متنوعاند، از جمله sequence، Apache ORC™، Apache Parquet™ و فرمتهای دیگر. فرمت Parquet بهویژه برای queryهای تحلیلی بهینه است چون ستونمحور و فشرده است.
همانطور که همیشه، یکی از مزایای بزرگ داشتن source code پروژهها در repository عمومی این است که میتوانیم ببینیم تیمهای دیگر چگونه نیازمندیهایی مشابه نیازمندیهای ما را پیادهسازی کردهاند.
شکل ۸.۳ نشان میدهد Secor چگونه بهعنوان consumer یک Kafka cluster عمل میکند، درست مانند هر برنامهٔ دیگر. اضافه کردن consumer به cluster برای backup داده موضوع بزرگی نیست. از روشی که Kafka همیشه چند reader رویداد را مدیریت میکند بهره میبرد.
شکل ۸.۳. Secor بهعنوان consumer و قرار دادن داده در storage
Secor acts as another consumer of your cluster. kinaction_alerttrend is one topic to consider moving data to for longer-term keeping. Kafka cluster Secor Java process S3 Events Broker Broker Broker Application 1 Producer clients 1 2 3 consumer Application 2 consumer
Secor بهعنوان process Java اجرا میشود و میتواند پیکربندیهای خاص ما را دریافت کند. در عمل، بهعنوان consumer دیگری از topic(های) موجود ما عمل میکند تا داده را جمع کند و در مقصد مشخصی مانند S3 bucket به پایان برسد. Secor در راه consumerهای دیگر ما قرار نمیگیرد و به ما اجازه میدهد کپی رویدادهایمان را داشته باشیم تا وقتی retention Kafka داده را از logهایش حذف میکند، از دست نروند.
فراخوانی Secor برای کسانی که با JARها در محیط Java کار کردهاند آشناست. میتوانیم آرگومانها را با پارامترهای استاندارد -D به برنامهٔ Secor بدهیم. در این مورد، مهمترین فایل برای بهروزرسانی فایل properties با گزینههای پیکربندی است. این فایل به ما اجازه میدهد جزئیات bucket cloud storage مشخص، برای مثال، را پر کنیم. فرمتهای خروجی مانند Parquet برای تحلیل داده در ابزارهایی مانند Apache Spark™ یا Amazon Athena™ بهینهاند.
۸.۳.۴ مثال use case برای ذخیرهٔ داده
بیایید مثالی ببینیم که چگونه انتقال داده از Kafka برای ذخیره میتواند بعداً استفاده شود. ابتدا برای روشنسازی، استفادهٔ خود از همان داده را بین دو حوزهٔ مختلف تقسیم میکنیم. یک حوزه کار با داده بهصورت عملیاتی (operational) همانطور که به Kafka میآید است.
این تفکیک در طراحی pipelineهای داده رایج است: دادهٔ عملیاتی برای پاسخ سریع به رویدادها نگه داشته میشود و دادهٔ تحلیلی برای بینشهای بلندمدت archive میشود. Kafka میتواند هر دو نقش را در مراحل مختلف عمر داده بازی کند.
دادهٔ عملیاتی رویدادهایی است که توسط عملیات روزمرهٔ ما تولید میشوند. میتوانیم رویداد سفارش یک قلم از وبسایت را مثال بزنیم. رویداد خرید برنامهٔ ما را به حرکت درمیآورد و این کار را با latency پایین انجام میدهد. ارزش این داده برای برنامههای real-time ما ممکن است نگهداشتن آن را برای چند روز تا تکمیل و ارسال سفارش توجیه کند. پس از این بازهٔ زمانی، رویداد ممکن است برای سیستمهای تحلیلی ما مهمتر شود.
دادهٔ تحلیلی، در حالی که بر همان دادهٔ عملیاتی استوار است، معمولاً بیشتر برای تصمیمگیریهای کسبوکار استفاده میشود. در سیستمهای سنتی، اینجاست که فرایندهایی مانند data warehouse، سیستم online analytical processing (OLAP) و Hadoop میدرخشند.
آن دادهٔ رویداد میتواند با ترکیبهای مختلف فیلدها در رویدادهای ما در سناریوهای مختلف برای یافتن insight در دادهٔ فروش، برای مثال، استخراج شود. اگر متوجه شویم فروش لوازم نظافت همیشه قبل از تعطیلات spike میکند، ممکن است از آن داده برای تولید گزینههای فروش بهتر برای کسبوکار در آینده استفاده کنیم. تفکیک این دو حوزه به شما کمک میکند retention و استراتژی ذخیرهٔ مناسب برای هر نوع داده را تعیین کنید.
۸.۴ بازگرداندن داده به Kafka
یکی از مهمترین نکات این است که فقط بهخاطر خروج داده از Kafka به معنای عدم امکان بازگرداندن آن نیست. شکل ۸.۴ مثالی از دادهای را نشان میدهد که عمر عادی خود را در Kafka گذرانده و در cloud storage مانند S3 archive شده است.
وقتی تغییر logic برنامه نیاز به reprocess دادهٔ قدیمیتر داشت، مجبور نشدیم کلاینتی بسازیم که هم از S3 و هم از Kafka بخواند. بلکه با ابزاری مانند Kafka Connect میتوانیم آن داده را از S3 به Kafka برگردانیم! از دید برنامههای ما interface یکسان میماند.
اگرچه شاید در نگاه اول واضح نباشد چرا چنین کاری میخواهیم، بیایید موقعیتی را در نظر بگیریم که در آن ارزش انتقال داده به Kafka پس از پردازش و گذشت دورهٔ retention را میبینیم.
تصور کنید تیمی روی یافتن الگو در دادهای که در سالهای مدیریت رویداد جمع کردهاند کار میکند. در مثال ما، terabyteها داده وجود دارد. برای سرویسدهی به جمعآوری دادهٔ real-time عملیاتی، این داده پس از پردازش توسط consumerهای real-time از Kafka به HDFS منتقل شده بود.
آیا logic برنامهٔ ما اکنون باید مستقیماً از HDFS بکشد؟ چرا فقط آن را به Kafka برنگردانیم و برنامه همانطور که قبل پردازش کند؟ بارگذاری دوباره داده در Kafka راه معتبری برای reprocess دادهای است که ممکن است از سیستم ما خارج شده باشد. شکل ۸.۴ مثال دیگری از نحوهٔ بازگرداندن داده به Kafka را نشان میدهد.
شکل ۸.۴. بازگرداندن داده به Kafka
Application rerun Kafka New topic Application New logic logic S3 Older data moved to Kafka Connect external data store like Loaded from S3 store kinaction_alerttrend data
پس از مدتی، رویدادها بهخاطر پیکربندیهای retention داخل Kafka برای برنامهها در دسترس نیستند. اما کپی همهٔ رویدادهای قبلی را در S3 bucket داریم.
فرض کنید نسخهٔ جدیدی از برنامهٔ قبلی داریم و ترجیح میدهیم همهٔ رویدادهای قبلی را مانند برنامهٔ قبلی پردازش کنیم. اما چون آن رویدادها در Kafka نیستند، آیا اکنون از S3 میکشیم؟
آیا میخواهیم logic برنامه از منابع مختلف بکشد یا فقط یک interface (یعنی Kafka) داشته باشد؟ میتوانیم topic جدیدی در Kafka cluster موجود بسازیم و با Kafka Connect داده را از S3 بارگذاری کنیم و در topic جدید Kafka قرار دهیم. سپس برنامه میتواند روی Kafka اجرا شود و رویدادها را بدون تغییر هیچ logic پردازشی پردازش کند.
فرایند فکری واقعاً این است که Kafka را بهعنوان interface برنامه نگه داریم و مجبور نشویم راههای متعدد برای کشیدن داده به پردازش بسازیم. چرا کد سفارشی برای کشیدن از مکانهای مختلف بسازیم و نگه داریم وقتی میتوانیم از ابزار موجودی مانند Connect برای انتقال داده به یا از Kafka استفاده کنیم؟
وقتی داده را در آن یک interface داریم، میتوانیم همانطور پردازش کنیم. این الگو بهویژه برای تیمهایی که میخواهند نسخهٔ جدید logic را روی دادهٔ تاریخی تست کنند قبل از cutover به production ارزشمند است.
یادداشت بهخاطر داشته باشید این تکنیک فقط برای دادهای اعمال میشود که از Kafka حذف شده است. اگر هنوز timeline کامل دادهای که نیاز دارید در Kafka دارید، همیشه میتوانید به offsetهای قدیمیتر seek کنید.
۸.۴.۱ Tiered Storage
گزینهٔ جدیدتری از Confluent Platform نسخه ۶.۰.۰ به بعد Tiered Storage نام دارد. در این مدل، storage محلی همان broker است و storage remote برای دادهٔ قدیمیتر (و در مکان remote ذخیرهشده) معرفی میشود و با پیکربندی زمانی (confluent.tier.local.hotset.ms) کنترل میشود [8].
بهعبارت دیگر، دادهای که هنوز «داغ» (hot) است روی دیسکهای broker محلی میماند و دادهای که از این آستانهٔ زمانی قدیمیتر شده به storage remote منتقل میشود — بدون اینکه consumerها مجبور شوند interface خود را تغییر دهند.
این رویکرد میتواند هزینهٔ نگهداری دادهٔ حجیم را کاهش دهد و در عین حال امکان دسترسی به تاریخچهٔ طولانیتر را فراهم کند. برای سازمانهایی که میخواهند retention طولانی داشته باشند اما هزینهٔ دیسک محلی broker را نمیپردازند، Tiered Storage راه میانهای بین نگهداری کامل روی broker و archive دستی به S3 است.
۸.۵ معماریها با Kafka
اگرچه الگوهای معماری مختلفی داده را هنگام ساخت محصولات بهعنوان رویداد میبینند، مانند model-view-controller (MVC)، peer-to-peer (P2P) یا service-oriented architecture (SOA) و غیره، Kafka میتواند نحوهٔ فکر شما به کل طراحی معماری را تغییر دهد. بیایید نگاهی به چند معماری بیندازیم که میتوانند توسط Kafka (و برای انصاف، platformهای streaming دیگر) تقویت شوند. این به دید متفاوتی از طراحی سیستمها برای مشتریانمان کمک میکند.
اصطلاح big data در برخی از این بحثها استفاده میشود. مهم است توجه کنیم مقدار داده و نیاز به پردازش آن بهموقع محرکهایی بودند که به برخی از این طراحیهای سیستم منجر شدند. با این حال، این معماریها فقط به برنامههای fast data یا big data محدود نیستند.
با رسیدن به limitهای فناوریهای پایگاه دادهٔ سنتی، دیدگاههای جدیدی دربارهٔ داده تکامل یافت. بیایید دو مورد را در بخشهای بعد ببینیم.
۸.۵.۱ معماری Lambda
اگر دربارهٔ برنامههای دادهای که نیاز به batch processing و workloadهای عملیاتی دارند تحقیق یا کار کردهاید، شاید به lambda architecture برخورده باشید. پیادهسازی این معماری میتواند با Kafka هم شروع شود، اما کمی پیچیدهتر است.
view real-time داده با view تاریخی ترکیب میشود تا به end userها سرویس دهد. پیچیدگی ادغام این دو view داده نباید نادیده گرفته شود. برای نویسندگان، rebuild کردن serving table چالش بود. همچنین احتمالاً باید interfaceهای مختلفی برای داده هنگام کار با نتایج هر دو سیستم نگه دارید.
کتاب Big Data نوشتهٔ Nathan Marz با James Warren lambda architecture را کاملتر بحث میکند و به جزئیات لایههای batch، serving و speed میپردازد [9]. شکل ۸.۵ مثالی از نحوهٔ دیدن سفارش مشتری بهصورت batch و real-time را نشان میدهد. مجموع مشتریان روزهای قبل میتواند با سفارشهای روز جاری در view دادهٔ ترکیبی برای end userها ادغام شود. این ترکیب میتواند بهصورت روند در topic kinaction_alerttrend نمایش داده شود — روندهای ماههای قبل همراه با رویدادهای جدید امروز.
شکل ۸.۵. معماری Lambda
Overnight batch Real-time totals totals This could also be shown by trends in kinaction_alerttrend being shown as trends from months before and combined with new events happening today. Customer D total Combined view Customer batch Customer A-C Customer A total Customer D Customer B total Customer E Customer C total Customer E total
با گرفتن مفاهیم شکل ۸.۵ و برای درک این معماری، بیایید هر لایه را در سطح بالا ببینیم. این لایهها در Big Data اثر Marz بحث شدهاند:
لایهٔ Batch — این لایه شبیه نحوهٔ batch processing با MapReduce در سیستمی مانند Hadoop است. با اضافه شدن دادهٔ جدید به data storeهای شما، لایهٔ batch به precompute کردن view دادهای که از قبل در سیستم است ادامه میدهد. نتایج معمولاً در پایگاه دادهٔ serving ذخیره میشوند.
لایهٔ Speed — این لایه از نظر مفهومی شبیه لایهٔ batch است، بهجز اینکه viewها را از دادهٔ اخیر تولید میکند. این لایه برای پوشش دادهای که هنوز توسط batch پردازش نشده مسئولیت دارد.
لایهٔ Serving — این لایه viewهایی را که به consumerها میفرستد پس از هر بهروزرسانی به viewهای batch بهروز میکند. end user در نهایت ترکیبی از viewهای batch و speed را میبیند.
برای end user، lambda architecture داده را از لایهٔ serving و لایهٔ speed ترکیب میکند تا درخواستها را با view کامل همهٔ دادهٔ اخیر و گذشته پاسخ دهد.
این لایهٔ streaming real-time واضحترین جایی است که Kafka نقش بازی میکند، اما میتواند برای feed کردن لایهٔ batch هم استفاده شود. در عمل، بسیاری از تیمها از Kafka برای ingest دادهٔ خام به لایهٔ speed و همزمان export داده به سیستمهای batch مانند Hadoop برای پردازشهای سنگینتر استفاده میکنند.
چالش اصلی lambda در نگهداری دو مسیر پردازشی موازی و ادغام نتایج آنها در لایهٔ serving است — هزینهای که kappa architecture (بخش بعدی) سعی در کاهش آن دارد.
۸.۵.۲ معماری Kappa
الگوی معماری دیگری که میتواند از قدرت Kafka بهره ببرد kappa architecture است. این معماری توسط co-creator Kafka، Jay Kreps، پیشنهاد شد [10].
به حفظ سیستمی فکر کنید که بدون اختلال برای کاربران تأثیر میگذارد. یک راه تعویض viewهای بهروزشده مانند lambda است. راه دیگر اجرای موازی سیستم فعلی با سیستم جدید و cutover وقتی نسخهٔ جدید آمادهٔ سرویسدهی به ترافیک است.
بخشی از این cutover البته اطمینان از این است که دادهای که نسخهٔ قدیمیتر سرویس میدهد در نسخهٔ جدیدتر بهدرستی منعکس شود. در kappa، این کار با replay همهٔ رویدادها از Kafka انجام میشود — نه با ادغام batch و stream.
فقط وقتی نیاز دارید دادهٔ رو به کاربر را regenerate میکنید. نیازی به ادغام دادهٔ قدیم و جدید نیست که در برخی پیادهسازیهای lambda فرایند مداومی است. لازم نیست job مداوم باشد، بلکه وقتی تغییر logic برنامه لازم است فراخوانی میشود. همچنین نیازی به تغییر interface به داده نیست. Kafka میتواند همزمان توسط کد برنامهٔ جدید و قدیم استفاده شود. شکل ۸.۶ نشان میدهد چگونه رویدادهای مشتری برای ساخت view بدون استفاده از لایهٔ batch استفاده میشوند.
شکل ۸.۶ رویدادهای مشتری از گذشته و حال را که مستقیماً برای ساخت view استفاده میشوند نشان میدهد. تصور کنید رویدادها از Kafka منبع میشوند و سپس با Kafka Streams یا ksqlDB همهٔ رویدادها را در نزدیکی real-time میخوانیم و view برای end userها میسازیم.
در این مدل، دادهٔ kinaction_alerttrend batch نمیشود، بلکه در صورت نیاز replay میشود. هیچ مجموع batch شبانهای وجود ندارد — فقط رویدادها و logic streaming.
شکل ۸.۶. معماری Kappa
Past New events events Running total logic Custom customer Live view event Customer totals Customer events 0 to X Custom customer event For example, kinaction_alerttrend data No batch not being batched totals, just but replayed if needed events
اگر تغییری در نحوهٔ پردازش رویدادهای مشتری لازم شود، میتوان application دومی با logic متفاوت (مانند query جدید ksqlDB) ساخت و همان منبع داده (Kafka) را مثل قبل استفاده کرد. نیازی به لایهٔ batch (و مدیریت آن) نیست چون فقط logic streaming برای ساخت viewهای end user استفاده میشود. replay رویدادهای تاریخی از Kafka — همان قابلیتی که در فصلهای قبل دربارهٔ offset و seek بحث کردیم — ستون فقرات kappa است: وقتی logic عوض میشود، همان رویدادها را دوباره از ابتدا پردازش میکنید و view جدید میسازید.
۸.۶ راهاندازی چند cluster
بیشتر topicها و بحثهای ما تا اینجا از دیدگاه داده در یک cluster بودهاند. اما Kafka خوب scale میشود و رسیدن به صدها broker برای یک cluster غیرمعمول نیست. با این حال، یک cluster با اندازهٔ واحد همهٔ infrastructureها را پوشش نمیدهد. یکی از نگرانیهایی که هنگام صحبت دربارهٔ storage cluster با آن روبهرو میشویم این است که داده را نسبت به کلاینتهای end user کجا سرویس میدهید. اگر producerها و consumerهای شما در مناطق جغرافیایی مختلف یا دیتاسنترهای جدا هستند، latency و هزینهٔ انتقال داده میتواند تصمیم شما را به سمت چند cluster هدایت کند. در این بخش دربارهٔ scale با افزودن cluster صحبت میکنیم، نه فقط با افزودن broker.
۸.۶.۱ Scale با افزودن cluster
معمولاً اولین چیزهایی که scale میشوند منابع داخل cluster موجود شما هستند. تعداد brokerها اولین گزینهای است که مسیر مستقیمی به رشد میدهد. اما وقتی یک cluster به صدها broker و terabyteها داده میرسد، مدیریت آن — از جمله backup، upgrade و troubleshooting — خودش چالش میشود. Netflix® استراتژی multicluster خود را بهعنوان راهی برای تقسیم این بار معرفی کرده است [11]. بهجای استفاده از تعداد broker بهعنوان تنها راه scale کردن cluster، فهمیدند میتوانند با افزودن خود clusterها scale کنند! مثلاً یک cluster مخصوص ingest (نوشتن) و cluster(های) جدا برای serving (خواندن) داشته باشند.
این طراحی ایدهٔ Command Query Responsibility Segregation (CQRS) را به ذهن میآورد. برای جزئیات بیشتر CQRS، سایت Martin Fowler را در https://martinfowler.com/bliki/CQRS.html ببینید، بهویژه ایدهٔ جداسازی بار خواندن داده از بار نوشتن داده [12].
هر action میتواند بهصورت مستقل scale شود بدون اینکه actionهای دیگر را محدود کند. اگرچه CQRS الگویی است که میتواند پیچیدگی به سیستمهای ما اضافه کند، جالب است ببینیم این مثال خاص چگونه با جداسازی بار producerها که داده به Kafka میفرستند از بار گاهی بسیار بزرگتر consumerها که داده را میخوانند، عملکرد cluster بزرگ را مدیریت میکند.
در عمل، MirrorMaker یا replication بین clusterها میتواند داده را از cluster ingest به clusterهای read-only کپی کند تا consumerهای سنگین بار اضافی روی cluster اصلی نگذارند. این الگو در سازمانهایی با ترافیک خواندن بسیار بیشتر از نوشتن رایج است.
۸.۷ گزینههای ذخیرهٔ cloud و container
اگرچه در فصل ۶ دربارهٔ دایرکتوریهای log Kafka صحبت کردیم، به انواع instanceهایی که در محیطهایی با storage کوتاهعمرتر استفاده میشوند نپرداختیم. برای مرجع، Confluent مطالعهای دربارهٔ deploymentها با ملاحظات AWS بهاشتراک گذاشت که در آن trade-offهای نوع storage را بررسی کردند [13]. در آن مطالعه، انواع EBS volume و تأثیر آنها بر throughput و durability مورد بررسی قرار گرفته است.
گزینهٔ دیگر Confluent Cloud (https://www.confluent.io/confluent-cloud/) است. این گزینه به شما اجازه میدهد کمتر نگران storage زیرین استفادهشده در providerهای cloud مختلف و نحوهٔ مدیریت آن باشید.
همانطور که همیشه، بهخاطر داشته باشید Kafka خودش همچنان تکامل مییابد و به نیازهایی که کاربران بهعنوان چالشهای روزانه با آن روبهرو میشوند واکنش نشان میدهد. KIP-392 موردی را نشان میدهد که در زمان نگارش پذیرفته شده بود و به حل مسائل cluster Kafka که دادهمراکز را در بر میگیرد کمک میکند. KIP با عنوان «Allow consumers to fetch from the closest replica» است [14]. این به consumerها اجازه میدهد از replica نزدیکتر بخوانند تا latency در deploymentهای چند دیتاسنتری کاهش یابد.
حتماً گاهی KIPهای اخیر (Kafka Improvement Proposals) را ببینید تا ببینید Kafka چگونه به روشهای هیجانانگیز تکامل مییابد.
۸.۷.۱ clusterهای Kubernetes
در محیط containerized، ممکن است با چالشهایی مشابه cloud روبهرو شویم. اگر به limit memory بد پیکربندیشده روی broker برخورد کنیم، ممکن است خود را روی node کاملاً جدیدی بدون داده بیابیم مگر اینکه داده بهدرستی persist شده باشد.
اگر در محیط sandbox نیستیم که بتوانیم داده را از دست بدهیم، persistent volume claimها ممکن است توسط brokerهای ما لازم باشد تا اطمینان حاصل شود داده از هر restart، failure یا جابهجایی جان سالم به در میبرد. اگرچه container instance broker ممکن است تغییر کند، باید بتوانیم persistent volume قبلی را claim کنیم.
برنامههای Kafka احتمالاً از StatefulSet API استفاده میکنند تا هویت هر broker را در برابر failureها یا جابهجایی pod حفظ کنند. این هویت static هم به claim کردن همان persistent volumeهایی که قبل از down شدن pod استفاده شدهاند کمک میکند. از قبل Helm® chartها (https://github.com/confluentinc/cp-helm-charts) برای شروع با setup تست هنگام کاوش Kubernetes وجود دارند [15]. Confluent for Kubernetes هم در مدیریت Kubernetes به ما کمک میکند [16].
هنگام deploy Kafka روی Kubernetes، علاوه بر brokerها به ZooKeeper (یا در نسخههای جدیدتر، KRaft) و exporterهای monitoring هم نیاز دارید. Helm chartها این اجزا را بهصورت یک مجموعه نصب میکنند.
دامنهٔ Kubernetes نسبتاً بزرگ است که در بحث ما پوشش دهیم، اما نگرانیهای کلیدی صرفنظر از محیط ما وجود دارند. brokerهای ما هویتی در cluster دارند و به دادهای که هر کدام مرتبط است وابستهاند. برای سالم نگه داشتن cluster، آن brokerها باید بتوانند logهای مدیریتشدهٔ broker را در برابر failure، restart یا upgrade شناسایی کنند. در محیط container، این یعنی persistent volumeها باید به broker ID ثابت متصل بمانند — در غیر این صورت پس از restart ممکن است broker فکر کند log خالی است و دادهٔ شما از بین برود. همان اصولی که در فصل ۶ دربارهٔ log.dirs و ساختار فایلهای log روی دیسک یاد گرفتیم، در Kubernetes هم با لایهٔ abstraction اضافی persistent volume اعمال میشوند.
در این فصل گزینههای مختلف نگهداری و جابهجایی داده را بررسی کردیم — از retention روی broker تا archive در cloud و بازگرداندن داده برای reprocess. فصل بعد به موضوعات مرتبط با مصرف و پردازش داده در Kafka میپردازد.
خلاصه
- retention داده باید توسط نیازهای کسبوکار هدایت شود. تصمیمهایی که باید سنجید شامل هزینهٔ storage و نرخ رشد دادهٔ ما در طول زمان است. retention پیشفرض هفت روز برای همهٔ use caseها کافی نیست.
- اندازه و زمان پارامترهای پایه برای تعریف مدت نگهداری داده روی دیسک هستند. میتوان retention را با
-1برای هر دو پارامتر غیرفعال کرد یا از topic فشردهشونده برای نگهداری latest value استفاده کرد. - ذخیرهٔ بلندمدت داده خارج از Kafka گزینهای برای دادهای است که ممکن است برای مدتهای طولانی نیاز به نگهداری داشته باشد. ابزارهایی مانند Secor و Connect sinkها میتوانند archive را خودکار کنند. داده میتواند در صورت نیاز با produce کردن دوباره به cluster در زمان بعدی دوباره معرفی شود.
- توانایی Kafka در مدیریت سریع داده و همچنین replay داده میتواند معماریهایی مانند lambda و kappa را فعال کند. kappa پیچیدگی ادغام batch و stream را با تکیه بر replay کاهش میدهد.
- workloadهای cloud و container اغلب شامل instanceهای broker کوتاهعمر هستند. دادهای که باید persist شود نیاز به برنامهای دارد — persistent volume و StatefulSet در Kubernetes — تا instanceهای تازهساخته یا بازیابیشده بتوانند در همهٔ instanceها از آن داده استفاده کنند.
منابع
- «Kafka Broker Configurations.» مستندات Confluent (بدون تاریخ). https://docs.confluent.io/platform/current/installation/configuration/broker-configs.html#brokerconfigs_log.retention.hours (دسترسی: ۱۴ دسامبر ۲۰۲۰).
- B. Svingen. «Publishing with Apache Kafka at The New York Times.» وبلاگ Confluent (۶ سپتامبر ۲۰۱۷). https://www.confluent.io/blog/publishing-apache-kafka-new-york-times/ (دسترسی: ۲۵ سپتامبر ۲۰۱۸).
- «Kafka Broker Configurations.» مستندات Confluent (بدون تاریخ). https://docs.confluent.io/platform/current/installation/configuration/broker-configs.html (دسترسی: ۱۴ دسامبر ۲۰۲۰).
- «Kafka Broker Configurations: log.retention.ms.» مستندات Confluent (بدون تاریخ). https://docs.confluent.io/platform/current/installation/configuration/broker-configs.html#brokerconfigs_log.retention.ms (دسترسی: ۱۴ دسامبر ۲۰۲۰).
- «Flume 1.9.0 User Guide: Kafka Sink.» Apache Software Foundation (بدون تاریخ). https://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#kafka-sink (دسترسی: ۱۰ اکتبر ۲۰۱۹).
- «Connectors.» مستندات Debezium (بدون تاریخ). https://debezium.io/documentation/reference/connectors/ (دسترسی: ۲۰ ژوئیه ۲۰۲۱).
- «Pinterest Secor.» Pinterest. GitHub. https://github.com/pinterest/secor/blob/master/README.md (دسترسی: ۱ ژوئن ۲۰۲۰).
- «Tiered Storage.» مستندات Confluent (بدون تاریخ). https://docs.confluent.io/platform/current/kafka/tiered-storage.html (دسترسی: ۲ ژوئن ۲۰۲۱).
- N. Marz and J. Warren. Big Data: Principles and best practices of scalable real-time data systems. Shelter Island, NY, USA: Manning, 2015.
- J. Kreps. «Questioning the Lambda Architecture.» O'Reilly Radar (۲ ژوئیه ۲۰۱۴). https://www.oreilly.com/radar/questioning-the-lambda-architecture/ (دسترسی: ۱۱ اکتبر ۲۰۱۹).
- A. Wang. «Multi-Tenant, Multi-Cluster and Hierarchical Kafka Messaging Service.» ارائهشده در Kafka Summit Confluent، San Francisco، USA، ۲۰۱۷ [آنلاین]. https://www.confluent.io/kafka-summit-sf17/multitenant-multicluster-and-hieracrchical-kafka-messaging-service/.
- M. Fowler. «CQRS» (۱۴ ژوئیه ۲۰۱۱). https://martinfowler.com/bliki/CQRS.html (دسترسی: ۱۱ دسامبر ۲۰۱۷).
- A. Loddengaard. «Design and Deployment Considerations for Deploying Apache Kafka on AWS.» وبلاگ Confluent (۲۸ ژوئیه ۲۰۱۶). https://www.confluent.io/blog/design-and-deployment-considerations-for-deploying-apache-kafka-on-aws/ (دسترسی: ۱۱ ژوئن ۲۰۲۱).
- KIP-392: «Allow consumers to fetch from closest replica.» Wiki for Apache Kafka. Apache Software Foundation (۵ نوامبر ۲۰۱۹). https://cwiki.apache.org/confluence/display/KAFKA/KIP-392%3A+Allow+consumers+to+fetch+from+closest+replica (دسترسی: ۱۰ دسامبر ۲۰۱۹).
- cp-helm-charts. Confluent Inc. GitHub (بدون تاریخ). https://github.com/confluentinc/cp-helm-charts (دسترسی: ۱۰ ژوئن ۲۰۲۰).
- «Confluent for Kubernetes.» مستندات Confluent (بدون تاریخ). https://docs.confluent.io/operator/2.0.2/overview.html (دسترسی: ۱۶ اوت ۲۰۲۱).