توسعه دهنده ارشد وب
ارتباط مایکرو سرویس های لاراولی با RabbitMQ
وقتی از معماری یکپارچه (Monolith) استفاده میکنیم، توسعه دادن پروژه های بزرگ دست و پاگیر میشود. به عنوان یک توسعه دهنده لاراول ، این نکته کاملا چالش برانگیز است; زیرا لاراول به ما یک محیط توسعه کاملا فول استک را ارائه می دهد که در آن می توانیم با Front-end و همچنین Back-end در همان پروژه کار کنیم ، به عبارت دیگر یک برنامه یکپارچه (Monolithic application) داشته باشیم. اما اگر بخواهیم از معماری مایکرو سرویس ها بهره ببریم، مراحل کار به چه شکل خواهد بود؟ و ارتباط سرویس های ما به چه شکل برقرار میشود؟ در این مقاله با هم بررسی میکنیم.
قبل از آنکه ادامه دهیم، لازم است تا به چند نکته دست و پا گیر در مورد معماری یکپارچه اشاره کنیم. در این معماری چون تمام عملکرد ها (functionalities) داخل یک پروژه هستند، حتی با کوچکترین تغییراتی باید اپلیکیشن را دوباره دپلوی کنیم، که ممکن است روی کل برنامه تأثیر بگذارد. در مقیاس بالا نگهداری چنین پروژه های بزرگی، مشکل تر میشود. در اینجاست که معماری مایکرو سرویس ها به کمک ما میآید و میتوانیم عملکرد ها را به کامپوننت ها یا اجزای مستقل تفکیک کنیم..
مسلما معماری مایکرو سرویس ها مناسب هر پروژه ای نیست.. اگر شما در حال خواندن این مقاله هستید، من فرض را بر این گرفته ام که پیشاپیش میدانید محل صحیح استفاده از این معماری کجاست و همچنین با نقاط ضعف و قوت آن آشنایی کامل دارید. پس بدون اتلاف وقت سراغ توضیح دادن یکی از قسمت های اصلی در این معماری میرویم.
هنگام کار با این معماری باید زیرساختی را برای ارتباطات داخلی سرویس های خود مهیا کنیم. ۳ روش مطرحی که برای این مهم میتوان استفاده کرد عبارتند از:
- وب سرویس های REST یا (Representational State Transfer)
- کانال RPC یا (Remote Procedure Call)
- مسیج بروکر ها (ابزارهایی مانند Apache Kafka ، RabbitMQ و غیره)
ما در این مقاله قصد داریم استفاده از مسیج بروکر RabbitMQ را در معماری مایکرو سرویس ها بررسی کنیم. یک "مسیج بروکر" به عنوان یک واسطه برای سرویس های ما عمل میکند ، پیام ها را از یک سرویس (Publisher یا تولید کننده) دریافت می کند و آنها را برای انجام کار به دیگر سرویس ها (Subscriber یا مصرف کننده) تحویل می دهد. (در مقالات مختلف ممکن است این ۲ بخش Producer و Consumer نیز خوانده شوند)
خوبی استفاده از RabbitMQ این است که پیام های ما را داخل یک صف قرار میدهد. پس اگر Subscriber مشغول باشد و یا ارتباط آن با شبکه قطع شده باشد، پیام ما در حافظه موقت RabbitMQ ذخیره میشود و هر زمان Subscriber دوباره آنلاین شود، پیام از حافظه موقت به مصرف کننده تحویل داده میشود.
مطالبی که بررسی خواهیم کرد، شامل موارد زیر هستند:
- هدف
- سرویس ابری AMQP
- راه اندازی پروژه لاراولی
- اجرا کردن جاب Ping
- اجرا کردن جاب User
- بررسی بهبود ها
هدف
بیایید با نتیجه آنچه در این مقاله خواهیم ساخت شروع کنیم. ما باید ۲ سرویس مجزا آماده کنیم. یکی از آنها به عنوان مصرف کننده یا Consumer عمل می کند و به هر پیام دریافتی گوش می دهد. و دیگری به عنوان تولید کننده ، Publisher و یا ناشری عمل می کند که برخی پیام ها را منتشر میکند.
همانطور که مشاهده می کنید ، ترمینال سمت راست به عنوان تهیه کننده / ناشر فعالیت می کند. ابتدا یک جاب به نام پینگ از طریق یک کامند در کنسول اجرا میشود ، و سپس جاب دیگری به نام یوزر اجرا شده و اطلاعات کاربر را از سرویس ۱ به سرویس ۲ منتقل میکند. پس وقتی مصرف کننده اطلاعاتی را از ناشر دریافت میکند، میتواند از آن اطلاعات در سیستم خودش استفاده کند.
مسلما برای استفاده از RabbitMQ باید این ابزار را روی سرور و یا محیط توسعه خود نصب کنید، اگر قبلا این ابزار رو نصب کرده اید که هیچ و اگر هم نه، در پایان این مقاله به راحتی RabbitMQ را با استفاده از داکر راه اندازی میکنیم.
سرویس ابری AMQP
علاوه بر نصب RabbitMQ روی سیستم لوکال یک راه استفاده دیگر هم داریم و آن استفاده از سرویس ابری AMQP به عنوان یک سرویس است که میتوانید از وب سایت CloudAMQP.com بهره ببرید. استفاده از این سیستم بسیار ساده است. کافیه ابتدا ثبت نام کنید و یک Instance برای خودتون بسازید. پس از طی این مراحل یک آدرس هاست، یوزر و پسورد و یک vhost دریافت میکنید که میتونید بلافاصله ازش استفاده کنید
این سرویس همچنین امکان استفاده از ابزار مدیریت RabbitMQ رو به شما میده، که میتونید از طریقش کانال های مختلفی بسازید و کانکشن ها و صف ها رو مدیریت کنید.
راه اندازی پروژه لاراولی
نصب فریم ورک لاراول رو بار ها با هم بررسی کردیم.. پس نصب ۲ پروژه مجزای لاراولی رو به عهده خودتون میگذارم. پس از نصب لاراول احتیاج داریم تا پکیج کارآمد vyuldashev/laravel-queue-rabbitmq رو که توسط Valdimir Yuldashev توسعه داده شده رو روی هر دو پروژه نصب کنیم:
حال فایل config/queue.php را باز کرده و یک درایور جدید برای RabbitMQ تعریف کنید.
حالا باید چند متغیری که در تنظیمات بالا تعریف شد را در فایل ENV بگذارید و مقدار دهی کنید. همچنین باید کلید QUEUE_CONNECTION را برابر با نام کانکشنی که در بالا ساختیم (rabbitmq) ، قرار بدهید.
تنها نکته باقیمانده در این بخش این است که این تنظیمات را باید روی هر ۲ پروژه لاراولی اعمال کنید.
اجرا کردن جاب Ping
در این قسمت ۲ جاب مختلف میسازیم تا عملکرد هر ۲ سیستم را تست کنیم. دقت کنید که هر کدام از جاب ها باید در داخل هر ۲ پروژه ساخته شوند. (که علتش رو توضیح میدهم) پس ابتدا دستور زیر رو در هر ۲ پروژه اجرا کنید:
در سرویس Publisher (سرویس ۱) بدنه این جاب خالی است و داخل متد handle هیچ کدی وجود نداره:
و در سرویس Subscriber (سرویس ۲) با استفاده از دستور اکو داریم دریافت شدن یک رویداد (Event) رو شبیه سازی میکنیم:
این در حالیست که در واقع داریم این رویداد رو از طریق سرویس ۱ اجرا و فراخوانی میکنیم. حال برای اینکه در سرویس ۲ بتوانیم به رویدادهای سرویس ۱ گوش کنیم، کافی است دستور زیر را در ترمینال سرویس ۲ اجرا کنیم
حالا که سرویس ۲ آماده است، میتوانیم جاب PingJob رو از طریق سرویس ۱ اجرا (Dispatch) کنیم.
راه اول دیسپچ کردن این جاب استفاده از Tinker و اجرای مستقیم این دستور هست:
و راه دوم دیسپچ کردن این جاب ساخت یک کامند Artisan و اجرای آن در کنسول هست:
حالا میتونید با اجرای دستور زیر در کنسول جاب رو اجرا کنید:
اجرا کردن جاب User
جاب قبلی مثال بسیار ساده ای بود، اما ما همچنین میتونیم داده ها رو به جاب ها پاس بدهیم و در سرویس Subscriber از اون داده ها استفاده کنیم. (کاری که در این جاب انجام خواهیم داد) پس در هر ۲ پروژه دستور زیر رو اجرا میکنیم:
درست مثل جاب قبلی، بدنه متد handle جاب ما در سرویس ۱ خالی است و تنها کاری که انجام میدیم، پاس دادن داده ها از طریق متد سازنده کلاس هست:
حالا در سرویس ۲ داخل متد handle داده ها رو به فرمت Json تبدیل میکنیم و اکو میکنیم...
<پرانتز>
این جا (متد handle) نقطه ای از کدهای ماست که میتونه اتفاق های جالبی بیفته، مثلا:
- یه سری داده توی دیتابیس ذخیره یا آپدیت بشه.
- یا یک Event داخلی در اپلیکیشن Trigger بشه و زنجیره ای از دستورات اجرا بشند.
- یا اینکه از مایکرو سرویس های دیگری استفاده کرد و سایر کارها رو به عهده اونها گذاشت.
<پرانتز/>
بسیار خوب، ادامه میدیم. برای اجرای جابی که ساختیم ، این بار احتیاج داریم تا از طریق متد سازنده اطلاعات کاربر رو در سرویس ۱ به جاب پاس بدیم. (به فرض اینکه حداقل ۱ کاربر توی دیتابیس داشته باشیم) پس از محیط Tinker استفاده میکنیم و دستورات زیر رو اجرا میکنیم:
توجه داشته باشید که در سرویس ۲ باید کامند rabbitmq:consume اجرا شده باشه.. نکته دیگه اینکه در کد بالا داده ای (متغیر user) رو که به کلاس جاب پاس میدیم از نوع آرایه هست; اما چرا؟
اگر آبجکت یک user رو پاس بدیم (مثلا با id شماره ۲) و چنین رکوردی داخل سرویس ۲ موجود نباشه، با یک اکسپشن روبرو میشیم چون که داده ها نمیتونند unserialize بشند. پس بهتره که داده ها رو به شکل آرایه پاس بدیم.
همون طور که برای جاب اول یک دستور Artisan ساختیم، این کار رو برای جاب دوم هم انجام میدیم، تا بتونیم از کنسول این جاب رو اجرا کنیم..
حالا میتونیم داده ها رو به راحتی به مایکرو سرویس هامون ارسال کنیم.
بررسی بهبود ها
- هندلر های کاستوم
شاید این سوال براتون مطرح بشه که چرا باید یک جاب رو در هر ۲ سرویس بسازیم؟ مشکل اینه که اگر ما جابی رو در سرویس Publisher دیسپچ کنیم و اون جاب در سرویس Consumer موجود نباشه، با اکسپشن روبرو میشیم چون اون کلاس/آبجکت در اون پروژه موجود نیست.
اما یک راه حل هم برای این موضوع وجود داره. اگر سری به فایل config/queue.php و بخش درایور rabbitmq بزنید، این امکان وجود داره که از کلاس جاب کاستوم خودتون استفاده کنید. (هر رویداد یا پیامی که به سرویس گیرنده برسه، توسط کلاس جاب کاستوم خودتون مدیریت میشه)
برای استفاده از کلاسهای جاب کاستوم، میتونید به مستندات پکیج در گیت هاب مراجعه کنید.
۲. صف های سفارشی
ویژگی جالب دیگر صف های سفارشی هستند. میتوانیم پیامی را در تنها یک صف خاص منتشر کنیم و یا به یک مایکرو سرویس ارسال کنیم. تنها لازم است تا یک صف سفارشی بسازید.
اگر می خواهید برای یک مایکرو سرویس مشخص کنید که یک صف خاص، به عنوان مثال یک صف سفارشی را هدف قرار دهد ، کلید زیر را به فایل ENV اضافه کنید.
سپس سرویس Consumer شما تنها به پیامی که روی صف سفارشی ارسال شود، گوش میدهد. حال برای ارسال پیام از سرویس Publisher روی یک صف سفارشی میتوان از متد onQueue(‘queuename’) استفاده کرد.
۳. داکرایز کردن RabbitMQ
ساده ترین روش اجرای RabbitMQ (مخصوصا در محیط توسعه) استفاده از داکر است. کافی است داکر روی سیستم شما نصب باشد، سپس میتوانید به راحتی RabbitMQ را با دستور زیر بالا بیاورید:
حال کافی است به پورت 15672 روی localhost مراجعه کنید و پنل مدیریت صف های RabbitMQ را ببینید.
۴. استفاده از Laravel Horizon
اگر با Horizon آشنا باشید، میدانید که این پنل برای مدیریت صف های مربوط به Redis استفاده میشود، نکته جالب که شاید ندانید این که این پنل به راحتی با RabbitMQ نیز سازگار است. تنها کاری که باید انجام دهید افزودن کلید زیر به فایل ENV است.
مطلبی دیگر از این انتشارات
چرا لاراول یک فریمورک مبتنی بر MVC نیست ، و باید MVC را فراموش کنید !
مطلبی دیگر از این انتشارات
نظرسنجی بهترین هاست لاراول در سال 99 ؟
مطلبی دیگر از این انتشارات
لاراول : Mass Assignment