مطلب را با یک تصویر کلی از RabbitMQ آغاز میکنیم. RabbitMQ ابزاری است که از آن برای انتقال اطلاعات بین چندین سیستم مجزا استفاده میشود. مثلا فرض کنید میخواهیم ایمیل افراد مختلف را از سایتی دریافت کرده و به آنها ایمیل بزنیم. حالا یا این فرآیند را در یک برنامه انجام میدهیم و یا از دو برنامه جدا که هر یک وظیفه خاصی دارند استفاده میکنیم. این مقاله درباره روش دوم است.
مثلا برنامه زرد رنگ ایمیلها را از وب دریافت کرده و به RabbitMQ میفرستد. برنامه دوم هم آدرسها را گرفته و به آنها ایمیل ارسال میکند. با این کار دیگر لازم نیست نگران چفت شدگی منطقهای دو برنامه باهم باشیم. برنامهها منطق خود را دارند و به راحتی کنار هم کار میکنند. پس هدف کلی این ابزار، ایجاد ارتباط بین سیستمهای مختلف است.
پروتکل AMQP
پروتکل بایدها و نبایدهایی است که موجودیتهای مختلف برای این که بتوانند باهم ارتباط برقرار کنند، باید آن را رعایتکنند. مثلا پروتکلهای بهداشتی در ایام کرونا که بایدها و نبایدهایی بود برای این که بتوانیم در این ایام باهم تعامل کنیم یا پروتکلهای وب که بایدها و نبایدهایی است برای تعامل در سطح شبکه.
این پروتکلها به خودی خود، پیادهسازی نیستند بلکه فقط تعریف کننده قوانین هستند. حال ابزارهای مختلف این قوانین را پیادهسازی میکنند تا در جاهای مختلف مورد استفاده قرار گیرند. Advanced Message Queuing Protocol یا به اختصار AMQP هم یکی از پروتکلهایی است که قوانینی را تعریف میکند که با رعایت آن، میتوان بین سیستمهای مختلف ارتباط ایجاد کرده و اطلاعات رد و بدل کرد و RabbitMQ یکی از ابزارهایی است که این پروتکل را پیاده کرده است.
این پروتکل بخشهای مختلفی دارد که سعی میکنیم هرکدام رو توضیح دهیم.
تولیدکننده پیام یا Producer: عضوی که وظیفه ارسال پیام را دارد. در مثال قبل، برنامه زرد، ایمیلها را خزش میکرد و به RabbitMQ میفرستاد.
مصرفکننده یا Consumer: عضوی که وظیفه دریافت پیام را دارد و از آن استفاده میکند. در مثال قبل، برنامه آبی، ایمیلها را دریافت کرده و پردازش مورد نظر خود را روی آنها انجام میداد (نوشتن کدی برای ارسال ایمیل).
مبادلهکننده یا Exchange: عضوی که پیامها را از تولیدکننده دریافت میکند و به صف متناسب انتقال میدهد. مصرفکنندهها به این صف وصل میشوند نه به خود Exchange.
صف یا Queue: عضوی که پیامهارا از Exchange دریافت کرده و در خود ذخیره میکند تا زمانی که توسط یک مصرفکننده استفاده گردد.
کلید مسیریابی یا Routing Key: به فرآیند ارسال پیام به Exchange و تصمیمگیری Exchange برای ارسال این پیام به صف درست، مسیریابی گفته میشود. در این مسیریابی، عنصری به اسم کلید مسیریابی دخیل است. این کلید به صورت یک متن است و به محتوای اصلی اضافه میشود و بعد، Exchange تصمیم میگیرد که بر اساس این کلید، محتوا را به کدام صف تحویل دهد.
اتصال یا Binding: کلیدی که یک صف را به یک Exchange وصل میکند.
همانطور که درباره مسیریابی گفتیم، این فرآیند باعث میشود یک پیام به یک صف خاص یا صفهای خاص انتقال پیدا کند. در این مسیریابی سه عنصر تاثیر بسیار زیادی دارند. Routing Key - Binding - Exchange. ما در RabbitMQ انواع مختلفی از Exchange ها را داریم که هر کدام رفتار خاصی دارند. مثلا یک نوع Exchange پیامهای دریافتی خود را، به همه صفهایی که به آن Exchange وصل شدهاند ارسال میکند. اما Exchange هایی هم داریم که پس از دریافت پیام، ابتدا Routing Key و Binding را بررسی کرده و بعد تصمیم به ارسال پیام به صف مناسب میکنند. پس این سه عنصر در فرآیند مسیریابی بسیار دخیل هستند.
زبان Erlang
برای پیادهسازی RabbitMQ از زبان برنامهنویسی Erlang استفاده شده است. از این زبان برای سناریوهایی استفاده میشود که تمرکز زیادی روی انتقال اطلاعات از فواصل دور دارند. این سناریوها عموما از شبکههای مختلف از جمله شبکه تلفن همراه و بیسیم برای انتقال اطلاعات استفاده میکنند. همزمانی، توزیع و مقیاس پذیری، تحمل خطا و ... از ویژگیهای این زبان هستند که RabbitMQ از همین ویژگیها برای قابلیت اطمینان ارسال پیامها و سایر ویژگیهای مورد نیاز خود استفاده میکند.
انواع مختلف Exchange
برای نمایش انواع مختلف Exchangeها از سایتی با این آدرس https://tryrabbitmq.com استفاده شده است. بهتر است خودتان هم موارد گفته شده را تست کنید.
نوع شماره 1: Direct Exchange: در این نوع اگر Routing Key با Binding Key برابر باشد، پیام به این صف انتقال مییابد. در مثال پایین، توپهای سفید پیامهایی هستند که Routing Key آنها شامل مقدار errors است پس Exchange پس از دریافت این پیامها، آنها را به صفی ارسال میکند که با Binding Key آنهم مقدارش errors باشد. (صف سمت راست). دقت داشته باشید که یک صف هم در سمت چپ قرار دارد که مقدار Binding Key آن برابر log است و فقط پیامهایی به این صف میآید که مقدار Routing Key آنها برابر با log باشد.
نوع شماره 2: Default Exchange: در این نوع، مقدار Binding Key برابر با اسم صف است. دقت داشته باشید در حالت قبل، ما میتوانستیم یک نام برای صف و یک مقدار متفاوت برای Binding اختصاص بدهیم ولی در این حالت هر دو یکی است. نحوه ارسال پیامها مانند Direct Exchange است.
نوع شماره 3: Topic Exchange: در این نوع، مقدار Binding Key برابر الگویی است که همخوانی Routing Key با این الگو مشخص میکند که پیام به کدام صف منتقل شود. برای ساختن این الگو از دو نماد استفاده میشود. یکی * به معنی یک کلمه و # به معنی 0 یا بینهایت کلمه. مثلا اگر Binding Key برابر با *.error باشد، این یعنی همه پیامهایی که Routing Key آنها برابر با مقادیری مثل error.ali - error.book - error.anything باشد به این صف انتقال پیدا میکنند یا مثلا اگر Binding Key برابر با #.error باشد، این یعنی همه پیامهایی که Routing Key آنها برابر با مقادیری مثل error.ali.reza.hamid.book - error - error.word باشد به این صف انتقال پیدا میکنند.
در عکس دوم ما پیامی را با Routing Key معادل با error.a ارسال کردیم. چون این Routing Key شامل هردو الگو میشود پس به هردو صف وارد میگردد.
نوع شماره 4: Fanout Exchange: در این نوع، مقدار Binding Key و Routing Key اهمیتی ندارد چرا که پیام وقتی به Exchange برسد، به همه صفها انتقال مییابد.
ویژگیهای RabbitMQ
حال بیایید با تعدادی از ویژگیهای RabbitMQ آشنا شویم.
پایداری پیام یا Message Durability: این امکان در RabbitMQ وجود دارد که پیامها را در دیسک ذخیره کند تا درصورت خاموش شدن ماشین یا هر اتفاق دیگری، پیامها قابل بازیابی باشند. البته این قابلیت هم در پیامها و هم درباره صفها وجود دارد. درواقع شما میتوانید صفهای خود را Durable کنید تا درصورتی که Exchange به هر دلیلی از دسترس خارج شد یا ریستارت شد، صفها بازیابی شوند.
تایید دریافت پیام یا Message Acknowledgment: این قابلیت وجود دارد که مصرفکننده پیام، پس از این که پیام را دریافت کرد، یک تایید به RabbitMQ ارسال کند تا RabbitMQ از ارسال و تحویل آن به مصرفکننده اطمینان پیدا کند. این کار باعث میشود پیام گم نشود. درصورتی که Exchange این تایید را دریافت نکند، پیام را از حافظه خود پاک نمیکند بلکه عملیات لازم برای ارسال دوباره پیام انجام میدهد.
تایید ارسال پیام یا Publisher Confirms: مانند قابلیت قبلی است با این تفاوت که اینبار Exchange به فرستنده تاییدی ارسال میکند مبنی بر این که پیام فرسنده دریافت و ذخیره شده است. در صورتی که فرستنده این تایید را دریافت نکند میتواند دوباره پیام خود را ارسال کند.
در دسترس بودن یا High Availability: یکی دیگر از قابلیتهای RabbitMQ این است که میتوان چندین Node از آن را بالا آورد و تمام این کلاستر به صورت یک سیستم فعالیت کند و درصورت خاموش شدن یک ماشین، میتوان اطمینان داشت که Node های دیگر به کار خود ادامه میدهند و مانع از پایین بودن کل سیستم میشوند.
فعالیت عملی
متاسفانه الان فرصت این رو ندارم که مثال عملی براتون بنویسم و از طرفی خود داکیومنت RabbitMQ مثالهای خوبی داره و میتونید از اونها استفاده کنید. با این حال شاید در آینده یه مقاله دیگه یا ویدئو ازش ساختم و براتون آپلود کردم. لطفا هر سوالی داشتید ازم بپرسید. اگر بتونم حتما جواب میدم.