RabbitMQ و ارتباط سرویسهای ابری
یک راهنمای سریع برای درک RabbitMQ
به طور کلی، در معماری microservice دو راه برای برقرای ارتباط بین سرویسها وجود دارد:
- ارتباط Synchronous (همزمان): در این نوع ارتباط، یک برنامه یا سرویس به طور مستقیم و با استفاده از پروتکل HTTP با برنامه دیگر ارتباط برقرار میکند که نیاز به پاسخ فوری و مستقیم از سرور دارد.
- ارتباط Asynchronous (غیرهمزمان): در این نوع ارتباط که از مکانیزم publish-subscribe استفاده میشود، نیازی به پاسخ فوری از سرور نیست و پیامها (درخواستها) به یک message broker یا کارگزار پیام (مانند RabbitMQ) ارسال میشوند و سرویس مربوطه آن را گرفته و پردازش میکند.
Message Broker (کارگزار پیام) چیست؟
Message Broker نرم افزاری است که برنامهها، سیستمها و سرویسها را قادر میسازد تا با یکدیگر ارتباط برقرار کرده و تبادل اطلاعات داشته باشند. Message Broker با ترجمه پیامها به پروتکلهای پیام رسان رسمی این کار را انجام میدهد. بنابراین به سرویسهای وابسته این امکان را میدهد تا با یکدیگر “صحبت” کنند، حتی اگر به زبانهای مختلف نوشته شده باشند. Message Broker پیامهای دریافتی را از برنامه فرستنده دریافت میکند و آنها را برای برنامه گیرنده ارسال میکند. به این ترتیب فرستنده و گیرنده میتوانند کاملا مجزا باشند.
Message Queuing (صف بندی پیام) چیست؟
همه ی پیامها توسط یک برنامه ی تولید کننده (Producer)، تولید میشوند و به یک صف پیام، push میشوند. این فرایند به Enqueuing معروف است. پیامهای push شده در این صف باقی میمانند تا زمانی که یک برنامه ی مصرف کننده (Consumer) متصل شده و این پیامها را واکشی کند. این فرایند به Dequeuing معروف است. هر دو فرایند Enqueue و Dequeue به طور مستقل توسط برنامههای Producer و Consumer انجام میشوند و این امکان را داریم که یک پیام را در انتظار دریافت یک Consumer، در یک صف پیام نگه داریم. بنابراین فرایند push شدن پیام به صف توسط برنامه Producer و مصرف شدن آن توسط برنامه Consumer، به عنوان Message Queueing (صف بندی پیام) شناخته میشود.
شکل 1 فرایند ارسال پیام به RabbitMQ و دریافت پیام از آن
برای اجرای Message Queueing، یک message broker مانند RabbitMQ گزینه خوبی است و در ادامه به چگونگی جریان پیام در RabbitMQ و همین طور به برخی مفاهیم اساسی آن اشاره خواهیم کرد.
مفاهیم RabbitMQ:
- مفهوم Producer: اپلیکیشنی که پیام را ارسال میکند.
- مفهوم Consumer: اپلیکیشنی که پیام را دریافت میکند.
- مفهوم Queue: بافر برای ذخیره سازی پیامها.
- مفهوم Message: دیتا ارسال شده از طرف Producer به Consumer به واسطه RabbitMQ.
- مفهوم Connection: اتصال TCP بین اپلیکیشن و RabbitMQ broker.
- مفهوم Channel: یک اتصال مجازی در یک اتصال اصلی. انتشار یا دریافت پیام، همه با Channel انجام میشود.
- مفهوم Exchange: دریافت پیام از Producerها و Push کردن آنها روی Queue بسته به قوانین تعریف شده در Exchange type. یک صف احتیاج دارد که به حداقل یک Exchange مقید شده باشد تا بتواند پیامها را دریافت کند.
- مفهوم Binding: اتصال بین Queue و Exchange.
- مفهوم Routing key: یک کلید در Message که Exchange با استفاده از آن تصمیم میگیرد چطور پیام را به سمت صف Route کند. Routing key را به عنوان آدرس مقصد پیام در نظر بگیرید.
- مفهوم AMQP: مخفف Advanced Message Queuing Protocol، پروتکل اصلی مورد استفاده برای Messaging در RabbitMQ.
- مفهوم Users: این امکان وجود دارد که به وسیله نام کاربری و رمز عبور و مجوزهای دسترسی مشخص شده به RabbitMQ وصل شد. همچنین میتوان برای کاربران مجوز دسترسی به Virtual host خاص تعیین کرد.
- مفهوم VHost: برای تفکیک اپلیکیشنهایی که در حال استفاده از RabbitMQ هستند از Virtual Host استفاده میکنیم. کاربران مختلف میتوانند دسترسیهای مختلفی به VHostها و Queueها و Exchangeهای مختلف داشته باشند.
- مفهوم Acknowledgments and Confirms: شاخصهایی برای مشخص کردن اینکه پیام دریافت شد یا پردازش شد. Acknowledgements میتواند در هر دو طرف استفاده شود؛ برای مثال، یک Consumer میتواند به سرور اطلاع بدهد که پیام دریافت یا پردازش شد، و سرور هم میتواند همچنین گزارشی را به Producer بدهد.
جریان پیام در RabbitMQ
در RabbitMQ، پیامها مستقیما به صف publish نمیشوند و ابتدا توسط exchange دریافت میشوند. exchangeها بسته به قوانینی که متناسب با نوع آنها تعیین شده است (در RabbitMQ چهار نوع exchange مختلف وجود دارد که در ادامه ی همین مقاله اشاره ی مختصری به انواع آنها خواهیم داشت) ؛ پیامها را از producer دریافت میکنند و به exchange مشخص شده در پیام تحویل میدهند. سپس exchange، پیامها را در صفها توزیع میکند. (قابل بیان است که صفها در RabbitMQ از روش FIFO (First In, First Out)، پیروی میکنند).
برای ارسال پیامهای مناسب به صفهای مناسب، از قوانینی به نام binding استفاده میشود. binding لینکی است که برای اتصال صف به exchangeها تنظیم میشود. میتوان یک صف را به چندین exchange متصل کرد.
برای درک بهتر جریان پیام در RabbitMQ به تصویر زیر و توضیحات آن توجه کنید:
۱. تولیدکننده یک پیام را به یک exchange، پوش میکند. هنگام ایجاد exchange، نوع آن باید مشخص شود.
۲. Exchange پیام را دریافت میکند و اکنون مسئول مسیر دهی به پیام است.
۳. بین exchange و صف باید binding تنظیم شود. در این تصویر exchange به دو صف متفاوت bind شده است. exchange، براساس ویژگیهای پیامها (message attribute)، آنها را به صفها مسیردهی میکند.
۴. پیامها در صف قرار میگیرند تا زمانی که توسط یک consumer، مصرف شوند.
۵. Consumer، پیامها را پردازش میکند.
شکل 2 فرایند قرار گرفتن یک پیام در صف RabbitMQ و دریافت پیام از آن
Exchangeها و انواع آنها
Exchange یک درگاه ورود به RabbitMQ برای پیامهاست. در RabbitMQ بسته به نوع exchange، پیامها در صفهای متفاوتی مسیردهی میشوند. در اصل چهار نوع وجود دارد:
- Direct exchange: پیامها را بر اساس routing key پیام به صف منتقل میکند. routing key یک ویژگی پیام است که توسط تولید کننده به پیام اضافه میشود. میتوانید routing key را به عنوان یک “آدرس” در نظر بگیرید که exchange برای تصمیم گیری در مورد نحوه ی مسیردهی پیام از آن استفاده میکند.
- در direct exchange، پیام به صفهایی هدایت میشود که binding key آنها دقیقاً با routing key پیام مطابقت دارد. به عنوان مثال، اگر صفی که binding key آن برابر با yottabProcess است به exchange متصل باشد، پیامیکه routing key آن برابر با yottabProcess باشد، به آن صف هدایت میشود.
- Fanout exchange: یک fanout، پیامهای دریافتی را به تمامیصفهای متصل، منتقل میکند و توجه ای به routing keyها ندارند.
- Topic exchange: پیام به صفی ارسال میشود که الگوی binding آن با routing key پیام مطابقت داشته باشد.
- Routing key باید لیستی از کلمات باشد که با نقطه (.) از هم جدا شده باشند. مانند yottab.events و yottab.events.err. الگوی مسیردهی ممکن است شامل یک ستاره (*) برای مطابقت یک کلمه در یک موقعیت خاص از routing key باشد (برای مثال الگوی مسیردهی yottab.*.*b.* تنها با routing key ای مطابقت دارد که کلمه اول آن yottab و چهارمین کلمه آن b باشد).
- Headers exchange: از ویژگیهای هدر پیام برای مسیریابی استفاده میکنند. headers exchange بسیار شبیه به topic exchange است، با این تفاوت که مسیردهی در آن به جای routing key بر اساس مقادیر هدر است. اگر مقدار هدر پیام با مقدار مشخص شده در binding برابر باشد، آن پیام مطابقت دارد.
Message Acknowledgement (تایید پیام):
چه اتفاقی میافتد اگر پیامینتواند به مصرف کننده برساند؟ این امر ممکن است به دلیل خرابی شبکه یا برنامه رخ دهد. اگر هر یک از این خرابیها اتفاق بیفتد، سیستم ما میتواند پیام را برای همیشه از دست بدهد.
برای پرداختن به این مسئله، AMQP یک مکانیزم تأیید تحویل (delivery acknowledgement) را در کار دارد. بنابراین یک پیام به طور کامل از یک صف حذف نخواهد شد، مگر اینکه از مصرف کننده تاییدیه مثبت ارسال کنیم. در صورت تایید منفی، پیام میتواند دوباره برای مصرف کننده ارسال شود یا بسته به تنظیمات پیکربندی تولید کننده هنگام ارسال پیام، پیام را رها کند.
جمع بندی:
RabbitMQ محصولی بسیار کامل و مفید برای ارتباط بین سرویسهای مختلف در معماری microservice است. این مقاله تنها مقدمه ای برای RabbitMQ است و ما مفاهیم را در این مقاله ساده بیان کردیم تا نقطه ی عطفی برای شروع حرکت شما باشد. میتوانید با مراجعه به سایت RabbitMQ، موضوعات و مفاهیم مرتبط با RabbitMQ را کامل تر بررسی کنید.