Message,Queue , Concurrency , Scaling

سلام . در این پست به پیشنهاد اقا سمیر عزیز @lxsameer درباره مسائلی پیرامون سولوشن ها و سیستم هایی که برای اسکیل و کانکارنسی/اسینکرونوز هست صحبت میکنیم …

استارت بحث فک کنم با این موضوع باشه

من قبلن actor model رو بررسی کردم . و همینطور یه سری به akka زدم
نمیدونم این مورد درست هست و میتونه اتفاق بیفته یا نه.(مثل امکان از دست رفتن مسیج ها یا بلاک شدن حین انتقال از سرویس و تردی به ترد دیگه) .

یک مدل پیشنهادی Remote Actor بود . که با Rabbit MQ تلفیق شده بود . و با جمله هایی با این مظمون (durable messaging guarantees) , (message delivery guarantees) جلب توجه میکرد

من با ابزار های دیگه زیاد تجربه ندارم . یه تجربه بیسیکی روی کافکا و بیشتر کارم روی RabbitMQ با library بودن .
هرکدوم اینا چه تضمینی تو چه حیطه ای دارن
برای scaling متوسط و بزرگ . با horizontal scaling و افزایش نود های RabbitMQ ایا میشه حد قابل قبولی رسید

قدیما با kafka connect jdbc روی 5تا sqlite دیتا میریختم :smile: (اس کیو ال لایت توانایی write همزمان نداره در لحظه بخاطر ساختار فایلیش . بنابرین بصورت کیو و اسینک با کمک کافکا اینکارو کردم . و خیلی هم لذتبخش بود ک با SQLite بتونم اندازه MySQL کار بکشم:) )…

درباره ActiveMQ و ZeroMQ هم میخام شروع کنم به تحقیق . .

نکته مهم مد نظرم اینه که .آیا میشه فریم ورکی مبتنی بر همینا ساخت بصورت اسینک برای زبانی خاص , و ایا bottleneck دیگه ای حین message passing‌وجود داره یا نه

5 پسندیده

Actor model به خصوص طوری که در ارلنگ پیاده شده بسیار ارتقا پذیره ولی با این حال بی مشکل نیست درک برنامه در در actor model بسیار سخته چون state میتونه در actor ها تقسیم بشه و دلیل دیگه سختی کار عدم وجود تایپ و محدودیت در actor هاست
Rabbitmq کاملا ساختارش فرق میکنه با کافکا چون queue با خوانده شدن هر message توسط یک consumer
Message از بین میره و اصطلاحا exactly once semantic داره یعنی گارانتی که یک پیام فقط یک بار استفاده بشه در queue

کافکا حدفش نگه داشتن ترتیب پیام ها بیشتره و مثل یک لاگ ارتقا پذیره که یک پیام در یک topic هر چند consumer که به topic وصل هستند همزمان میگیرند

کافکا با پارتیشن شدن که از اول میشه بسیار ارتقا پذیرتر از rabbitmq هستش
از کافکا میشه به عنوان queue استفاده کرد فقط یک کم کار بیشتر داره
در کافکا اگر دو consumer به یک تاپیک وصل می‌شوند و مثلا ۱۰۰ پیام بیاد هردو همه ۱۰۰ پیام میبینن ولی اگر هردو این consumer ها عضو یک گروه باشند consumer group
هرکدام ۵۰ تا از پیام هارو میبینند

در نسخه آخر کافکا exact once semantics یک feature که میشه برای یک تاپیک فعال کرد و همچنین ksql که میشه روی stream پیام ها sql اجرا کرد

4 پسندیده

یک بلاگ پست راجع به اینکار با کافکا نسخه قدیمی تر
https://segment.com/blog/exactly-once-delivery/

2 پسندیده

فوق العاده بود :heart_eyes: مرسی اقای سام . پس یه چیزی . RabbitMQ برای نگه داشتن استیت ها نمیتونه مناسب باشه درسته ؟

2 پسندیده

بله پیام ها رو فقط به صورت داده در rabbitmq به کار میگیرند
State در سیستم های distributed بسیار دشواره و باید دلیل خوبی براش داشت
اگر برنامه stateful باید بسازی ولی ارلنگ عالیه
بسیاری از سیستم های همزمان نرم مثل سرور بازی با ارلنگ ساخته شدند

2 پسندیده

راستش دلیل خوبی ندارم متاسفانه . ولی سیستم نهایی قراره بره زیر دست دیزاینر ها و ایده پرداز ها … که انعطاف بیش از حدی به سیستم باید بده . بخاطر همینم نیاز دارم استیت نگه دارم تا creativity ای که میاد سمت بکند و پروسس ها رو بتونم مدل و مپ کنم …

برای پروتوتایپ فعلا از همین پایتون و رپر هاش استفاده میکنم . تا برسه به حدی که تیکه تیکه بازنویسی بشه با rust , erlang یا حتی scala

2 پسندیده

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

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

و سوال بعدی چند بار اسم ارلنگ رو آوردید آیا الکسیرم جزوش حساب کردید یا خیر؟

ببخشید بین سوالاتتون سوال ساده پرسیدم شرمنده :rose:

1 پسندیده

در مورد RabbitMQ vs Kafka باید بگم که بزرگترین فرقشون تو این موضوع هست که در RabbitMQ برکر (Broker) هوشمند هست و کانسومر خنگ و در kafka بر عکس. برای مثال تو کافکا شما باید مدیریت کنی افست رو و اینکه کی چی رو پردازش کنه. اما تو RabbitMQ اینطور نیست.

این موضوع تفاوت های زیادی ایجاد می کنه مثلا در مورد distributed job queue ( البته بسته به طراحی سیستم) ورکر من فقط باید یه فانکشن رو با state ی که بهش میدم اجرا کنه و نتیجه رو به کیو بر گردونه و نمی خوام کار دیگه ای انجام بده. برای این مورد RabbitMQ می تونه بهتر باشه. یا مثلا من یه سری ورکر دارم که می خوام بر اساس ترتیب کلی یه سری job رو پردازش کنند توی کافکا total order فقط در سطح پارتیشن هست و نه تاپیک و در سطح تاپیک فقط یک کانسومر در هر کانسومر گروپ مجاز هست. یعنی اگر یه کانسومر تحت هر شرایطی عقب بیفته اون پارتیشن نسبت به بقیه عقب می مونه. در صورتی که تو RabbitMQ اگرم یه کانسومر عقب بمونه بقیه به ترتیب از کیو می خونن و کارشون رو انجام می دن. فاکتور اصلی پردازش موازی تو کافکا تعداد پارتیشن ها هست. بعنی اگر هر زمان شما بخواین پردازش موازیتون رو گسترش بدین باید تعداد پارتیشن ها رو همراه با کانسومر ها افزاریش بدید که این باعث می شه کافکا تاپیک رو ری پارتیشن کنه که بسته به حجم دیتا می تونه پر هزینه باشه.

برای یه distributed job queue که برای ایجاد پاراللیسم ایجاد شده و هدفش اجرای جاب های خیلی کوچیک ( در حد فانکشن ) هست مهم نیست که بتونه در صورت failed شده یه جاب آفست رو به عقب برگردونه و از اول اجرا کنه بلکه مهم هست که نتیجه و failed شدن رو به عنوان یه جاب جدید گزارش بده و به انتهای صف اضافه کنه.

این ها رو نمی گه که بگم کافکا بده . کافکا عالیه و حتی برای distributed job queue هم ازش می شه استفاده کرد اما نیاز به کلی کار هست که قبلا کسی توی نرم افزاری مثل RabbitMQ انجام داده و تست شده هست اما تو کافکا خودتون باید اون لاجیک رو پیاده کنین. اما در مورد کاربرد های دیگه این داستان کاملا منطقی هست و کافکا عالیه. کافکا موارد استفاده بسیار زیاد و گسترده ای داره اما جواب همه چیز نیست.

@salvador عزیز خیلی پیشنهاد می کنم این ویدئو رو برای الهام گرفتن ببینی:

یه کاری که دارم انجام می دم اینه که با الهام گرفتن از O(1) scheduler لینوکس که الان دیگه تو لینوکس ازش استفاده نمی شه و با استفاده از abstraction ی که hellhound داره یه سیستم distributed بسازم که سیستم ها رو به صورت distributed اجرا کنه.

4 پسندیده

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

2 پسندیده

فکر میکنم کلا مسیجینگ در kafka مبتنی بر pull باشه اما در RabbitQM به صورت push که احتمالا در حال تغییر راهبردی در این زمینه هست

2 پسندیده

تو جفتش می شه از Pull به Push و بر عکس تغییر داد.

3 پسندیده

راستش حدس میزنم در روش پول کانسوم کردن بهتر از مدل پوش برای کنسومر قابل کنترل باشه و این به سادگی و صعودپذیری کمک میکنه.

ببخشید که کوتاه و بریده پست میزارم.

3 پسندیده

به نظر من هر کدوم خوبیه خودشون و دارن. مثلا تو حالت pull پیاده سازیه back pressure رسما کاری نداره. اما تو پوش سخت هست. در مقابل حالت push بسیار مناسب تر هست برای سیستم های reactive که باید به یه سری event عکس العمل نشون بدن به صورت real time. اما در حالت pull هر چقدر هم کوتاه ولی delay به وجود میاد.

3 پسندیده

بله کاملا موافقم

3 پسندیده

مرسی از اطلاعات خوبتون سمیرجان واقعا استفاده کردم
راستش برای سیستم من order و وابستگی بین جاب ها اهمیت زیادی داره , بخاطر همینم به یه چیزی که بتونه fail over و retry انجام بده و نره سراغ بدی مد نظرم بود , و همینطور قراره از هر از استیت چندبار استفاده بشه ,…

تا اینجا حس میکنم کافکا بهتر از RabbitMQ‌ برای سیستمم جوابگو هست … اما دارم روی architect یه فکر دیگه ای میکنم تا dependency ها به حداقل کاهش بدم ,

این همون اسکژور دو آرایه ای با اولویت اجرا هست درسته؟ . چطور روی RibbitMQ پیاده میشه و چطور اینتراکتیو تسک هارو ترتیب بندی میکنید اینجا

2 پسندیده

من هم فکر می کنم کافکا بهترین انتخاب برای شما باشه.

بله دقیقا. البته از این scheduler الهام گرفتم و پیاده سازی نهایی متفاوت خواهد بود.

در این مورد باید بگم که من از RabbitMQ فقط برای توزیع جاب ها بین ورکر هام استفاده می کنم هر جاب یه فانکشن هست که ۳ پارامتر می گیره و یه هش مپ بر می گردونه. این پروسه کاملا از دید کاربری که با hellhound کار می کنه پنهان می مونه و از دید اون یه سری کامپوننت هست (‌که در واقع یه سری فانکشن هستند ) که از طریق یه سری استریم با هم در ارتباط هستند.

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

استریم های hellhound به این شکل هستند که وقتی مقداری توشون قرار میگیره. پروسه ی کانسوم اون مقدار رو به صورت یه فانکشن داخل جاب کیو (‌همونی که کاربر نمی بینه) قرار میدند. این کیو تو یه abstraction هست که در سطح هر نود توسط یه implementation ی از BlockingQueue پیاده سازی می شه و توی سطح سیستم توزیع شده توسط یه مسیج کیو که الان فقط zookeeper و RabbitMQ پیاده سازی شدن.

همه ی اون فانکشن های کانسومی که توی جاب کیو هستند قانکشن های هستند که state رو همراه خودشون دارند و یه هش مپ بر می گردونند که توصیفی از side effect هایی هست که باید انجام بشه. یعنی در واقع هر فانکشن pure هست و می تونه هر زمانی و رو هر نودی اجرا بشه. side effect ها هم توسط سوپر وایزر دوباره schedule می شن و بنا به طبیعتشون توی تردپول مربوط به اون اجرا می شن. مثلا اگه ساید افکت قرار دادن یه مقدار توی استریم خروجی باشه این کار توی execution threadpool یا همون ترد پول اصلی اتفاق می افته، اگر side effect یه پروسه IO باشه این کار تویه wait threadpool انتفاق می افته که اولویت پایین تری داره و …

3 پسندیده

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

2 پسندیده

استک هیولایی هستش . اتفاقا قبلن همه فکرم درگیر ارتقای راحت یه سیستم بزرگ monolithic به microservice و منیج اون بود . که Mesos رو دیدم … اما فعلا برای اسکیلی که کار میکنیم . خیلی بزرگ و زمانبر هست

بازم بسیار ممنونم :blush: :rose:

2 پسندیده

شهریارجان . حس میکنم سوالت پنهان موند . من منشن میکنم و یه توضیحی میدم . و باقی دوستان تخصصی تر توضیح میدن

اگه درست متوجه شده باشم . با مقایسه db با data in memory سعی داشتی بگی که یه استیتی بالاخره نیاز هست …
تقریبا میشه گفت سیستم خالص stateless وجود نداره … اما مهم dealing هست تو هر level . مثلا سیستم عامل استیت های خودشو هندل میکنه و با ما کاری نداره . database connectorها هم همینطور .

اما چیزی که دیتا یا استیت روی رم رو مهم میکنه برای برنامه نویسا . اینه ک دیتای روی رم مستقیم میتونه هرموقعی(یا حتی ریل تایم به محض تولید شدن یا رسیدن) به cpu و ترد ها پخش بشه و استفاده بشه … و از اونجایی که ترد ها شعور کافی ندارن :smile: اگه حواست نباشه میتونن استیت هارو تغییر یا شیر کنن… یا اینکه Nحالت برات پیش بیارن که نیاز به توجه کافی داره و هروقت x == ? بود یه سناریوی جدایی باید براش نوشته بشه …

حالا توی سیستم های توزیع شده . اگه استیتی باشه( ک خیلی اوقات هم هست . اما سعی میکنن ایزوله نگهش دارن برای هر سرویس یا نود) . و از وضع هم خبر داشته باشن(به نوعی کارکردشون به این استیته ربط مستقیم داشته باشه) باید با مشکلات مختلفی مثل همین retry , ordering , dependency , fail loops دست و پنجه نرم کرد . و با بزرگ تر شدن سیستم . و سرویس های استیت دار . هندل کردن پیچیدگیش انقد سخت میشه ک از دست خارج میشه …
اما dbهای روی استوریج فیزیکی صرفا موقع نیاز به داده نهایی یا خام فراخوانی میشن
نمیدونم درست متوجه منظورت شدم یا نه . و اینکه درست تونستم منظورمو برسونم یا نه …

3 پسندیده

بسیار ممنون دوست عزیزم @salvador عزیز . کامل توضیح فرمودید و متوجه شدم . خیلی ممنون . چون قبل از این پست داشتم به این فکر می کردم برای یادگیری کل سایتمو کامل دوباره با GenServer روی الکسیر به صورت استیت فول بازنویسی کنم که یک دفعه این پست جالب اومد بالا

2 پسندیده