در مدل Client/Server برای ارتباط بین Client و Server معمولا از روش Request/Response استفاده میکنیم؛یعنی Client نیاز خود را در قالب یک Request برای Server ارسال میکند و منتظر Response از سمت Server میماند.تا زمانی که Server پاسخ مورد نیاز Client را آماده کند،Client باید منتظر بماند و در صورتی که Server زمان زیادی را نیاز داشته باشد تا پاسخ را آماده کند،در صورت همگام بودن(Synchronous) بودن Request و Response احتمالا Client مسدود(Block) میشود.به طور کلی اینترنت بر پایهی این مدل سنتی Request/Response کار میکند و در اکثر مواقع مشکلی وجود ندارد و درخواست Client به شکل مناسبی پاسخ داده میشود.
۱) فرض کنید آماده شدن Response از طرف Server زمانی نسبتا طولانی نیاز داشتهباشد و چندین Client به طور مداوم Requestهای خود را برای Server ارسال میکنند.در این سناریو Server همیشه باید در دسترس باشد و علاوه بر آن هیچ یک از Request ها نباید از دست بروند.آیا مدل سنتی Request/Response میتواند برای این سناریو مناسب باشد؟آیا میتواند تجربه کاربری مناسبی را برای کاربران فراهم کند؟
۲) زمانی که از معماری Microservice استفاده میکنیم و Client برای گرفتن پاسخنهایی خود نیاز به تعامل چندین سرویس با هم دارد،استفاده از مدل سنتی Request/Response باعث مسدود شدن درخواست Clientهای دیگر میشود.برای مثال زمانی که میخواهیم یک ویدیو را در Youtube آپلود کنیم چندین سرویس مانند Upload Service، Compress Service، Format Service، Notification Service، باید با یکدیگر همکاری کنند تا درخواست آپلود یک ویدیو انجام شود.
همانطور که در تصویر میبینیم به دلیل ارتباط زنجیرهای که سرویسها با یکدیگر دارند و هر کدام منتظر پاسخ سرویس بعدی برای یک درخواست هستند، درخواستهای بعدی برای آپلود ویدیو از سمت Clientهای دیگر که شامل تعداد زیادی درخواست است، مسدود میشوند و هر Client بدون دریافت هیچ نوع پاسخی باید برای مدت زمانی طولانی منتظر بماند؛این انتظار تجربه کاربری بسیار بدی را برای application ما خواهد داشت.بنابراین روش سنتی Request/Response برای معماری Microservice مناسب نخواهد بود.
مشکل اصلی در روش Request/Response این است که کاربر ممکن است برای مدت نامعلومی پشت سیستم خود منتظر بماند تا پاسخی دریافت کند؛چطور میتوانیم یک تجربهی کاربری مناسبتری را برای کاربر فراهم کنیم؟
بهتر است زمانی که میدانیم فرآیند پاسخ(Response) طولانی خواهدبود،درخواست کاربر را در جایی ذخیره کنیم و به وی اطمینان دهیم که درخواستش(Request) دریافت شده و مدتی طول خواهد کشید تا پاسخ (Response) آماده شود و به محض این که پاسخ آماده شود، کاربر را مطلع خواهیم کرد.
در این صورت کاربر میتواند به کارهای دیگر خود برسد و نیازی نیست تمام مدت آماده شدن پاسخ منتظر آن بماند بدون آن که بتواند کار دیگری انجام دهد.
چالش اصلی برای ایجاد این تجربهی کاربری میتواند نحوهی ذخیره کردن درخواست Client ها باشد.سادهترین روشی که احتمالا به ذهن همهی ما میرسد،ایجاد یک صف(Queue)است که درخواستها به ترتیبی که وارد میشوند در آن ذخیره شوند.
صف پیام (Message Queue) در واقع همان صفی هست که ما برای ذخیره سازی موقت درخواستها میخواستیم.در این روش ،Client، پیام(Message) خود را که حاوی درخواست مورد نظرش است به مقصد Message Queue میفرستد؛پیامهای تمامی Client ها میتواند در صفهای متفاوتی به ترتیب زمان ارسال یا اولویتی که برایشان تعیین میشود،قرار بگیرند؛ تا زمانی آن پیام توسط Service یا Application دیگری(Consumer) برای خدمتدهی از صف برداشته شود،پیام در صف باقی خواهد ماند و بنابراین هیچ یک از پیامها که حاوی درخواست Clientهاست از دست نخواهد رفت.
پاسخ هر پیام میتواند پیامی برای یک Service یا Application دیگر باشد مانند مثالی که برای آپلود ویدیو در Youtube گفتیم بنابراین پاسخ هر پیام نیز مستقیما برای Service یا Application یا Client ارسال نمیشود بلکه مقصد هر پاسخ باز هم یک Message Queue خواهد بود.
صف بندی پیامها این امکان را میدهد که سرویسها و application ها به طور غیر همگام (Asynchronous) با یکدیگر ارتباط داشته باشندچرا که سرویسها و application ها دیگر به طور مستقیم با یکدیگر در اتباط نیستند و از طریق صف پیام به عنوان یک واسط با هم تعامل میکنند.
تولید کننده پیام(Producer) پیام خود را در صف قرار میدهد بدون آنکه منتظر بماند تا نتیجهی آن را دریافت کند.
یکی از مثالهایی که شاید خیلی از افراد به صورت روزمره با آن در ارتباط هستند می تواند ایمیل باشد.وقتی که ایمیلی را به مقصد ایمیلی دیگر ارسال می کنیم،پیامی با مضمون اینکه ایمیل ما ارسال شد به دست ما میرسد و بنابراین ما میتوانیم به دیگر کارهای خود برسیم.در ارسال ایمیل پیام ما گره(node)های میانی ذخیره میشوند و هر زمانی که گرهی بعدی آماده بود،به گرهی بعدی ارسال میشود بنابراین نیازی نیست تمامی گرهها در همان لحظهی ارسال ایمیل ما آنلاین باشند و یا ایمیلی که به مقصد آن پیاممان را ارسال کردیم همزمان با ما آنلاین باشد،پیام به صندوق الکترونیکی مقصد میرسد و هر زمان کاربر ایمیل خود را باز کند آن را می بیند.
در واقع Message Queue برای ایجاد این نوع ارتباط بین برنامهها ایجاد شده است(Program to Program)
Message: پیامی حاوی دادههای مورد نیاز است که برای یک سرویس یا برنامه برای Message Queue می فرستد. پیامها انواع مختلفی دارند.
Queue:نام مقصدی که هر برنامه پیامهای خود را برای آن میفرستد. پیامها در صفها جمعآوری میشوند تا زمانی که یکی از سرویسها یا برنامهها به آن خدمت رسانی کند
Producer:برنامه یا سرویسهایی که پیامها را تولید می کنند و به آن ها اولویت اجرا میدهند و درون صفها قرار میدهند.
Consumer: سرویسها و برنامههایی که پیامها را از صف برمی دارند و به آنها خدمت رسانی می کنند.
اصلی ترین عیب این روش را میتوان پیچیدگی استفاده از آن دانست چرا که هماهنگی میان Message Queue با هر یک از تولید کنندگان و مصرف کنندگان و چگونگی ارتباط گرفتن صفها با تولید کنندگان و مصرف کنندگان روشی پیچیده را میطلبد.اطمینان از اینکه پیامی با محتوای یکسان دو بار ارسال نشده باشد.در روش نقطه به نقطه چگونه میتوان مطمئن شد که یک پیام توسط یکی از برنامهها خوانده شده تا آن پیام را حذف کنیم تا برنامه یا سرویس دیگری آن را بر ندارد.
۱) RabbitMQ
RabbitMQ محصول شرکت CloudAMQP است که از طریق پروتکل ارتباطی AMQP پیامها را تبادل میکند. نرم افزار RabbitMQ یکی از Message Brokerهای پر استفاده در جهان است، دارای بیش از 35,000 استفاده کننده دارد.RabbitMْQ تمام ویژگیهای معرفی شده برای Message Queue را دارد و بنابراین با تعریف تنظیمات مورد نیازمان در آن میتوانیم برای سیستم مورد نظرمان از آن استفاده کنیم و بنابراین نیازی به این نداریم که خودمان یک Message Queue برای سیستم نرم افزاری ایجاد کنیم. با استفاده از RabbitMQ میتوانیم هر دو نوع Message Queue را پیاده سازی کنیم.
توسعه دهندگان اکثرا این ابزار را به دلیل انعطاف پذیری بالایش در سناریوهای پیچیدهی Routing استفاده میکنند. از دیگر قابلیتهای RabbitMQ میتوان به نصب پلاگینهای مختلف بر روی آن برای ساپورت کردن دیگر پروتکلهای پیام مانند STOMP و MQTT اشاره کرد
این نرمافزار با زبان Erlang نوشته شده است و قابلیت نصب بر روی اکثر سیستم عاملها را دارد.
۲)Kafka
Apache Kafka یکی دیگر از Message Broker های معروف و پر استفاده است که LinkedIn آن را با Java و Scala برای پیگیری کردن وبسایت LinkedInتوسعه داده است. استفاده از کافکا نیز میتواند مزیت استفاده از هر دو نوع Message Queue را داشته باشد. با توجه به سیستم نرم افزاری مورد نیاز میتوانیم تنظیمات مورد نظر را برای آن پیاده سازی کنیم.
هر دوی این ابزارها در سطح بالا دارای کارآیی یکسانی هستند اما در جزئیاتی با یکدیگر تفاوت دارند.
شرکت فعالی در این حوزه در ایران طی جستجوهایی که انجام دادم پیدا نکردم و به نظرم دلیل آن میتواند این باشد که دو ابزار معرفی شده به طور کامل تمامی ویژگیهای مورد نیاز را به صورت متن باز در اختیار تمامی افراد و شرکتها قرار میدهند و ما در ایران نیز میتوانیم از خدمات آن استفاده کنیم.
این مطلب، بخشی از تمرینهای درس معماری نرمافزار در دانشگاه شهیدبهشتی است.
https://www.ibm.com/docs/en/ibm-mq/8.0?topic=overview-introduction-message-queuing
https://www.ibm.com/docs/en/ibm-mq/8.0?topic=queuing-main-features-benefits-message
https://www.ibm.com/docs/en/ibm-mq/8.0?topic=queuing-message-terminology
https://www.cloudamqp.com/blog/what-is-message-queuing.html
https://www.youtube.com/watch?v=DXTHb9TqJOs
https://www.youtube.com/watch?v=5-Rq4-PZlew