کافکا از نمای نزدیک: سفری به قلب یک سیستم قدرتمند

با توجه به رواج و محبوبیت کافکا در میان اکثر سیستم‌های اطلاعاتی نوین و ضرورت آشنایی عمیق‌تر با این سامانه توزیع پیام قدرتمند، تصمیم به ترجمه مقاله If you’re learning Kafka, this article is for you گرفتم و تمامی عکس ها هم از این مقاله برگرفته شده است.


مقدمه

حدود چهارده سال پیش، شرکت لینکدین (LinkedIn) ابزار قدرتمندی به نام کافکا را طراحی کرد تا بتواند حجم عظیمی از داده‌های تولیدشده در سیستم‌هایش (مثل لاگ‌ها یا گزارش‌های فعالیت کاربران) را مدیریت کند.

کافکا سیستمی است که ویژگی‌های دو نوع فناوری را با هم ترکیب کرده است: تجمیع‌کننده‌های لاگ (ابزارهایی که داده‌های پراکنده را جمع‌آوری و ذخیره می‌کنند) و سیستم‌های پیام‌رسانی انتشار/اشتراک (که امکان ارسال و دریافت پیام‌ها بین برنامه‌ها را فراهم می‌کنند). به زبان ساده، کافکا مثل یک پل ارتباطی عمل می‌کند که داده‌ها را با سرعت بالا و به‌صورت قابل‌اعتماد بین بخش‌های مختلف یک سیستم منتقل می‌کند. این سیستم طوری طراحی شده که بتواند حجم عظیمی از داده‌ها را به‌سرعت پردازش کند و با افزایش نیاز، به‌راحتی مقیاس‌پذیر باشد (یعنی بتوان سرورهای بیشتری به آن اضافه کرد).

کافکا یک رابط برنامه‌نویسی (API) ساده ارائه می‌دهد که به برنامه‌ها اجازه می‌دهد داده‌ها یا رویدادها (مثل کلیک کاربران یا تراکنش‌های مالی) را در لحظه دریافت و پردازش کنند. امروزه کافکا در بسیاری از شرکت‌های بزرگ مثل نتفلیکس، اوبر و حتی بانک‌ها و فروشگاه‌های آنلاین استفاده می‌شود، چون می‌تواند داده‌های عظیم را به‌صورت بلادرنگ (real-time) مدیریت کند.

کافکا در طول زمان پیشرفت‌های زیادی کرده است، مثلاً قابلیت‌های جدیدی مثل ذخیره‌سازی لایه‌ای (tiered storage) یا پروتکل Kraft اضافه شده‌اند. اما هسته اصلی آن، یعنی روشی که داده‌ها را مدیریت می‌کند، از همان ابتدا تغییر زیادی نکرده است. این مقاله حاصل تجربیات و مطالعات من درباره کافکاست و هدفش این است که به شما کمک کند تا بدون احساس سردرگمی، با این ابزار قدرتمند آشنا شوید.

مرور کلی

پیام‌ها

در کافکا، واحد اصلی داده‌ها پیام نام دارد. می‌توانید پیام را مثل یک بسته اطلاعاتی کوچک تصور کنید که حاوی داده‌ای مثل یک لاگ، یک رویداد یا حتی یک دستور است. هر پیام می‌تواند یک کلید اختیاری داشته باشد. کلید مثل یک برچسب است که به کافکا کمک می‌کند پیام‌ها را بهتر سازمان‌دهی کند. هم پیام و هم کلید به‌صورت آرایه‌ای از بایت‌ها (یک سری کدهای کامپیوتری) ذخیره می‌شوند.

پیام ها در کافکا

کلیدها معمولاً زمانی استفاده می‌شوند که بخواهید کنترل کنید پیام‌های مرتبط با هم کجا ذخیره شوند. برای مثال، اگر بخواهید تمام پیام‌های مربوط به یک کاربر خاص (مثلاً تمام خریدهای یک مشتری) در یک مکان مشخص ذخیره شوند، کافکا با استفاده از کلید و یک روش به نام هشینگ ثابت (consistent hashing) این کار را انجام می‌دهد. این روش تضمین می‌کند که پیام‌هایی با کلید یکسان همیشه در یک مکان مشخص (پارتیشن) ذخیره شوند.

نکته جالب این است که پیام‌ها در کافکا یک شناسه (ID) مشخص ندارند. به‌جای آن، کافکا از چیزی به نام افست منطقی (logical offset) استفاده می‌کند. افست مثل یک شماره ردیف است که نشان می‌دهد هر پیام در کجا قرار دارد. این روش باعث می‌شود کافکا نیازی به نگه‌داری فهرست‌های پیچیده برای پیدا کردن پیام‌ها نداشته باشد، که باعث افزایش سرعت و کاهش مصرف منابع می‌شود. وقتی یک برنامه (مصرف‌کننده) می‌خواهد پیام بعدی را بخواند، کافکا با محاسبه طول پیام فعلی، مکان پیام بعدی را پیدا می‌کند.

موضوعات و پارتیشن‌ها

پیام‌ها در کافکا داخل موضوعات (topics) سازمان‌دهی می‌شوند. موضوع را می‌توان مثل یک پوشه یا کانال اطلاعاتی تصور کرد که پیام‌های مرتبط با یک موضوع خاص (مثلاً «تراکنش‌های بانکی» یا «فعالیت کاربران») در آن ذخیره می‌شوند. هر موضوع می‌تواند به بخش‌های کوچک‌تری به نام پارتیشن تقسیم شود. پارتیشن‌ها مثل زیرپوشه‌هایی هستند که به کافکا کمک می‌کنند داده‌ها را به‌صورت موازی و روی سرورهای مختلف مدیریت کند.

K3

این پارتیشن‌ها دو مزیت بزرگ دارند:

  1. افزونگی (redundancy): کافکا می‌تواند نسخه‌های پشتیبان از داده‌ها را در سرورهای مختلف نگه دارد تا اگر یک سرور از کار بیفتد، داده‌ها از دست نروند.
  2. مقیاس‌پذیری: چون هر پارتیشن می‌تواند روی یک سرور جداگانه باشد، می‌توانید با اضافه کردن سرورهای بیشتر، ظرفیت سیستم را افزایش دهید.

هر پارتیشن در واقع یک لاگ منطقی است، یعنی یک فهرست مرتب از پیام‌ها که به‌ترتیب زمان ورودشان ذخیره می‌شوند. از نظر فیزیکی، این لاگ به‌صورت مجموعه‌ای از فایل‌های کوچک‌تر به نام فایل‌های سگمنت ذخیره می‌شود (مثلاً هر فایل حدود ۱ گیگابایت). وقتی پیامی به پارتیشن اضافه می‌شود، کافکا آن را به انتهای فایل سگمنت فعال الحاق می‌کند، مثل اضافه کردن یک خط جدید به انتهای یک دفترچه یادداشت.

طراحی‌ها

استفاده کافکا از سیستم فایل

کافکا برای ذخیره‌سازی داده‌ها به سیستم فایل عامل‌سیستم (مثل لینوکس یا ویندوز) وابسته است، به‌جای اینکه خودش یک سیستم ذخیره‌سازی اختصاصی طراحی کند. این کار باعث ساده‌تر شدن طراحی کافکا می‌شود. کافکا از چیزی به نام کش صفحه‌ای (page cache) که توسط سیستم‌عامل مدیریت می‌شود، استفاده می‌کند.

K4

کش صفحه‌ای مثل یک حافظه موقت است که سیستم‌عامل از بخشی از RAM کامپیوتر برای ذخیره داده‌هایی که زیاد استفاده می‌شوند، استفاده می‌کند. این کار باعث می‌شود به‌جای اینکه هر بار داده‌ها از دیسک خوانده شوند (که کند است)، از این حافظه سریع‌تر در RAM استفاده شود. اگر برنامه دیگری به RAM نیاز داشته باشد، سیستم‌عامل به‌صورت خودکار بخشی از این حافظه را آزاد می‌کند تا عملکرد کلی سیستم مختل نشود.

این روش برای کافکا که روی ماشین مجازی جاوا (JVM) اجرا می‌شود، بسیار مفید است، چون JVM گاهی با مشکلات زیر روبه‌روست:

  • مصرف حافظه زیاد برای ذخیره اشیاء.
  • کند شدن فرآیند جمع‌آوری زباله (garbage collection) وقتی تعداد اشیاء زیاد می‌شود.
الگوی دسترسی ترتیبی

شاید فکر کنید: «دیسک‌ها کندتر از RAM هستند، پس چطور کافکا این‌قدر سریع است؟» جواب در روشی است که کافکا داده‌ها را می‌خواند و می‌نویسد. کافکا از الگوی دسترسی ترتیبی استفاده می‌کند، یعنی داده‌ها به‌ترتیب و پشت سر هم خوانده و نوشته می‌شوند، نه به‌صورت تصادفی.

  • دسترسی تصادفی: مثل این است که بخواهید صفحات مختلف یک کتاب را به‌ترتیب دلخواه بخوانید، که زمان‌بر است.
  • دسترسی ترتیبی: مثل خواندن کتاب از صفحه اول تا آخر است، که بسیار سریع‌تر است.

کافکا طوری طراحی شده که:

  • نوشتن: وقتی داده‌ای (مثلاً یک پیام) به کافکا اضافه می‌شود، به انتهای فایل سگمنت الحاق می‌شود، مثل نوشتن یک خط جدید در انتهای یک فایل. این کار کاملاً ترتیبی است.
  • خواندن: وقتی برنامه‌ای (مصرف‌کننده) داده‌ها را می‌خواند، پیام‌ها را به‌ترتیب از یک پارتیشن مشخص می‌خواند. کافکا از دو فایل شاخص استفاده می‌کند: یکی برای پیدا کردن سریع مکان پیام‌ها بر اساس افست، و دیگری برای پیدا کردن پیام‌ها بر اساس زمان‌بندی.

این روش باعث می‌شود کافکا حتی با استفاده از دیسک، عملکردی نزدیک به RAM داشته باشد.

بهینه‌سازی کپی صفر (Zero-copy)

کافکا از یک تکنیک به نام کپی صفر (zero-copy) استفاده می‌کند که باعث می‌شود انتقال داده‌ها سریع‌تر و کارآمدتر باشد. معمولاً وقتی داده‌ای از دیسک به شبکه منتقل می‌شود، چندین بار کپی می‌شود و این کار زمان‌بر است. مثلاً:

  1. داده از دیسک به کش صفحه‌ای سیستم‌عامل کپی می‌شود.
  2. از کش به برنامه کافکا کپی می‌شود.
  3. از برنامه به بافر شبکه کپی می‌شود.
  4. از بافر شبکه به کارت شبکه (NIC) کپی می‌شود.
K5

هر مرحله نیاز به تغییر زمینه (context switch) بین حالت‌های کاربر و کرنل دارد، که باعث کندی می‌شود. اما با کپی صفر، کافکا داده‌ها را مستقیماً از کش صفحه‌ای به کارت شبکه منتقل می‌کند (با استفاده از فراخوانی سیستمی به نام sendfile() در سیستم‌های یونیکس). این کار تعداد کپی‌ها را از چهار به دو کاهش می‌دهد و سرعت را به‌طور چشمگیری افزایش می‌دهد.

K6
دسته‌بندی (Batching)

کافکا برای افزایش کارایی، پیام‌ها را به‌صورت گروهی (batch) ارسال و ذخیره می‌کند. به‌جای اینکه هر پیام به‌تنهایی فرستاده شود (که باعث افزایش رفت‌وبرگشت‌های شبکه می‌شود)، کافکا چندین پیام را با هم گروه‌بندی می‌کند و یکجا ارسال یا ذخیره می‌کند. این کار مثل این است که به‌جای ارسال تک‌تک نامه‌ها، یک بسته پستی بزرگ بفرستید.

این دسته‌بندی باعث می‌شود:

  • نوشتن سریع‌تر: کارگزار کافکا به‌جای نوشتن تک‌تک پیام‌ها، یک گروه از پیام‌ها را یکجا به دیسک اضافه می‌کند.
  • کاهش فشار شبکه: اگر پهنای باند شبکه محدود باشد، کافکا می‌تواند این دسته‌های پیام را فشرده‌سازی کند تا حجم داده‌های ارسالی کمتر شود.

تولیدکننده (Producer)

جریان کار

K7

وقتی از تولیدکننده کافکا (Kafka Producer API) برای ارسال داده استفاده می‌کنید، چند مرحله ساده اتفاق می‌افتد. بیایید این مراحل را مثل ارسال یک بسته پستی تصور کنیم:

  1. ایجاد بسته اطلاعاتی (ProducerRecord): تولیدکننده ابتدا یک بسته اطلاعاتی به نام ProducerRecord می‌سازد. این بسته شامل خود پیام (مثلاً داده‌ای مثل «کاربر X خرید کرد»)، موضوع (topic) مقصد، و گاهی اطلاعاتی اضافی مثل کلید (برای دسته‌بندی پیام)، شماره پارتیشن، زمان‌بندی (timestamp)، یا هدرهای اضافی است.
  2. تبدیل به فرمت قابل‌ارسال: پیام و کلید به شکل آرایه‌ای از بایت‌ها (یک نوع کد کامپیوتری) تبدیل می‌شوند تا بتوانند از طریق شبکه ارسال شوند.
  3. انتخاب پارتیشن: اگر خودتان شماره پارتیشن را مشخص نکرده باشید، تولیدکننده از یک بخش به نام پارتیشنر (partitioner) استفاده می‌کند. این بخش با توجه به کلید پیام، تصمیم می‌گیرد که پیام به کدام پارتیشن در موضوع ارسال شود.
  4. گروه‌بندی پیام‌ها: پیام به یک گروه (batch) از پیام‌هایی که به همان موضوع و پارتیشن می‌روند، اضافه می‌شود. این کار مثل جمع کردن چند نامه در یک بسته پستی است تا ارسال کارآمدتر باشد.
  5. ارسال گروه پیام‌ها: یک نخ (thread) جداگانه این گروه‌های پیام را به کارگزارهای کافکا (Kafka brokers) می‌فرستد.
  6. دریافت پاسخ: اگر کارگزار پیام را با موفقیت دریافت کند، اطلاعاتی مثل موضوع، پارتیشن و شماره افست (offset) پیام را برمی‌گرداند. اگر مشکلی پیش بیاید (مثلاً خطا یا تأخیر)، تولیدکننده ممکن است چند بار تلاش کند و اگر موفق نشود، خطا گزارش می‌شود.

روش‌های ارسال پیام

آیا می‌توانیم نحوه ارسال پیام را کنترل کنیم؟ بله! کافکا سه روش برای ارسال پیام دارد:

  • ارسال و فراموشی (Fire-and-forget): مثل این است که نامه‌ای را در صندوق پستی بیندازید و چک نکنید که رسیده یا نه. تولیدکننده پیام را می‌فرستد و منتظر پاسخ نمی‌ماند. این روش خیلی سریع است، اما اگر مشکلی پیش بیاید (مثلاً پیام گم شود)، شما متوجه نمی‌شوید. برای کاربردهایی که سرعت مهم‌تر از اطمینان است، استفاده می‌شود.
  • ارسال هم‌زمان (Synchronous): مثل این است که نامه را با پست سفارشی بفرستید و منتظر تأیید تحویل بمانید. تولیدکننده پیام را می‌فرستد و تا وقتی پاسخ از کارگزار نرسد، منتظر می‌ماند. اگر خطایی رخ دهد، می‌تواند آن را تشخیص دهد. این روش کندتر است و به همین دلیل در سیستم‌های بزرگ کمتر استفاده می‌شود.
  • ارسال غیرهم‌زمان (Asynchronous): مثل ارسال نامه با امکان دریافت پیامک تأیید است. تولیدکننده پیام‌ها را بدون منتظر ماندن برای پاسخ می‌فرستد، اما می‌تواند یک تابع (callback) تنظیم کند تا در صورت خطا، مطلع شود. این روش تعادل خوبی بین سرعت و اطمینان ایجاد می‌کند.
K9
روش ارسال و فراموشی
K92
روش ارسال هم‌زمان
K93
ارسال غیرهم‌زمان

آیا پیام با موفقیت تحویل شد؟

کافکا به شما اجازه می‌دهد با تنظیم پارامتر acks مشخص کنید که چه زمانی یک پیام «با موفقیت ارسال‌شده» تلقی شود. این پارامتر تعیین می‌کند که کارگزار تا چه حد باید تأیید کند که پیام دریافت شده است:

  • acks=0: تولیدکننده اصلاً منتظر تأیید کارگزار نمی‌ماند و فرض می‌کند پیام ارسال شده است. این روش سریع‌ترین است، اما خطر از دست رفتن پیام‌ها زیاد است.
  • acks=1: تولیدکننده وقتی پیام به رهبر (leader، کارگزار اصلی پارتیشن) برسد، تأیید می‌گیرد. این روش تعادل خوبی بین سرعت و اطمینان دارد.
  • acks=all: تولیدکننده تنها زمانی تأیید می‌گیرد که همه نسخه‌های پشتیبان (replicas) پیام را دریافت کرده باشند. این روش امن‌ترین است، چون حتی اگر یک کارگزار خراب شود، پیام از دست نمی‌رود، اما کندتر است.
K10
ACKS=0
K101
ACKS=1
K102
ACKS=ALL

پیام‌ها چطور توزیع می‌شوند؟

11

پیام‌ها در کافکا می‌توانند یک کلید اختیاری داشته باشند (که به‌صورت پیش‌فرض خالی است). کلید مثل یک برچسب است که مشخص می‌کند پیام به کدام پارتیشن برود. اگر کلیدی وجود نداشته باشد، کافکا از یکی از این روش‌ها استفاده می‌کند:

  • پارتیشنر چرخشی (Round-Robin، نسخه‌های قدیمی کافکا ≤ ۲٫۳): پیام‌ها به‌ترتیب بین پارتیشن‌ها پخش می‌شوند، مثل پخش کردن کارت‌های بازی به نوبت بین بازیکنان.
  • پارتیشنر چسبنده (Sticky Partitioner، نسخه‌های جدیدتر ≥ ۲٫۴): کافکا سعی می‌کند گروهی از پیام‌ها را به یک پارتیشن بفرستد تا زمانی که آن پارتیشن پر شود، سپس به پارتیشن بعدی می‌رود. این روش کارایی را بالا می‌برد، چون پیام‌ها به‌صورت متمرکز ارسال می‌شوند.

اگر پیام کلیدی داشته باشد، کافکا با استفاده از یک الگوریتم هش (hash) تصمیم می‌گیرد که پیام به کدام پارتیشن برود. پیام‌هایی با کلید یکسان همیشه به همان پارتیشن می‌روند. همچنین می‌توانید یک پارتیشنر سفارشی تعریف کنید تا دقیقاً مشخص کنید پیام‌ها کجا بروند.

12

مصرف‌کننده (Consumer)

وقتی کافکا ساخته شد، سیستم‌های مشابه مثل Scribe (از فیسبوک) یا Flume از مدل فشاری (push-based) استفاده می‌کردند، یعنی داده‌ها را به مصرف‌کننده‌ها «هل» می‌دادند. اما مهندسان لینکدین مدل کششی (pull-based) را انتخاب کردند، چون به مصرف‌کننده‌ها اجازه می‌دهد داده‌ها را با سرعت دلخواه خود بخوانند. این روش مثل این است که به‌جای اینکه کسی کتاب‌ها را یکی‌یکی به شما بدهد، خودتان به کتابخانه بروید و هر وقت آماده بودید، کتاب بعدی را بردارید.

13

مزایای مدل کششی:

  • جبران تأخیر: اگر مصرف‌کننده از پردازش پیام‌ها عقب بیفتد، می‌تواند با سرعت خودش به‌روز شود.
  • دریافت گروهی: مصرف‌کننده می‌تواند گروهی از پیام‌ها را یکجا دریافت کند، که باعث صرفه‌جویی در زمان و منابع می‌شود.

درخواست‌های مصرف‌کننده

مصرف‌کننده‌ها همیشه پیام‌ها را از یک پارتیشن خاص به‌ترتیب می‌خوانند. وقتی مصرف‌کننده یک افست (شماره ردیف پیام) را تأیید می‌کند، به کارگزار می‌گوید که همه پیام‌های قبلی آن پارتیشن را دریافت کرده است.

رابط برنامه‌نویسی مصرف‌کننده (Consumer API) مثل یک حلقه بی‌پایان است که مرتب از کارگزار درخواست داده می‌کند. مصرف‌کننده:

  1. یک درخواست غیرهم‌زمان (pull request) برای دریافت داده‌ها می‌فرستد و افست پیام موردنظر را مشخص می‌کند.
  2. کارگزار با استفاده از افست، داده‌های درست را پیدا کرده و برمی‌گرداند.
  3. مصرف‌کننده افست پیام بعدی را محاسبه می‌کند (با اضافه کردن طول پیام فعلی به افست آن) و برای درخواست بعدی از آن استفاده می‌کند.

گروه‌های مصرف‌کننده

کافکا مفهومی به نام گروه مصرف‌کننده دارد. گروه مصرف‌کننده مثل تیمی از کارگران است که با هم روی یک مجموعه موضوع (topics) کار می‌کنند. هر گروه می‌تواند شامل یک یا چند مصرف‌کننده باشد. نکته مهم این است که هر پارتیشن فقط به یک مصرف‌کننده در گروه اختصاص داده می‌شود، یعنی پیام‌های یک پارتیشن فقط توسط یک مصرف‌کننده خوانده می‌شوند. اگر تعداد مصرف‌کننده‌ها بیشتر از تعداد پارتیشن‌ها باشد، برخی مصرف‌کننده‌ها بیکار می‌مانند.

هر مصرف‌کننده در یک گروه، یک شناسه گروه (group ID) یکسان دارد. وقتی مصرف‌کننده جدیدی به گروه اضافه می‌شود، به‌طور خودکار همان شناسه گروه را می‌گیرد.

14

کافکا از یک هماهنگ‌کننده گروه (Group Coordinator، یکی از کارگزارها) برای مدیریت گروه استفاده می‌کند. این هماهنگ‌کننده:

  • پیام‌ها را بین اعضای گروه به‌طور عادلانه توزیع می‌کند.
  • وقتی تعداد اعضای گروه تغییر می‌کند (مثلاً یک مصرف‌کننده جدید اضافه یا یکی خراب شود)، بار کاری را دوباره متعادل می‌کند.

وقتی مصرف‌کننده‌ای می‌خواهد به گروه بپیوندد، درخواستی به هماهنگ‌کننده می‌فرستد. اولین مصرف‌کننده‌ای که به گروه می‌پیوندد، رهبر گروه می‌شود. رهبر لیستی از همه مصرف‌کننده‌های فعال را از هماهنگ‌کننده می‌گیرد و پارتیشن‌ها را بین آن‌ها تقسیم می‌کند. مصرف‌کننده‌ها با ارسال ضربان قلب (heartbeats) به هماهنگ‌کننده، نشان می‌دهند که فعال هستند و پارتیشن‌هایشان را نگه می‌دارند.

تخصیص پارتیشن

هر مصرف‌کننده در گروه، تعدادی پارتیشن برای خواندن دریافت می‌کند. کافکا چند استراتژی برای تخصیص پارتیشن‌ها دارد:

  • محدوده‌ای (Range): روش پیش‌فرض است. تعداد پارتیشن‌های هر موضوع بین مصرف‌کننده‌ها تقسیم می‌شود. اگر تقسیم دقیق نباشد، چند مصرف‌کننده اول پارتیشن‌های بیشتری می‌گیرند (یعنی کار بیشتری انجام می‌دهند).
  • چرخشی (Round Robin): پارتیشن‌ها به‌ترتیب بین اعضای گروه تقسیم می‌شوند، مثل پخش کردن کارت‌های بازی. این روش تعداد بیشتری از مصرف‌کننده‌ها را درگیر می‌کند، اما اگر گروه تغییر کند، نیاز به جابه‌جایی زیادی دارد.
  • چسبنده (Sticky): شبیه روش چرخشی است، اما وقتی گروه تغییر می‌کند (مثلاً یک مصرف‌کننده اضافه یا حذف شود)، سعی می‌کند تخصیص‌های قبلی را حفظ کند. این روش تعادل را حفظ می‌کند و جابه‌جایی پارتیشن‌ها را کم می‌کند.
15
روش محدوده‌ای
152
روش چرخشی
153
روش چسبنده

تعادل مجدد (Rebalancing)

وقتی تعداد مصرف‌کننده‌ها تغییر می‌کند (مثلاً یک مصرف‌کننده جدید اضافه شود یا یکی خراب شود)، کافکا باید پارتیشن‌ها را دوباره بین مصرف‌کننده‌ها تقسیم کند. این فرآیند تعادل مجدد نام دارد:

  • تعادل مجدد مشتاق (Eager): همه مصرف‌کننده‌ها کارشان را متوقف می‌کنند، پارتیشن‌هایشان را رها می‌کنند و دوباره به گروه می‌پیوندند تا تخصیص جدیدی بگیرند. این روش باعث توقف کوتاه‌مدت کل گروه می‌شود.
  • تعادل مجدد همکاری‌محور (Cooperative): فقط بخشی از پارتیشن‌ها بین مصرف‌کننده‌ها جابه‌جا می‌شود، و مصرف‌کننده‌ها می‌توانند به خواندن پارتیشن‌هایی که تغییر نکرده‌اند ادامه دهند. این روش سریع‌تر و کم‌اختلال‌تر است.

ردیابی مصرف و ثبت افست

یکی از ویژگی‌های جالب کافکا این است که مصرف‌کننده نیازی به پیگیری پیام‌هایی که خوانده ندارد. در عوض، کارگزار این کار را انجام می‌دهد. مصرف‌کننده بعد از پردازش پیام‌ها، یک پیام تأیید (offset commit) به کارگزار می‌فرستد که نشان می‌دهد تا کدام پیام را با موفقیت خوانده است. کارگزار فرض می‌کند همه پیام‌های قبل از این نقطه پردازش شده‌اند و این اطلاعات را در یک موضوع داخلی ذخیره می‌کند.

روند ذخیره‌سازی ابری

طراحی کافکا به کش صفحه‌ای سیستم‌عامل وابسته است، یعنی ذخیره‌سازی و پردازش داده‌ها به هم گره خورده‌اند. این یعنی نمی‌توان ذخیره‌سازی را بدون اضافه کردن سرورهای جدید افزایش داد، که گاهی باعث هدر رفتن منابع می‌شود.

در گذشته که شبکه‌ها کندتر بودند و دیتاسنترهای محلی رایج‌تر بودند، این طراحی منطقی بود. اما در دنیای ابری (cloud) امروزی، این روش کمی چالش‌برانگیز است، چون هزینه‌های انتقال داده بین مناطق مختلف (cross-availability-zone) می‌تواند بالا باشد.

برای حل این مشکلات، ایده‌های جدیدی مطرح شده است. مثلاً شرکت اوبر پیشنهاد ذخیره‌سازی لایه‌ای (tiered storage) را داد که به کافکا اجازه می‌دهد:

  • داده‌های جدید را روی دیسک کارگزار (local storage) نگه دارد.
  • داده‌های قدیمی‌تر را به ذخیره‌سازی راه‌دور مثل HDFS، S3 یا GCS منتقل کند.

اخیراً روند استفاده از ذخیره‌سازی ابری (object storage) برای کافکا محبوب شده است. ابزارهایی مثل WarpStream، AutoMQ، Bufstream و Redpanda کافکا را طوری تغییر داده‌اند که مستقیماً روی ذخیره‌سازی ابری کار کند. مزایای این روش:

  • ذخیره‌سازی ارزان‌تر است.
  • پردازش و ذخیره‌سازی از هم جدا می‌شوند.
  • نیاز به کپی‌های اضافی داده (replication) از بین می‌رود، چون ذخیره‌سازی ابری خودش از داده‌ها محافظت می‌کند.

اخیراً شرکت Aiven با پیشنهاد KIP-1150 قابلیت جدیدی معرفی کرده که روش استفاده از کافکا را تغییر می‌دهد. این پیشنهاد به کافکا اجازه می‌دهد داده‌های یک موضوع را یا روی دیسک یا در ذخیره‌سازی ابری نگه دارد، که انعطاف‌پذیری زیادی به کاربران می‌دهد.

پ.ن:

خلاصه مقاله فوق را با تمامی مفاهیم اصلی و اشکال استفاده شده از پی دی اف زیر هم می توانید مطالعه کنید :

Reference

[۱] Jay Kreps, Neha Narkhede, Jun Rao, Kafka: a Distributed Messaging System for Log Processing (2011)

[۲] Gwen Shapira, Todd Palino, Rajini Sivaram, Krit Petty, Kafka The Definitive Guide Real-Time Data and Stream Processing at Scale (2021)

[۳] Kafka Official Documentation

[۴] Wikipedia – Memory-mapped file

[۵] Wikipedia – Page cache

[۶] Linux ate my ram

[۷] Andriy Zabolotnyy, How Kafka Is so Performant If It Writes to Disk? (2021)

[۸] Stanislav Kozlovski, Zero Copy Basics (2023)

[۹] Travis Jeffery, How Kafka’s Storage Internals Work (2016)

[۱۰] Confluent Document, Kafka Consumer Design: Consumers, Consumer Groups, and Offsets

[۱۱] Conduktor Blog, Kafka Partition Assignment Strategy (2022)

[۱۲] Redpanda Blog, Kafka partition strategy

[۱۳] Filip Yonov, Diskless Kafka: 80% Leaner, 100% Open (2025)

نوشته های مشابه