داده‌های جریانیمصاحبه ها

کافکا، بستر نوین جریان‌پردازی- مصاحبه با جون راو

این مطلب عیناً از وب سایت مطلبچه های مهندسی نرم افزار برداشته شده است که با همت جناب محمدعلی بزرگ زاده به زیبایی ترجمه شده است و مهندسی داده، با هدف جمع آوری مطالب مناسب فارسی در حوزه کلان داده به بازنشر آن پرداخته است .
در این اپیزود که در فوریه ۲۰۱۵ منتشر شده است، جف میرسون با جون راو در ارتباط با Apache Kafka مصاحبه می‌کند. جون راو پیش از این در LinkedIn مشغول بوده است و سپس به افتتاح شرکتی مبادرت کرده که کارش به شکل گسترده‌ای مبتنی بر Kafka است. او یک محقق و توسعه‌دهنده نرم‌افزار است و بیشتر زمانش را به تحقیق در حوزه‌های MapReduce، پایگاه‌های مقیاس‌پذیر، پردازش پرس‌وجوها و جنبه‌های دیگر انباره‌های داده (Datawarehouse) صرف کرده است. او طیہ چند سال گذشته از تثبیت‌کننده‌های کد (Commiter) در پروژه Kafka بوده است.
جون راو، به SE Radio خوش آمدی!
ممنونم جف که من را دعوت کردید.
بیا شروع کنیم و در مورد چند تا از تعاریف صحبت کنیم. شما جریان‌پردازی (Streaming) را چطور تعریف می‌کنید؟ و پیام‌رسانی (Messaging) را چطور؟
سئوال خوبی است. بر اساس دیدی که من دارم جریان‌پردازی، تاریخچه‌اش بیشتر برمی‌گردد به سیستم‌ها یا فریم‌ورک‌هایی که قابلیت پردازش یک یا چند دنباله از رخدادهای نامتناهی را فراهم می‌کنند. این سیستم‌ها برای پردازش این رخدادها، عموماً امکاناتی از قبیل جازدنِ (Plugin) منطق‌های شخصی‌شده (Customized Logic) فراهم می‌کنند، می‌توانید کارهایی از قبیل فیلتر کردن، تجمیع‌سازی‌ مبتنی بر پنجره‌های زمانی و یا الحاق‌ کردن جریان‌ها را انجام دهید. برخی فریم‌ورک‌هایی هم وجود دارند که کارهایی مانند موازی‌سازی را برایتان انجام می‌دهند و دیگر نیاز نیست که خیلی نگران موازی‌سازی‌ها باشید. این فریم‌ورک‌ها اغلب امکانات تحمل‌پذیری خطا هم فراهم می‌کنند و لازم نیست نگران از کار افتادن یکی از واحدهای پردازشی باشید زیرا فریم‌ورک می‌تواند بر روی یک ماشین دیگر دوباره یک پراسس برایتان اجرا کند. از دیدگاه من، این‌ها چیزهایی است که یک سیستم جریان‌پردازی به آن ارجاع دارد. براساس این تعریف، چیزهایی از قبیل Apache Storm و Apache Spark در این دسته قرار می‌گیرند، همینطور Apache Samza هم هست که در این دسته قرار می‌گیرد. این‌ها سیستم‌هایی هستند که فریم‌ورکی برای پردازش دنباله‌های نامتناهی از رخدادها فراهم می‌کنند.
حال، یکی از چیزهایی که این سیستم‌ها باید نگرانش باشند این است که داده‌ها را از کجا بیاورند؟ اینجاست که سیستم‌های پیام‌رسانی وارد می‌شوند. بنابراین یکی از راه‌های اصلی که این سیستم‌های جریان‌پردازی برای گرفتن داده‌ها دارند از سیستم‌های پیام‌رسانی یا سیستم‌های انتشار/عضویت (Publish/Subscribe) است. مثلاً در Apache Storm متداول‌ترین راه گرفتن داده‌ها از طریق Apache Kafka است که یک سیستم پیام‌رسانی است. در سیستم‌های جریان‌پردازی دیگر مانند Spark و Samza هم یکپارچه‌سازی‌ باKafka وجود دارد. این دید من در مورد ارتباط‌های مختلف بین سیستم‌های جریان‌پردازی و پیام‌رسانی است.
قیاس دیگری که وجود دارد مقایسه آن با دنیای Hadoop است. Hadoop دو بخش دارد. یکی بخش MapReduce است که فریم‌ورک پردازشی داده‌های برون‌خط (Offline) است و بخش دیگر، HDFS است که مکانیزم ذخیره‌سازی و تحویل‌دهی این داده‌ها است و این دو سیستم با روش غیرسفت و سختی به هم همبسته شده‌اند تا یک فریم‌ورک محاسباتی برون‌خط را فراهم کنند. شما می‌توانید سیستم‌های جریان‌پردازی را به مثابه MapReduce و سیستم‌های پیام‌رسانی مانند Kafka را معادل بخش HDFS آن ببینید اما با این تفاوت که این‌ها برای دنیای بلادرنگ هستند.
جالب است که می‌توانید اینطور توضیحش دهید که Kafka و Storm به نوعی دسته‌های از هم باز شده چیزهایی هستند که در حوزه‌های دیگر عموماً با هم هستند. بیا کمی در این مورد صحبت کنیم که Kafka چه چیزی است؟ جمع‌بندی که من پیدا کردم این است که یک سیستم پیام‌رسانی انتشار/عضویت است که به عنوان یک Commit Log توزیع‌شده بازنگری شده است. نظر شما در مورد این تعریف چیست؟ چرا شباهت برقرار کردن بین پیام‌رسانی و Commit Log توزیع‌شده مفید است؟
درست است که در تعریف سطح بالایش Kafka یک سیستم پیام‌رسانی انتشار/عضویت است اما امروزه مرز بین سیستم‌های پیام‌رسانی و انتشار/عضویت محو شده است. سابقاً سیستم‌های پیام‌رسانی بیشتر به سیستم‌هایی اطلاق می‌شد که نوعی توزیع پیام نقطه به نقطه داشتند، پیام در محلی انتشار می‌یافت و تحویل محل دیگری می‌شد اما در دنیای انتشار/عضویت این تفاوت وجود دارد که پیام‌ها می‌توانند چندین بار و بالقوه توسط مصرف‌کننده‌های مختلف، مصرف شوند. اما امروزه این مرزها محو شده است چرا که خیلی از سیستم‌ها می‌توانند هر دو ویژگی را پشتیبانی کنند.
اما چرا بین یک سیستم پیام‌رسانی و Commit Log قیاس می‌کنیم؟ فکر می‌کنم دو مطلب است. یکی اینکه در سطح خیلی بالا هر دو مورد سیستم پیام‌رسانی و Commit Log با دنباله‌ای از داده‌های فقط افزودنی (Append Only) سر و کار دارند. بنابراین الگوی دسترسی خیلی ساده‌ای دارند، برای اینکه داده‌ای را در این سیستم‌ها بنویسید تنها به افزودن داده‌های جدید ادامه می‌دهید، بروزرسانی وجود ندارد و فقط به افزودن چیزهای جدید ادامه می‌دهید. روش خواندن هم خیلی ساده است و عموماً این داده‌ها را تنها بصورت ترتیبی می‌خوانید. به خاطر چنین سادگی، مزایای زیادی هم فراهم می‌شود و می‌توانید چنین سیستم‌هایی را از لحاظ مقیاس‌پذیری و قابلیت اطمینان و کارایی به روش خیلی پربازدهی پیاده‌سازی کنید. این مشابهت اول است.
من از پس زمینه پایگاه داده می‌آیم. اغلب پایگاه‌های داده، Commit Log دارند. این Commit Log در‌واقع منبع حقیقت‌یابی (Source of Truth) از همه داده‌هایی است که در پایگاه داده‌تان ذخیره کرده‌اید. اگرچه ممکن است آن‌ها را برای همیشه نگه ندارید اما این جایی است که داده‌های اولیه وارد می‌شوند و از طریق آن می‌توانید همه داده‌هایی که در سیستم پایگاه داده‌تان دارید (مانند داده‌هایی که در جداول ذخیره می‌کنید و داده‌هایی که در ایندکس‌ ذخیره شده‌اند) را استخراج کنید. این در مورد سیستم‌های پیام‌رسانی هم صادق است. سیستم پیام‌رسانی نوعی منبع حقیقت‌یابی برای همه مصرف‌کننده‌ها و برنامه‌های پایین‌دستی است که داده‌ها را از سیستم پیام‌رسانی دریافت می‌کنند. این مشابهت دوم بین یک سیستم‌ پیام‌رسانی و Commit Log است.
بسیار خوب، Kafka در مقایسه با سیستم‌های سنتی‌تر پیام‌رسانی از قبیل RabbitMQ و ActiveMQ چگونه است؟
این سئوال خوبی است که زیاد از ما پرسیده می‌شود. من این‌طور جمع‌بندی می‌کنم که دو تفاوت اصلی وجود دارد که در آن، Kafka کمی مزیت دارد. یکی این است که Kafka واقعاً برای حجم زیاد داده طراحی شده است، سیستم‌های سنتی‌تر عموماً تنها مسئول ذخیره‌سازی داده‌هایی بودند که در پایگاه داده تولید می‌شد اما Kafka برای ذخیره‌سازی مواردی از قبیل آمارهای سنجش کسب‌وکار (Business Metrics)، لاگ‌های سرویس‌ها، آمارهای سنجش عملیاتی (Operational Metrics) و … بوده است، این نوع داده‌ها از لحاظ حجم ۱۰۰ یا ۱۰۰۰ برابر بزرگ‌تر از داده‌هایی هستند که در پایگاه داده ذخیره می‌کنید. این‌ها چیزهایی نیست که سیستم‌های پیام‌رسانی سنتی برایش طراحی شده باشد اما Kafka واقعاً برای این‌ها طراحی شده است. برای مثال Kafka از ابتدا به عنوان یک سیستم توزیع‌شده طراحی شده است بنابراین اگر حجم داده‌ها افزایش یابد می‌توانید به راحتی ماشین‌های بیشتری به کلاستر اضافه کنید تا آن حجم داده را رسیدگی کنید و همینطور در مؤلفه‌های مختلف می‌توانیم چند بهینه‌سازی مختصر از قبیل فشرده‌سازی و دسته‌کردن (Batching) داشته باشیم تا بتوانیم این حجم از داده‌ها را به شکل کاراتری رسیدگی کنیم.
کاملاً منطقی است. از ابتدا به حجم داده‌ها نظر داشته‌اید و به این نتیجه رسیده‌اید که نیاز به چیزی دارید که کاملاً بزرگ‌تر از چیزهایی مانند ActiveMQ و RabitMQ باشد.
بله، می‌توانید آن را یک نسخه از سیستم‌های پیام‌رسانی برای داده‌های عظیم در نظر بگیرید. این تفاوت اول است. تفاوت دوم که آن هم مهم است، این است که سیستم‌های پیام‌رسانی سنتی تنها برای کاربردهای بلادرنگ طراحی شده بودند. اما در Kafka نه تنها آن کاربردهای بلادرنگ را داریم بلکه یکی از مصرف‌کننده‌های مهم یا برنامه‌های پایین‌دستی Kafka، تغذیه کردن لوله‌های برون‌خط (Offline) است. یکی از مهمترین آن‌ها، Hadoop است. افراد از Kafka برای وارد کردن داده‌ها به سیستم‌های Hadoop استفاده می‌کنند. در این موارد، سیستم‌هایی داریم که هم به کاربردهای بلادرنگ و هم کاربردهای غیر بلادرنگ و یا دسته‌ای (Batch) نیاز دارند. بسیاری از سیستم‌های سنتی پیام‌رسانی از آنجاییکه برای کاربردهای بلادرنگ بهینه شده‌اند، همه پیام‌ها یا پیام‌های مصرف‌نشده را در حافظه بافر می‌کنند. حال فرض کنید که یک مصرف‌کننده پایین‌دستی مانند Hadoop داشته باشید که برای چندین ساعت در حال تعمیر باشد، در آنصورت نمی‌توانید این همه داده را در کارگزار پیام مربوطه بافر کنید. به همین علت برای بسیاری از کاربردهای مربوط به مصرف‌کننده‌های برون‌خط، کارایی سیستم‌های پیام‌رسانی سنتی به مراتب کمتر است.
آیا شما Kafka را به عنوان یک سیستم پیام‌رسانیِ انباره داده (Datawarehouse) توصیف می‌کنید؟ یا این تعریف خیلی محدود است؟
فکر می‌کنم می‌توانید آن را یک انباره داده در نظر بگیرید اما در‌واقع جایی است که می‌توانید هر نوع داده‌ای را جمع‌آوری کنید و با آن داده‌ها، پلتفرم‌های مختلفی را تغذیه کنید. یکی از مهمترین جاهایی که می‌توانید تغذیه کنید پلتفرم‌های مربوط به انباره‌های داده برون‌خط است اما در عین حال می‌توانید از همان سیستم برای تغذیه پلتفرم‌های بلادرنگ‌‌تر هم استفاده کنید. نقطه ترکیب برای هر دو نوع مصرف برون‌خط و بلادرنگ است.
بسیار خوب، حال که برای مخاطبین ایده اساسی Kafka را گفتیم بیا در مورد اصطلاحات اصلی در Kafka صحبت کنیم و بحث را به نحوه کارکرد آن بکشیم. شاید بتوانید بگویید که برخی مؤلفه‌های اصلی Kafka چگونه کار می‌کنند، آیا ممکن است کمی در مورد موضوع‌ها (Topic)، تولید‌کننده‌ها (Producer)، مصرف‌کننده‌ها (Consumer) و کارگزارها (Broker) صحبت کنید؟
بله، از دیدگاه خیلی سطح بالا، Kafka مانند سیستم‌های پیام‌رسان سنتی دیگر است و یک مفهوم ۳ لایه دارد که در وسط آن لایه کارگزار را داریم که در‌ واقع جایی است که پیام‌ها ذخیره و رسیدگی می‌شوند. از طرفی لایه تولید‌کننده را داریم که منتشرکننده‌های پیام هستند و همینطور مصرف‌کننده‌ها را داریم که سیستم‌هایی هستند که برای یک یا چند منبع داده، ثبت‌نام می‌کنند که چه داده‌هایی به آن‌ها تحویل شود. این‌ها در سطح خیلی بالا، ۳ لایه‌ای از موجودیت‌ها هستند که در Kafka وجود دارند.
موضوع‌ها (Topic) در‌ واقع واحدهای منطقی برای تعریف منابع مجزا هستند، شما می‌توانید هر موضوع را متناظر با یک صف مجازی در نظر بگیرید. وقتی شما پیامی را منتشر می‌کنید در‌ واقع آن را در یک موضوع منتشر می‌کنید و بعد داده‌های‌تان در یکی از این صف‌های مجازی اضافه می‌شود و عموماً برای یک یا چندتا از آن موضوع‌ها ثبت‌نام می‌کنید تا پیام‌هایشان را دریافت کنید.
همین‌طور یک مفهوم سطح پایین دیگر به نام پارتیشن‌ دارید که به موضوع انتساب می‌یابد. هر موضوع می‌تواند از لحاظ فیزیکی یک یا چند پارتیشن داشته باشد. وجود پارتیشن‌ها، به علت امکان موازی‌سازی است. می‌توانید این‌طور در نظر بگیرید که یک کانال مجازی داریم که به یک یا چند کانال یا صف فیزیکی تفکیک می‌شود و این زیرکانا‌ل‌ها یا زیرصف‌ها می‌توانند بصورت مستقل بر روی ماشین‌های مختلف ذخیره شوند و به این طریق در سیستم، موازی‌سازی بیشتری حاصل می‌شود.
وقتی از موازی‌سازی صحبت می‌کنید به منظور افزونگی (Redundancy) یا تحمل خطا (Fault Tolerant) است و یا بیشتر به این علت است که سرعت افزایش یابد؟
فکر می‌کنم بیشتر به این خاطر است که سرعت افزایش یابد، به این ترتیب که منطقاً پارتیشن‌های مختلف می‌توانند بصورت مستقل، مصرف کنند. هرچه پارتیشن‌های بیشتری داشته باشید برای هم مصرف‌کننده‌‌ها و هم کلاینت‌ها، کانال‌های موازی بیشتری خواهید داشت. به این ترتیب درجه موازی بودن را افزایش می‌دهید. هر پارتیشن می‌تواند رونوشت‌برداری (Replicate) هم بشود و این راهی است که برای فراهم کردن قابلیت اطمینان در سیستم می‌توانیم استفاده کنیم اما این مسأله، ارتباطی با موازی‌سازی ندارد.
پیام‌رسانی عموماً دو مدل دارد: صف کردن (Queueing) و انتشار/عضویت (Publish/Subscribe). در روش صف کردن، انبوهی از مصرف‌کننده‌ها را داریم که از سرور می‌خوانند و هر پیام تنها به یکی از مصرف‌کننده‌ها می‌رود. مثلاً ممکن است لیستی از وظایف داشته باشید که سرور می‌خواهد هر کدام تنها یک بار انجام شوند. اما در انتشار/عضویت، پیام‌ها به همه مصرف‌کننده‌ها ارسال می‌شود. Kafka تنها یک انتزاع از مصرف‌کننده دارد که گروه‌های مصرف‌کننده‌ خوانده می‌شود و حالت عمومیت‌یافته هر دو مورد است. ممکن است کمی در مورد گروه‌های مصرف‌کننده و نحوه عملکردشان صحبت کنید؟
بله، فکر می‌کنم گروه‌های مصرف‌کننده خیلی جالب هستند. همانطور که شما گفتید هر دو مورد الگو‌های کاربرد را پوشش می‌دهد. یک مورد این است که تنها یک گروه مصرف‌کننده داشته باشید و در آن چندین مصرف‌کننده داشته باشید که مشترکاً یک نوع از موضوع را مصرف کنند. مثلاً می‌توانید دو مصرف‌کننده در یک گروه مصرف‌کننده داشته باشید و امید داشته باشید که آن موضوع، بصورت مساویِ نصف و نصف بین آن دو مصرف‌کننده تقسیم شود. این روشی برای افزایش درجه موازی‌سازی بین مصرف‌کننده‌ها است. مورد کابرد دیگر آنجا است که منطقی که برای مصرف وجود دارد کمی CPU بَر یا زمانبر باشد. در اینصورت اگر مصرف‌کننده‌های بیشتری داشته باشید، می‌توانید از قدرت CPU و منابع بیشتر استفاده کنید تا سرعت پردازش داده‌ها را افزایش دهید. این یک مورد کاربرد است.
مورد کاربرد دیگر این است که چندین گروه مصرف‌کننده بر روی یک موضوع داشته باشید که نوعی مدل چندعضویتی است. در این حالت، هر گروه مصرف‌کننده‌ای، بصورت کامل با همه داده‌های آن موضوع، تغذیه می‌شوند. موارد زیادی وجود دارد که نرم‌افزارهای مختلف می‌خواهند داده‌های یکسانی را مصرف کنند اما بر اساس کاربردشان به روش‌های متفاوتی آن‌ها را پردازش کنند و این مدل چندعضویتی، روش خیلی قدرتمندی برای این نرم‌افزارها برای مصرف داده‌ها بصورت مستقل از یکدیگر است. در‌ واقع شما می‌توانید در این مدل چندعضویتی در هر کدام از این گروه‌های مصرف‌کننده هم، چندین مصرف‌کننده داشته باشید تا بتوانید ترکیب مزایای چندعضویتی و موازی‌سازی در هر کدام از این نمونه‌های مصرف را داشته باشید.
چه جنبه‌های دیگری از ارتباط بین تولید‌کنندگان و مصرف‌کنندگان، منحصر به Kafka است؟
اگر Kafka را با سیستم‌های پیام‌رسانی سنتی مثلاً GMS مقایسه کنید ما یک سری چیزها را نداریم، GMS مجموعه امکانات گسترده‌ای از قبیل تحویل مرتب‌شده (Ordered Delivery)، اولویت (Priority) و … را دارد که ما در Kafka نداریم. همانطور که قبلاً گفتم Kafka واقعاً برای حجم بالای داده‌ها و رسیدگی به آن‌ها با یک روش کارا طراحی شده است به همین خاطر ما بسیاری از امکانات موجود در سیستم‌های پیام‌رسانی سنتی را نداریم.
آیا این نتیجه می‌دهد که برخی موارد کاربرد مشخص وجود دارد که انتخاب Kafka به عنوان سیستم پیام‌رسانی معنی نمی‌دهد؟
بله، بستگی به کاربردتان دارد. از یک طرف Kafka امکانات اصلی که خیلی از نرم‌افزارها می‌خواهند داشته باشند را داراست. مثلاً امکان تضمین تحویل: API های سمت تولید‌کننده به شما امکان می‌دهند که تنظیم کنید وقتی پیامی را منتشر می‌کنید چه زمانی بتوانید تأییدیه (Acknowledge) آن را بگیرید. روش‌های مختلفی که برای گرفتن تأییدیه وجود دارد، تضمین‌های مختلفی در ارتباط با مانایی (Durability) فراهم می‌کند. این‌ها چیزهایی است که خیلی از کاربران برای کاربردهای‌شان استفاده می‌کنند.
اما آنچه ما نداریم برخی چیزهای دیگر از قبیل اولویت دادن و تحویل خارج از نوبت است. اگر چنین نیازهایی دارید یا باید خودتان آن را پیاده‌سازی کنید و یا از سیستم پیام‌رسانی دیگری استفاده کنید که چنین امکاناتی را داشته باشد.
از دیدگاه وسیع‌تر یا تاریخچه‌ای، طی چند سال گذشته پلتفرم‌های زیادی ارائه شده است که ما تا اینجا به چند مورد از آن‌ها اشاره کردیم. شما در خط مقدم توسعه‌دهندگان اینگونه چیزها قرار دارید. چه تغییراتی را در آینده می‌بینید؟ در این حوزه چه تکاملی می‌بینید؟
این هم سئوال جالبی است. من دو فاکتور مهم که تغییر کرده است را می‌بینم. یکی میزان داده‌هایی است که افراد جمع می‌کنند. در گذشته‌ها، اکثر داده‌هایی که افراد به آن‌ها علاقه نشان می‌دادند تنها داده‌های پایگاه داده‌ بود اما در ۱۰ یا ۱۵ سال گذشته افراد آغاز به جمع‌آوری چیزهای دیگری کردند که ما به آن کلان‌داده‌ها (Big Data) می‌گوییم. این داده‌ها چه هستند؟ این‌‌ها به عنوان نمونه، آمارهای کسب‌وکار (Business Metrics) مثلاً میزان مشاهده صفحات وب، تأثیرپذیری‌ها، کلیک‌ها، کلیدهای جستجوی تایپ‌شده توسط افراد، است. همینطور شامل آمارهای عملیاتی (Operational Metrics) از قبیل وضعیت I/O، وضعیت CPU و … است. همینطور شامل سرویس‌های لاگ از قبیل log4j و لاگ‌های سیستمی و همه جور سرویس‌های لاگ هم می‌شود. از لحاظ حجم داده‌ها، چنین داده‌هایی به راحتی ۱۰ یا ۱۰۰ برابر بیشتر از داده‌هایی هستند که در پایگاه داده‌های سنتی ذخیره می‌شدند. از لحاظ میزان ارزش، این داده‌ها دیدی ایجاد می‌کنند که برای خیلی از نرم‌افزارهای پایین‌دستی ارزشمند است. بنابراین این گرایش اول است.
سئوال این است که چرا اخیراً افراد چنین داده‌هایی را جمع می‌کنند؟ چرا ۱۵ یا ۲۰ سال قبل این‌طور نبوده است؟ این مربوط به ُبروز سیستم‌های تخصصی مقیاس‌پذیر عمودی است. مثلاً Hadoop یک سیستم تخصصی مقیاس‌پذیر برای پردازش‌های برون‌خط است. به صورت سنتی یکی از جاهایی که چنین کارهایی را می‌توانستید انجام دهید در Oracle و Teradata است که گران است. اما آنچه Hadoop انجام داد خیلی خاص بود. آن‌ها تنها یک جنبه که همان پردازش‌های برون‌خط بود را در نظر گرفتند و آن را بر روی سخت‌افزارهای عادی (Commodity) مقیاس‌پذیرتر کردند. در نتیجه توانستند یک راه حل پردازش برون‌خط با یک روش اقتصادی‌تر فراهم کنند در واقع، افراد اگر بخواهند در Hadoop پردازش برون‌خط داشته باشند نمی‌توانند از عهده ذخیره‌سازی چنین حجم بالایی از داده برآیند. اما با این روش مجبور نیستید تجهیزات گرانقیمت Oracle یا Teradata را بخرید. چنین جریانی نه تنها در دنیای پردازش‌های برون‌خط رخ داده بلکه در دیگر حوزه‌های تخصصی نیز آغاز شده است. مثلاً برای جستجو، ElasticSearch وجود دارد که یک نسخه مقیاس‌پذیر بر روی سخت‌افزارهای عادی در حوزه جستجو است یا مثلاً در مورد ذخیره‌گاه‌های کلید-مقدار (Key-Value Store) سیستم‌های زیادی وجود دارد که قابلیت ذخیره‌سازی و بازیابی داده‌ها به یک روش اقتصادی و مقیاس‌پذیر بر روی سخت‌افزارهای عادی را دارد. و یا موتورهای گراف (Graph Engine) مثلاً سیستم‌هایی که می‌توانند پردازش‌های گرافی داشته باشند را درنظر بگیرید، آن‌ها را هم می‌توان بر روی سخت‌افزارهای عادی به یک روش اقتصادی انجام داد. و یا سیستم‌های جریان‌پردازی (Streaming) متعددی وجود دارند که آن‌ها هم برای اجرا بر روی سخت‌افزارهای عادی طراحی شده‌اند که می‌توان به یک روش اقتصادی‌تر، مقیاس‌شان را بزرگ کرد.
آیا فکر نمی‌کنید که هزینه ذخیره‌سازی این نوع داده‌ها مستقل از اینکه از عهده ذخیره‌ کردنش بر می‌آیید یا نه، به این جنبه برمی‌گردد که مجبورید آن‌ها را تعمیر و نگهداری کنید؟
فکر می‌کنم هر دو جنبه به مقدار کافی اهمیت دارند. اولی مربوط به هزینه اولیه است که خرید نرم‌افزار و سخت‌افزار متناظرش چه هزینه‌ای برای‌تان دارد. اگر نرم‌افزارتان رایگان یا متن‌باز باشد و بتواند بر روی سخت‌افزارهای عادی اجرا شود، نسبت به حالتی که مجبورید برای برای نرم‌افزار تجاری، هزینه اضافه‌تری بپردازید خیلی ارزانتر خواهد بود. این جنبه اول آن است. مورد دوم این است که وقتی سیستم فراهم شد حال باید با آن کار کنید. هر چه کلاستر بزرگ‌تری داشته باشید سربار مانیتور کردن و عملیاتی کردن آن بیشتر است. ابزارهای زیادی وجود دارد که قطعاً در این زمینه کمک می‌کند. اگر ابزارها و مانیتورگر‌های خوبی فراهم باشد، در آنصورت دیگر واقعاً اهمیت ندارد که بخواهید کلاستری از ۱۰ گره را مانیتور کنید یا کلاستری از ۱۰۰ گره را مانیتور کنید زیرا چیزهای زیادی هستند که با امکان هشداردهی مناسب با هم یکپارچه شده و امکان مانیتور کردن برقرار می‌شود. به این طریق مسلماً می‌توانید هزینه‌های عملیاتی چنین سیستم‌هایی را کاهش دهید.
بسیار خوب، بیا کمی عقب برگردیم تا به صورت خاص در مورد Kafka صحبت کنیم. شما به مثال‌های انتزاعی از Kafka اشاره داشتید. شاید بهتر باشد به سراغ برخی کاربردهای مشخص Kafka برویم. توضیح دهید که اگر کسی می‌خواهد Kafka را مستقر کند چطور این کار را انجام داده و به دیگر مؤلفه‌ها متصل می‌کند.
از دیدگاه سطح بالا این به تغییرات در گرایشات صنعت برمی‌گردد که پیش از این اشاره کردم یعنی به خاطر وجود و یا بروز سیستم‌های مقیاس‌پذیر تخصصی مختلف است. این سیستم‌ها نیاز دارند که با نوع یکسانی از داده‌ها تغذیه شوند. مثلاً اگر مجموعه‌ای از داده‌های لاگ داشته باشیم، حتماً می‌خواهید آن‌ها را برای پردازش برون‌خط به Hadoop وارد کنید، اما با همان درجه از اهمیت می‌خواهید آن را به سیستم جستجوی‌تان نیز وارد کنید تا بتوانید با سرعت، هر رخداد لاگی را جستجو کنید. این تا حدود زیادی همان منطق کاری است که Splunk انجام می‌دهد. به همین ترتیب اگر مثلاً جریانی از داده‌های عملیات داشته باشید می‌خواهید که هم آن را به سیستم برون‌خط وارد کنید و هم البته آن را به سیستم بلادرنگ مانیتور خود وارد کنید تا بتوانید آن داده‌ها را مانیتور کرده و از آن‌ها نمودار بکشید. حال سئوال این است که این سیستم‌های مستقل، داده‌های خود را از کجا بیاورند؟ شما به یک نقطه یکپارچه‌سازی نیاز دارید که همه این سیستم‌ها بتوانند داده‌های‌شان را از آن بگیرند. خیلی از آن سیستم‌ها بر خلاف Hadoop بیشتر جنبه بلادرنگ دارند بنابراین نمی‌توانید آن‌ها را در همان انباره داده برون‌خط خود یکپارچه کنید زیرا از لحاظ تأخیر (Latency)، ممکن است به مقدار کافی خوب نباشند که داده‌های نرم‌افزارها یا پلتفرم‌های بلادرنگی در ارتباط با مثلاً جستجو و یا رسم نمودار را تغذیه کنند. Kafka به نوعی این نقش را پر می‌کند، زیرا سیستمی است که در واقع برای جمع‌آوری و ذخیره‌سازی حجم بالای داده طراحی شده است و می‌تواند هر تعداد نرم‌افزار پایین‌دستی را تغذیه کند و این نرم‌افزارها هم می‌توانند بلادرنگ و هم می‌توانند برون‌خط باشند. بنابراین می‌توانید آن را به مثابه یک هاب یکپارچه‌سازی برای همه این کلان‌داده‌ها در نظر بگیرید.
از منظر نحوه به خدمت گرفتن Kafka می‌بینیم که افراد چیزهای مختلفی را برمی‌گزینند. یکی از موارد کاربرد رایج این است که از Kafka به عنوان یک خط لوله مصرف استفاده می‌کنند تا داده‌ها را وارد Hadoop کنند. اما در عین حال یک یا چند نرم‌افزار برای کاربردهای بلادرنگ هم دارند که می‌تواند یک نرم‌افزار بلادرنگ و یا یکی از فریم‌ورک‌های پردازش جریان باشد و یا گاهی سیستم جستجویی باشد که به خدمت گرفته‌اند. به خاطر نیاز به بیش از یک کاربرد برای داده‌های یکسان، برایشان خیلی اهمیت دارد که این خط‌های لوله را به کار بیاندازند. این یک الگوی رایج از نحوه به خدمت‌گیری Kafka است که ما می‌بینیم.
آیا پیاده‌سازی دیده‌اید که شما را خیلی غافلگیر کند؟ که شاید جهت پروژه را عوض کند؟ که دلیلی برای اضافه کردن برخی ویژگی‌هایی که پیش‌بینی نکرده بودید معرفی کند؟
با بکارگیری بیشتر و بیشتر Kafka، ویژگی‌های زیادی تا الان وجود دارد که ما می‌دانیم که نیاز است. چیزهایی از قبیل امنیت وجود دارد که اهمیت دارد. در این حوزه، از لحاظ درخواست ویژگی‌های بعدی، تعداد خیلی زیادی ویژگی یا نیازمندی غافلگیرکننده نمی‌بینیم اما گاهی از نظر روشی که افراد از سیستم استفاده می‌کنند غافلگیر می‌شویم. موارد زیادی هست که ما برنامه‌ریزی نکرده‌ بودیم که افراد به این روش از آن استفاده کنند اما افراد به هر روش از آن استفاده می‌کنند. گاهی مورد استفاده‌شان واقعاً ایده‌آل نیست و گاهی هم ما واقعاً غافلگیر می‌شویم که وقتی به آن شکل از آن استفاده می‌کنند، Kafka کار می‌کند. به عنوان مثال یکی از چیزهایی که ما را غافلگیر کرد این بود که دست‌کم یک بار به این شکل از Kafka استفاده شده بود که از آن به عنوان یک مکانیزم تحویل پیام برای پیام‌های بسیار حجیم در حد گیگابایت استفاده کرده بودند. البته می‌توانید Kafka را برای چنین کارهایی تنظیم کنید اما قطعاً این چیزی نیست که ما آن را برایش طراحی کرده باشیم. ما غافلگیر شدیم که افراد چنین استفاده‌ای می‌کنند و کار می‌کند. موارد دیگری هست که افراد از Kafka به مانند یک ذخیره‌گاه کلید-مقدار استفاده می‌کنند به این ترتیب که بصورت تصادفی پیام‌های رسیده از جاهای مختلف را مصرف می‌کنند. این می‌تواند کار کند اما واقعاً چیزی نیست که Kafka برای آن طراحی شده باشد. برای چنین موارد کاربردی احتمالاً ذخیره‌گاه کلید-مقدار مناسب‌تر است.
بله، این واقع غافلگیرکننده است. مانند این است که چون چکش دارید همه چیز را میخ ببینید!
همینطور است.
در یک مقاله در مورد Kafka که در سال ۲۰۱۱ منتشر شده است، بین داده‌های نرم‌افزار و داده‌های لاگ تفاوت قائل شده است. با گذشت زمان، این تفاوت، کمتر به چشم می‌آید. آیا فکر می‌کنید که همچنان به Kafka به عنوان یک ابزار انتشار پیام‌های لاگ نگریسته می‌شود؟ یا اینکه امروزه نسبت به ۳ سال قبل کمتر قابل پذیرش است که رکوردهای لاگ دور ریخته شوند؟
عموماً دیده‌ایم که بکارگیری Kafka ابتدا برای محل قرارگیری داده‌های لاگ آغاز می‌شود. این در‌واقع همان چیزی است که Kafka برایش طراحی شده است و روش قدرتمندی برای ذخیره کردن و رسیدگی به این حجم بزرگ داده‌ها است. به همین جهت شاید اشکالی نداشته باشد که برای داده‌های لاگ هر از چندگاهی، تعداد اندکی از پیام‌ها را از دست بدهید. بعد با‌گذشت زمان وقتی شما بتوانید خط لوله‌ای داشته باشید که حجم زیادی از داده‌ها را رسیدگی کند، افراد به این فکر می‌افتند که چرا دیگر داده‌های‌شان شامل داده‌های برنامه یا پایگاه داده‌شان را نتوانند داخل این خط لوله بیاورند. برای این داده‌های بغیر از لاگ، تضمین‌های مانایی و قابلیت اطمینان، شدید‌تر است. این یک جنبه‌اش است.
مطلب دیگر این است که وقتی داده‌ها را در Kafka منتشر می‌کنید یکی از کارهایی که می‌توانید انجام دهید این است که به جای اینکه یک توزیع تصادفی داشته باشید، پارتیشن‌بندی معنایی (Semantic Partitioning) داشته باشید. برای برخی نرم‌افزارها شاید بخواهید که به همه پیام‌ها یک شناسه کاربر انتساب داده شود و بخواهید که همه پیام‌ها [ی مربوط به یک کاربر] توسط یک مصرف‌کننده، مصرف شود. سرراست‌ترین راهی که می‌توانید این کار را بکنید این است که پیام‌ها را بر اساس این کلید پارتیشن‌‌بندی، که می‌تواند شناسه کاربر باشد، پارتیشن کنید و به این ترتیب تضمین کنید که همه پیام‌هایی که متعلق به یک شناسه کاربر هستند در یک پارتیشن قرار می‌‌گیرند و در نتیجه تنها توسط یک مصرف‌کننده، مصرف می‌شوند. برای انجام چنین کارهایی باید هر کدام از این پارتیشن‌ها کاملاً در دسترس و قابل اطمینان شوند؛ زیرا تصور کنید که یکی از این پارتیشن‌ها در دسترس نباشد و پیامی داشته باشید که از لحاظ معنایی بر اساس کلیدش باید در آن پارتیشن قرار بگیرد، حال چه می‌کنید؟ یا مجبورید آن را دور بریزید یا اگر آن را به پارتیشن دیگری نگاشت دهید، لازم می‌شود که مفهوم معنایی آن را تغییر دهید که هیچکدام مطلوب نیست. به همین خاطر حتی اگر بخواهید فقط داده‌های لاگ داشته باشید، هر دو مورد قابلیت اطمینان و مانایی به یک میزان اهمیت می‌یابند. به همین علت طی چند سال گذشته حجم قابل توجهی از زمان کار بر روی Kafka را صرف اضافه کردن پشتیبانی از مانایی و قابلیت اطمینان کردیم. آنچه انجام دادیم این است که برای هر پارتیشن Kafka می‌توانید چندین رونوشت (Replica) داشته باشید و وقتی پیامی را منتشر می‌کنید، رونوشت‌های مضاعفی از آن و عموماً بر روی کارگزارهای مختلفی نوشته می‌شوند. در Kafka منطقی تدارک دیده شده است که بتواند در صورت خرابی، هرکدام از این کارگزارهای مستقل، به عمل‌کرد قبلی‌اش ادامه دهد بنابراین از دیدگاه کاربر نهایی یعنی هم تولیدکننده و هم مصرف‌کننده مانند این است که هیچ اتفاقی نیافتاده است زیرا درون آن، خود سیستم، اتصال را از کلاینت به یک کارگزار زنده که کپی یکسانی از داده دارد، منتقل می‌کند. این یکی از چیزهای مهمی است که ما به Kafka اضافه کردیم.
آیا این با ZooKeeper انجام می‌شود؟
بله، ما از ZooKeeper برای ذخیره‌سازی برخی اطلاعات مهم مربوط به وضعیت پارتیشن‌ها استفاده کردیم. از لحاظ حجم، داده‌های زیادی نیست، شاید چند بایت اطلاعات باشد که برای هر پارتیشن از یک موضوع، نیاز داریم ذخیره کنیم. اطلاعات حیاتی از قبیل اینکه چه کسی پیشوای یک پارتیشن است. در دنیای رونوشت‌برداری، شما عموماً چندین رونوشت دارید که به یک پارتیشن نسبت داده می‌شود که یکی از آن‌ها به عنوان پیشوا است که حقوق مالکیت را اخذ می‌کند و رونوشت‌های دیگر پیروان (Follower) هستند که داده‌ها را از پیشوا دریافت می‌کنند. بنابراین هنگام خرابیِ پیشوا، نیاز داریم که به سرعت پیشوای جدیدی انتخاب کنیم و به صورت مستمر، داده‌ها را از پیشوای جدید بفرستیم. ما از ZooKeeper استفاده می‌کنیم تا اطلاعاتی از این قبیل را ذخیره کنیم که پیشوای کنونی یک پارتیشن کیست و در صورت خرابی پیشوای اصلی، چه کسی کاندیدای محتمل برای تبدیل شدن به پیشوای جدید است.
این توانایی در استفاده از آن جالب به نظر می‌رسد، نمی‌دانم چه مقدار انرژی صرف ZooKeeper شده است اما به نظر می‌رسد مقدار زیادی باشد. این من را به یاد بحثی می‌اندازد که شما پیشتر مطرح کردید که Kafka و Storm شبیه به مؤلفه‌های گسسته‌شده از Hadoop هستند. جالب است که الان ZooKeeper یک مؤلفه اساسی در Kafka است. همه این‌ها موجب می‌‌شود که من به این فکر بیافتم که آيا در آینده می‌توان برخی از انواع مؤلفه‌ها (چه متن‌باز و چه غیر از آن)‌ را دید که بر روی Kafka ساخته شده باشند؟
بله، نکته خوبی است. الان می‌توانید Kafka را جایی در نظر بگیرید که منبع تغذیه داده‌ها است و با توجه به قابلیت اطمینان و مانایی که ما فراهم می‌کنیم برای افراد این امکان فراهم شده است که داده‌هایی که نقش منبع حقیقت‌یابی دارند را در آن ذخیره کنند. از یک منظر می‌توان آن را به مانند Commit Log در دنیای پایگاه داده دانست. از منظر منبع حقیقت‌یابی، بالقوه سیستم‌های زیادی را می‌توان بر روی آن ساخت تا از داده‌ها تغذیه شده و آن را به فرمتی تبدیل کنند که برای پردازش در یک حوزه خاص، ساده‌تر باشد. سیستم‌هایی مثلاً سیستم‌های ذخیره‌گاه کلید-مقداری (Key-Value Store) بوده‌اند که به نوعی Commit Log توزیع‌شده-به عنوان یک محور- برای ذخیره و ترمیم (Recovery) داده‌ها متکی هستند. ما امتحانش نکرده‌ایم اما امکانپذیر است که از Kafka به عنوان نوعی Commit Log و منبع حقیقت‌یابی استفاده کرد و حول آن سیستم‌های دیگری مثلاً یک ذخیره‌گاه کلید-مقدار یا سیستم ذخیره‌سازی دیگر داشت.
چون فکر می‌کنم در بحث ما اهمیت زیادی دارد، اگر به بحث مدل Pub/Sub برگردیم، در آنجا هر موضوع (Topic) مشابه با یک کانال انتشار است و آنطور که من متوجه شدم هر کدام از این موضوع‌ها یک یا چند پارتیشن دارند که [هر پارتیشن] بلاکی از حافظه است که تخصیص یافته و پیام‌های جدید در آن افزوده می‌شوند. در هر مقطع زمانی، اعضایی (Subscriber) برای آن موضوع وجود دارند که تا جای مشخصی از آن پارتیشن را مصرف کرده‌اند. آیا این توضیح دقیقی در مورد نحوه عمل‌کرد کانال‌ها و پارتیشن‌ها است؟
صد در صد دقیق نیست. توجه کنید که Kafka هم برای مصرف بلادرنگ و هم مصرف برون‌خط بهینه‌سازی شده است بنابراین یکی از چیزهایی که نیاز به فکر داشت، در مورد بافر کردن پیام‌ها بود. اگر همه پیام‌های مصرف‌نشده را در حافظه بافر کنید، پشتیبانی از کاربردهای برون‌خط را محدود می‌کند زیرا حافظه محدود است و اگر مصرف‌کننده‌ای برای مدت طولانی، در دسترس نباشد، نمی‌توانید همه چیز را بافر کنید. بنابراین ما در کارگزار (Broker) حافظه زیادی از فضای Heap را برای ذخیره‌سازی پیام‌ها تخصیص‌دهی نمی‌کنیم. هر زمانی که تعدادی پیام از تولیدکننده دریافت می‌کنیم خیلی راحت آن را به کانال فایل متناظر بر روی دیسک محلی می‌افزاییم. البته ما داده‌ها را بلافاصله فلاش نمی‌کنیم، به منظور افزایش کارایی، فلاش داده‌ها بر روی دیسک را بصورت پریودیک انجام می‌دهیم اما ما کپی آن را در Heap مربوط به JVM نگه نمی‌داریم. در‌واقع ما آن را بلافاصله در فایل سیستم می‌ریزیم اما بیشتر مواقع فایل سیستم، کش صفحات (Pages Cache) خودش را دارد و این شانس وجود دارد که داده‌ها در حافظه باشند البته در کش صفحاتی که توسط خود فایل سیستم مدیریت می‌شود اما ما مجبور نیستیم که آن را در فضای Heap مربوط به JVM مدیریت کنیم که این کار از لحاظ میزان کردن GC و مسائل دیگر بهتر است.
در مورد مصرف‌کننده هم کارهای مشابهی می‌کنیم. ما از یک API استانداردشده UNIX استفاده می‌کنیم تا داده‌ها را از کانال فایل محلی مستقیماً به سوکت ریموت بفرستیم. از منظر مصرف‌کننده هم مجبور نیستیم که هیچ فضایی از Heap بگیریم یعنی مجبور نیستیم که اول داده‌ها را از کانال فایل به فضای برنامه کپی کنیم و بعد داده‌ها را از فضای برنامه به سوکت ریموت کپی کنیم. در عوض به سیستم‌عامل تکیه می‌کنیم تا این کار را بصورت کارآمدتری برای‌مان انجام دهد. به همین علت Kafka یا حداقل کارگزار آن از نظر میزان استفاده از Heap تخصیص یافته به JVM خیلی کارآمد است. ما عموماً به فضای زیادی از Heap نیاز نداریم و به میزان‌کردن‌های (Tuning) محدودی برای مدیریت GC نیاز داریم چون ما فضای دائمی زیادی را از Heap تخصیص یافته به JVM نمی‌گیریم و خیلی از مصرف‌های حافظه، بصورت موقتی برای هر درخواست است.
منطقی است. بیا در مورد جنبه دیگری صحبت کنیم که کلاً در سیستم‌های توزیع‌شده و خاصه در Kafka وجود دارد. می‌خواهم در مورد مانایی (Durability) صحبت کنم. آیا پیام‌ها در هنگام از نو اجرا کردن یا بروز خرابی، قابل ترمیم هستند؟
خرابی‌های متفاوتی وجود دارد. همانطور که پیش از این اشاره کردم در سمت کارگزار پشتیبانی از رونوشت‌برداری (Replication) را اضافه کرده‌ایم بنابراین در یک کلاستر، پیام‌ها می‌توانند بر روی چندین کارگزار تکرار شوند.
آيا کارگزار، معادل با یک پارتیشن از موضوع (Topic Partition) است؟
کارگزار مانند یک سرور یا گره می‌ماند که چندین پارتیشن داده می‌تواند بر روی آن ذخیره شود. مانند موتوری برای ذخیره پیام‌ها است و در یک کلاستر می‌توانیم چندین عدد از این موتورهای ذخیره‌سازی داشته باشیم اما رونوشت‌های یک موضوع بین این موتورهای ذخیره‌سازی پخش می‌شوند و هر کدام از این موتورهای ذخیره‌سازی یا کارگزارها عموماً چندین پارتیشن را ذخیره می‌کنند. البته هرکدام از این پارتیشن‌ها متناظر با یک دایرکتوری فایل محلی هستند و مجموعه فایل‌های خودشان را دارند و نوعی مجزاسازیِ در سطح دیسک وجود دارد.
از لحاظ قابلیت اطمینان، اگر یک موضوع (Topic) را طوری تنظیم کنید که چندین رونوشت داشته باشد در آنصورت می‌تواند خرابی‌های کارگزار را تحمل کند. خرابی معمول در Kafka نوعی از خرابی است که ما آن را خرابی نرم‌ می‌نامیم به این ترتیب که در‌ واقع کارگزار سالم است و تنها می‌خواهید که کد جدیدی را مستقر کنید یا تغییری در تنظیمات اعمال کنید و به همین خاطر باید یکی از کارگزارها یا همه کارگزارهای کلاستر را پایین بیاورید و آن‌‌ها را از نو اجرا کنید. در واقع این ۸۰ یا ۹۰ درصد از موارد خرابی در کلاستر Kafka است. با رونوشت‌برداری می‌توانیم چنین خرابی‌هایی را بصورت خیلی کارایی رسیدگی کنیم. ما امکانی داریم که بصورت خودکار پیشوای یک پارتیشن را به رونوشت دیگری منتقل کنیم و در این حالت، کلاینت‌ها به همان شکل قبل رفتار می‌کنند.
به نظر می‌رسد که گرفتن نسخه پشتیبان از پیام‌ها در یک ذخیره‌گاه مانا، در مشخصه‌های تعریف‌شده برای Kafka قرار نمی‌گیرد. همینطور است؟
بله، به نوعی در تقاطع با آن قرار می‌گیرد. در مورد رونوشت‌برداری از پیام‌ها با این مسائل مواجهیم که آن‌ها را کجا قرار دهیم و چطور آن‌ها را با هم همگام (In Sync) کنیم. اما مسأله دوم که شما به نوعی به آن اشاره کردید این است که برای چه مدتی یک پیام را در یک کلاستر Kafka نگاه می‌داریم. این هم منحصر به Kafka است که مانند سیستم‌های پیام‌رسانی متداول، نگهداشت (Retention) یک پیام پیرو مصرف آن نیست به این معنا که یک پیام وقتی مصرف‌کننده آن را مصرف کرد، سیستم را ترک نمی‌کند. در عوض، مبتنی بر یک «سیاست نگهداشت» است که باقی می‌ماند و این سیاست می‌تواند پیرو زمان باشد مثلاً می‌توانیم پیام‌ها را برای ۷ روز یا یک ماه یا هر مقدار دیگری که فکر می‌کنید نیاز دارید، نگه داریم؛ همینطور می‌تواند پیرو حجم باشد مثلاً یک ترابایت از داده‌ها را نگه داریم.
این نوع امکان نگهداشت پیام‌ها، از لحاظ آنچه قابلیت اطمینان برای مصرف‌کننده‌ها می‌خوانیم، خیلی مفید است. از این نظر که یک مصرف‌کننده بعد از آنکه یک پیام را مصرف کرد تا زمانی که پیام در پنجره نگهداشت باقی‌مانده باشد، می‌تواند آن را دوباره مصرف کند. این چند کاربرد دارد؛ فکر می‌کنم یکی از کاربردهای مهمش این است که می‌توان بصورت مؤثری به خطاهای منطقی نرم‌افزار رسیدگی کرد. فرض کنید نرم‌افزاری دارید که از Kafka تغذیه می‌شود و مثلاً کار استانداردسازی را انجام می‌دهد یعنی داده‌ها را به یک فرمت استاندارد واحد در می‌آورد. حال فرض کنید که زمانی یک نرم‌افزار جدید راه‌انداخته‌‌اید که باگ مهمی داشته است و به ناگاه متوجه می‌شوید که به خاطر آن باگ، داده‌هایی که طی یک ساعت گذشته پردازش شده‌اند قابل استفاده نیستند. حال چه می‌کنید؟ با استفاده از سیاست نگهداشت، می‌توانید مادامی که پیام‌ها همچنان باقی هستند، ‌ مصرف پیام‌ها را به نقطه‌ای برگردانید که خطا در آن زمان رخ داده بود. سپس با رفع کردن خطا، روی همان داده‌ها منطق جدید را اجرا کنید. به این ترتیب می‌توانید اشتباهاتی که در منطق کد استانداردسازی قبلی داشتید را برطرف کنید.
به نظر می‌رسید ویژگی فوق‌العاده مهمی باشد.
همینطور است. این چیزی نیست که سیستم‌های پیام‌رسانی سنتی فراهم کرده باشند.
اینکه بتوانیم در زمان به عقب برگردیم…
درسته، امکان دوباره مصرف کردن پیام‌ها در طی زمان. برطرف کردن مشکلات منطق برنامه یکی از مهمترین کاربردهای این ویژگی است.
یکی از کلماتی که در این پادکست زیاد شنیدیم، کلمه «ریزسرویس» است. این کلمه برای شما چه معنی دارد؟ آیا استفاده از آن در توضیح اینکه Kafka چیست و چه چیزی فراهم می‌کند، مناسب است؟
در‌واقع صدردرصد مطمئن نیستم که این ریزسرویس‌ها [که می‌گویید] به چه معنا هستند و چه تعبیری از آن دارید.
اگر بخواهم در زمینه صحبت خودمان بگویم من منظورم از ریزسرویس، سرویس کوچکی است که می‌توانید آن را بر روی هر کارگزار پیامی که داشته باشید، فراخوانی کرده و سرویس اجرا می‌شود، از مزایای آن این است که می‌توانید آن‌ها را ماژولار کنید و افزایش مقیاس دادن آن‌ها با [راه انداختن] نمونه‌های بیشتر ساده‌تر است. آن طور که من در مورد این کلمه متوجه شده‌ام برای افراد مختلف معانی مختلفی دارد. یکی از عللی که آن را مطرح کردم همین مسئله تفاوت برداشت‌ها بود. اما اگر شما در مورد آن اطلاعاتی ندارید یا دوست ندارید در موردش صحبت کنید، هیچ اشکالی ندارد.
من صد در صد مطمئن نیستم اما به نظر می‌ٰرسد که [منظورتان] یک کارگزار پیام موردی باشد که بتوانید آن را برای یک پنجره زمانی کوچک راه بیاندازید تا پردازش‌هایی بر روی پیام‌ها داشته باشید و بعد از آن، سرویس را متوقف کنید. منظورتان این است؟
بله، دقیقاً همین را می‌گویم. برای من سؤال است که آیا Kafka چنین خدمتی ارائه می‌کند؟
این در‌واقع مربوط به مدل چندعضویتی (Multisubscription) است که Kafka فراهم می‌کند. یکی از قابلیت‌های مهمی که می‌بینیم افراد با Kafka دارند، امکان خطایابی (Debugging) است. این می‌تواند در محیط عملیاتی هم انجام شود اما بیشتر در محیط‌های تست یا پیش‌عملیاتی رخ می‌دهد. چنانچه نرم‌افزاری داشته باشید که از یک منبع داده تغذیه می‌کند اگر گاهی نرم‌افزارتان به آن شکل که انتظار دارید عمل نکند چه می‌کنید؟ چطور می‌‌فهمید مشکل از کجاست؟ قابلیت چندعضویتی این امکان را می‌دهد که به سادگی با استفاده از یک ابزار خط فرمان در یک کنسول، داخل یک موضوع (Topic) شده و ببینید که داده‌ها چه هستند و بر اساس آن ببینید که آیا مشکل از اینجاست که داده‌های درستی نمی‌گیرید یا مشکل از چیز دیگری در نرم‌افزارتان است. این به نوعی شاید مورد خاصی از ریزسرویس‌ها باشد که شما اشاره می‌کنید.
قطعاً. بیا کمی به موضوع نحوه توسعه Kafka بپردازیم. چرا زبان انتخابی، Scala بوده است؟ آیا مشخصاً Erlang را هم در نظر داشتید؟
فکر می‌کنم جی کرپس اولین توسعه‌دهنده Kafka بود. آن موقع، Scala تا حدی محبوب شده بود و او شاید می‌خواست Scala را یاد بگیرد و به این خاطر بود که Scala را انتخاب کرد، به نوعی می‌خواسته آن را امتحان کند و ببیند چطور کار می‌کند. از دیدگاه یک توسعه‌دهنده همواره جذاب است که یک زبان برنامه‌نویسی جدید و پرآتیه را امتحان کنیم. در مورد Scala فکر می‌کنم آنچه از آن بهره زیادی بردیم، موجز بودن نحو (Syntax) آن بود. و همینطور از پشتیبانی‌های زیادی که برای عملکردهای روی مجموعه‌ها (Collection) داشت و اجازه می‌داد که دور زدن بر روی آن‌ها را خیلی راحت انجام دهیم، استفاده کردیم. به همین خاطر است که اگر به کدهای Kafka نگاه کنید به نسبت سیستم‌های مشابهی که با جاوا نوشته شده است، ما از نحو موجز آن بهره زیادی برده‌ایم.
اما یکی از چیزهایی که کمی کار با Scala را دشوار می‌کرد، در ارتباط با مشتریان بود. از آنجایی که Scala یک تکنولوژی در حال ظهور است، مثلاً از لحاظ حفاظت از سازگاری باینری، به اندازه Java بالغ نیست و چون در ریلیزهای ابتدایی خود قرار دارد مجبور می‌شود که سازگاری‌ باینری‌ها را نقض کند و برخی از بایت‌کدهایی که با نسخه‌های قبلی Scala تولید شده‌اند را نمی‌توان با نسخه‌های جدیدتر Scala اجرا کرد. این مشکلاتی برای بروزرسانی [نسخه‌های محصول] مشتری‌های‌مان ایجاد می‌کند. چون خیلی از مشتری‌های ما که به خاطر استفاده از Kafka به Scala وابستگی دارند ممکن است در عین حال از مؤلفه‌های دیگری هم استفاده کنند که آن‌ها هم به Scala و احتمالاً نسخه دیگری از آن، وابسته باشد. بنابراین اگر این نسخه‌های Scala با هم سازگار نباشند بروزرسانی برای چنین مشتری‌هایی خیلی دردسرساز می‌شود. این یکی از چیزهایی است که در ارتباط با Scala کمی کار را دشوار کرده است. ما تلاش کردیم برای حل این مشکل، مؤلفه‌های سمت کلاینت را با جاوای خالص بنویسیم، به این ترتیب می‌توانیم در عین حالی که تا حد ممکن از مزیت موجز بودن نحو Scala بهره ببریم، بروزرسانی کلاینت‌ها را هم خیلی ساده‌تر کنیم.
بسیار خوب، بحث خوبی در مورد Kafka داشتیم. مخاطبین ما برای یادگیری بیشتر در مورد Kafka و یا حتی کاری که خود شما بر روی پروژه دارید، کجا می‌توانند بروند؟
فکر می‌کنم بهترین جایی که برای آن وجود دارد سایت Kafka است. در آنجا مستنداتی وجود دارد که توضیح می‌دهد Kafka چیست و برای چه چیزی طراحی شده است و مثال‌هایی از نحوه استفاده از API ما وجود دارد. می‌توانید کدها را دانلود کنید و یک راهنمای آغاز بکار سریع وجود دارد که می‌توانید از آن پیروی کنید. کافیست که امتحانش کنید. در آن وبسایت، لینکی هم به سیستم Jira خود داریم. اگر علاقه‌مندید که مشارکت کنید می‌توانید در سیستم Jira ما بدنبال برخی کارهای جدیدی بگردید که ساده و دم‌دستی‌تر است و می‌توانید رویش کار کنید. ما یک Wiki هم داریم که برخی برنامه‌ریزی‌ها و ویژگی‌های مربوط به ریلیزهای بعدی را توضیح می‌دهد. آن‌ها، چیزهایی هستند که کار توسعه کلان‌تری را می‌طلبند. اگر یک همکار حرفه‌ای‌تر در Kafka هستید شاید برخی از این ویژگی‌های آتی برای‌تان جذاب باشد.
در حال حاضر، ما در حال بازنویسی برخی API های مصرف‌کننده‌ها (Consumer) هستیم که به منظور کاهش وابستگی به Scala – همان‌طور که پیش از این اشاره کردم- و تکمیل‌تر کردن ویژگی‌های API و بهبود عمل‌کرد آن است. چیز دیگری که به زودی خواهد آمد پشتیبانی از مبحث امنیت در Kafka است که شامل اعتبارسنجی و ارسال رمز شده برخی از داده‌ها می‌شود. ما به این هم فکر کرده‌ایم که چطور Kafka را در محیط‌های چندمستأجری (Multi-tenant Environment) محافظت کنیم که کاربران مختلف بر روی هم تأثیر نگذارند خصوصاً اگر یکی از نرم‌افزارها باگ داشته باشد و خارج از کنترل شده باشد. ما به این فکر کرده‌ایم که چطور از یک سیستم حد نصابی برای جلوگیری از وقوع چنین چیزهایی استفاده کنیم. این‌گونه اطلاعات، همگی می‌تواند در وبسایتِ Apache ما یافت شود. ما گروه‌های نامه‌ (Mailing List) هم برای کاربران و هم توسعه‌دهنده‌ها داریم و اگر علاقه‌مند باشید می‌توانید در آن‌ها عضو شوید و از آنچه در Kafka رخ می‌دهد باخبر شوید.
از اینکه به SE Radio آمدید خیلی متشکرم. خوشوقت شدیم.
خیلی ممنونم.

مجتبی بنائی

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

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

جای خالی در معادله زیر را با کی برد انگلیسی وارد کنید : * Time limit is exhausted. Please reload CAPTCHA.

این سایت از اکیسمت برای کاهش هرزنامه استفاده می کند. بیاموزید که چگونه اطلاعات دیدگاه های شما پردازش می‌شوند.

دکمه بازگشت به بالا