پیامگرایی (Messaging) از جمله رویکردهایی هست که برای ارتباط بین میکروسرویس ها استفاده می شود و همچنین الگوهای ادغام سازمانی (Enterprise Integration Patterns) به اختصار EIP، به الگوهای طراحی اشاره می کنند که برای ادغام نرم افزار هایی استفاده می شود که از رویکرد Messaging استفاده می کنند.
اصطلاح EIP دقیقا برگرفته از کتابی با همین نام است که اولین بار در سال 2003 منتشر شد. در این کتاب راهکارها و استاندارد های مختلفی برای طراحی سیستم های پیامگرا پیشنهاد می شود و سپس یک پیاده سازی ابتدایی برای آن ها ارائه می شود. در ادامه برخی از این الگوها و استاندارد ها را معرفی می کنیم.
جهت بررسی بیشتر می توانید به enterpriseintegrationpatterns.com مراجعه کنید.
فارغ از مزایایی که میکروسرویس ها می توانند برای ما داشته باشند، ادغام آنها چالش های زیادی برای ما دارد که برخی از مهمترین آنها عبارتند از:
توسعه دهندگان برای غلبه بر این چالش ها از روش های گوناگونی استفاده کردند این کتاب به صورت اختصاصی رویکرد پیامگرایی را برای ادغام سرویس ها مورد بررسی قرار می دهد.
پیامگرایی (Messaging)
برای توصیفی دقیق از پیامگرایی اجازه بدهید مثالی خدمتتون ارائه بدهیم. فرض کنید با یک نفر از دوستان خودتان تماس تلفنی برقرار می کنید. در این حالت ارتباط شما از نوع سنکرون می باشد چرا که تا زمانی که با او مکالمه می کنید، نمیتوانید با شخص دیگری تماس بگیرید. حال فرض کنید به هر دلیل امکان تماس با دوستتان را نداشته باشید یا آنقدر مشغول باشید که نتوانید با او مکالمه کنید. در این حالت شما از طریق ایمیل، پیامی برای او ارسال کرده و کار خودتان را از سر میگیرید. دوستتان هر زمان که خواست، ایمیل خود را چک کرده و پیام شما را می خواند این همان چیزی است که به عنوان ارتباط آسنکرون شناخته می شود. پیام گرایی در حقیقت امکان تعامل آسنکرون میان سرویس های شما را فراهم می کند. هر سرویس پیام خود را در کانال قرار داده و کار خودش را ادامه می دهد بدون آنکه منتظر پاسخ گیرنده بماند.
اجزاء اصلی در یک معماری پیامگرا عبارتند از:
قابلیت های پیام گرایی در حقیقت به وسیله واسط جداگانه به نام Messaging system ارائه می شود که با عنوان (message-oriented middleware (MOM هم شناخته می شود. در این واسط، اقدامات مربوط به مدیریت پیام انجام می شود و وظیفه هدایت پیام از تولید کننده به مصرف کننده را دارد. یک سیستم پیامگرا قابلیت ها و اجزاء متفاوتی دارد که خدمت شما شرح خواهیم داد.
در حالت کلی برای انتقال داده در یک معماری پیامگرا:
همانطور که اشاره کردیم Messaging system در حقیقت مانند واسطی میان تولید کننده و مصرف کننده عمل می کند و مدیریت پیام ها را بر عهده دارد. در یک Messaging system باید قابلیت های زیر را وجود داشته باشد:
پیام ها به دلایل مختلف و بین سرویس های متفاوت رد و بدل می شود. سرویس مقصد، قابلیت دریافت هر پیامی را ندارد زیرا برای هر کاربردی ساخته نشده است. سرویس پیامگرا مجموعه ای از اتصالات را دارد که برنامه های کاربردی را قادر می سازد با انتقال اطلاعات به روش های از پیش تعیین شده و قابل پیش بینی ارتباط برقرار کنند.
در حقیقت سرویس ها از طریق کانال با یکدیگر ارتباط برقرار می کنند به طوری که تولید کننده داده را متناسب با نوع استفاده، در کانال مناسب قرار داده و مصرف کننده آنها را به همان شکلی که انتظار دارد از کانال می خواند. هر کانال برای کاربرد ویژه ای استفاده می شود.
سرویس ها برای تعامل با یکدیگر پیام رد و بدل می کنند. یک پیام از دو بخش اساسی تشکیل شده است:
در بسیاری از شرایط ممکن است که یک پیام به مجموعه ای از عملیات برای پردازش نیاز داشته باشد. فرض کنید پیامی از جانب کلاینت برای سرویس ما ارسال می شود. ما ابتدا باید آن را رمزگشایی کرده سپس عملیات احراز هویت برای آن مشتری را انجام داده و در نهایت با حذف پیام های تکراری و اسپم کار خودمان را ساده تر کنیم. اولین راه حل این است که تمام این نیازمندی ها را به صورت یکجا پیاده سازی کنیم. اما انعطاف پذیری را از دست می دهیم، امکان استفاده مجدد را نداریم و همچنین برای آزمون نرم افزار، دچار مشکل می شویم. راه حل دیگر این است که هر کدام از این نیازمندی ها را در مؤلفه های جداگانه پیاده سازی کنیم. با این وجود مشکل ما به طور کامل حل نمی شود. به عنوان مثال، در نظر بگیرید که مولفه احراز هویت برای عملکرد درست نیاز دارد تا پیام را به صورت رمزگشایی شده دریافت کند. در این شرایط مجبوریم مولفه ها را به صورت ترتیبی از مراحل پشت سرهم، ترکیب کنیم.
یک سیستم پیامگرا باید این امکان را فراهم کند تا بتوانیم یک پردازش بزرگ را در قالب مجموعه ای از پردازش های کوچکتر (Process) و به صورت پشت سرهم (Pipe) انجام دهیم.
مسیریاب پیام را در حقیقت می توان فیلتری در نظر گرفت که پیام را از کانال ورودی دریافت کرده و با توجه به مجموعه ای از شروط مشخص می کند که آن را برای کدام یک از کانال های خروجی هدایت کند. گفتیم که هر پیام علاوه بر بدنه می تواند مجموعه ای هدر ها را هم داشته باشد که یکی از مهمترین کاربرد آن ها در این قسمت می باشد. مسیریاب از این هدر ها استفاده کرده و آن را برای کانال مشخصی ارسال می کند.
گفتیم که یکی از چالش های مهم ادغام میکروسرویس ها، پیاده سازی مختلف آنهاست. هر سرویس برداشت متفاوتی از <<مشتری>> خواهد داشت و به شکل جداگانه ای آن را پیاده سازی می کند. در این شرایط باید داده دریافتی را به شکل صحیح برای سرویس گیرنده تبدیل کنیم.
تبدیل کننده پیام در حقیقت فیلتر مخصوصی است که داده دریافتی را به فرمت قابل قبول برای گیرنده تبدیل می کند.
سرویس و سیستم پیامگرا دو مفهوم جداگانه هستند. سیستم های پیامگرا را می توان در حقیقت به عنوان یک سرور در نظر گرفت که وظیفه آن صرفا مدیریت پیام ها و هدایت آن ها به سمت مقصد می باشد. در حالی که سرویس چیزی از مفهوم پیام نمی داند و صرفا با داده خاصی کار می کند که از پیام استخراج می شود. سرویس ها در حالت عادی نمی دانند که چگونه از سیستم پیامگرا استفاده کنند. Message Endpoint در حقیقت واسطی است که به سرویس امکان بهره برداری از سیستم پیامگرا را می دهد. سرویس با استفاده از نقطه پایان، پیام ها را به کانال ارسال می کند یا از آن دریافت می کند.
در این قسمت برخی از خصوصیات بخش قبل را به صورت دقیق تر بررسی می کنیم
در حالت کلی کانال ها به به دو شکل میتوانند باشند:
همتا به همتا(Point to Point): در این نوع از کانال ها معمولا تعامل میان یک تولید کننده و یک مصرف کننده صورت می گیرد. در صورتی که چندین مصرف کننده بخواهند همزمان از کانال همتا به همتا استفاده کنند، در این صورت هر پیام داخل کانال فقط به وسیله یکی از مصرف کننده ها استفاده می شود.
پخشی(Publish-Subscribe): این نوع کانال معمولا به وسیله یک تولید کننده و چندین مصرف کننده استفاده می شود. هر مصرف کننده در حقیقت یک کپی از پیام داخل کانال را دریافت می کند.
نقطه پایان (Message Endpoint) واسط میان سرویس و سیستم پیامگرا می باشد و سرویس از طریق آن پیامی را به کانال ارسال می کند. آداپتور کانال در حقیقت برعکس عمل کرده و میان سیستم پیامگرا و سرویس عمل می کند. در یک معماری پیام گرا همه سرویس ها لزوما به وسیله خود شما توسعه داده نمی شود. برای مثال برای کار با یک پایگاه داده خاص یا بهره گیری از واسط های ارائه شده یک نرم افزار دیگر از آداپتور کانال استفاده می شود.
سرویس ها به وسیله کانال با یکدیگر ارتباط دارند. سیستم های پیامگرای مختلف برای تعامل از پل پیام استفاده می کند. یک پل پیام در حقیقت از مجموعه ای از آداپتورها استفاده می کند که ارتباط میان سیستم های پیامگرا را تسهیل می کنند. کارگزاران پیام، نظیر ActiveMQ، Apache Kafka یا RabbitMQ به عنوان پل پیام استفاده می شوند.
در حالت کلی پیام های رد و بدل شده در معماری پیامگرا در سه دسته تقسیم می شوند:
پیام فرمان (Command Message): برای فراخوانی روند در سرویس دیگر استفاده می شود.
پیام داده (Document Message): داده خاصی را به سرویس دیگر ارسال می کند. مصرف کننده آزاد است که هر کاری با سند دریافتی انجام دهد.
پیام رویداد (Event Message): به طور خاص برای کاربرد های آسنکرون استفاده می شود که تولید کننده وقوع رویدادی را به مصرف کننده اطلاع می دهد.
در بسیاری از شرایط نیاز است تا تولید کننده به ازای هر پیام ارسالی، پاسخی از گیرنده دریافت کند. به عنوان یک مثال ساده تولید کننده ای را در نظر بگیرید که از یک سرویس Restful استفاده می کند و طبعا برای هر درخواست به پاسخی نیاز دارد. برای پیاده سازی این حالت در معماری پیامگرا از یک کانال برای درخواست و کانال دیگر برای پاسخ استفاده می شود.
مصرف کننده از طریق نقطه پایان، با سرویس پیامگرا تعامل داشته و پیام ها را دریافت می کند. نقطه پایان ها برای مصرف کننده دو حالت را فراهم می کنند:
مصرف کننده رویداد محور (Event Driven Consumer): که به عنوان دریافت کننده آسنکرون هم شناخته می شود. در این حالت مصرف کننده منتظر دریافت پیام بوده و بلافاصله پس از دریافت، آن را پردازش می کند.
مصرف کننده خودمختار (Polling Consumer): دریافت کننده سنکرون که برای گرفتن پیام از یک ساختار خارجی استفاده می شود (برای مثال یک پایگاه داده یا استفاده از واسط های نرم افزاری دیگر). در حقیقت مصرف کننده، هر زمان که بخواهد پیامی را دریافت کرده و آن را پردازش می کند.
در معماری پیامگرا مدیریت سیستم شامل موارد زیر می باشد:
در ادامه ویژگی های هر کدام را به صورت مختصر شرح می دهیم
در حالت کلی، نظارت و کنترل شامل انجام کارهایی است که به منظور بررسی و کنترل یک سیستم پیامگرا انجام می شود. معمولا سیستم های پیامگرا توزیع شده هستند و نیازمند ساز و کاری هستیم که بتوانیم کنترل کاملی بر همه اجزاء داشته باشیم.
گذرگاه کنترل (Control Bus)، امکان مدیریت کل سیستم را برای ما فراهم می کند. این رویکرد در حقیقت از همان مکانیزم کانال برای ارسال پیام استفاده می کند با این تفاوت که از کانالهای جداگانه برای انتقال دادههایی استفاده میکند که مربوط به مدیریت اجزای درگیر در سیستم پیامگرا است.
در شرایط خاصی ممکن است نیاز باشد که پردازش های اضافه تری را بر پیام ها انجام بدهیم (مثلا به دلایل رفع اشکال یا بررسی داده هایی که در یک کانال رد و بدل می شوند). در این حالت می توانیم با ایجاد یک انحراف(Detour) در کانال عملیات بیشتری را روی داده ها انجام بدهیم. اینکه مشخص کنیم چه زمانی و کدام پیام ها از کانال انحراف عبور کنند به کمک گذرگاه کنترل انجام می شود.
کانال نقطه به نقطه به طور معمول برای پیام های نوع داده استفاده می شود زیرا همانطور که گفتیم، این اطمینان وجود دارد که هر پیام صرفا به وسیله یک مصرف کننده استفاده می شود. با این وجود برای اهدافی مانند بازرسی پیام ها، آزمون و رفع خطا این کانال ها گزینه خوبی هستند. برای اینکه بتوانیم پیام های یک کانال را به صورت جداگانه بازرسی کنیم، معمولا با ایجاد یک کانال اضافه تر به وسیله Wire Tap، یک کپی از پیام داخلِ کانالِ فعلی، به کانال دیگری هدایت می شود تا بتوانیم حالت فعلی یک پیام را به خوبی بررسی کنیم.
وابستگی کم از ویژگی های مهم یک معماری پیامگرا می باشد. مصرف کننده با دریافت پیام نمی داند که دقیقا کدام تولید کننده آن را ارسال کرده و پیام ها ساختار مشخصی داشته و به تولید کننده اش ارتباطی ندارد. این ویژگی به طور خاص رفع اشکال و آنالیز یک سیستم پیامگرا را با چالش هایی مواجه می کند چرا که دقیقا نمی دانیم که یک پیام چه مسیری را برای رسیدن به مقصد طی کرده است. چگونه میتوانیم جریان پیامها در یک سیستم را به طور مؤثر تجزیه و تحلیل و اشکالزدایی کنیم؟
برای حل این مشکل می توانیم در هر سرویس به پیام تاریخچه ای از آن را پیوست کنیم. این اطلاعات در هدر یک پیام ثبت می شود و در نهایت می دانیم که چه اتفاقاتی برای آن پیام در طول مسیر افتاده است.
آزمون یک سیستم پیامگرا قبل از استقرار آن مهم است اما نباید صرفا به قبل از استقرار محدود شود. قابلیت پیام آزمون (Test Message) این امکان را برای ما فراهم می کند تا بتوانیم پس از استقرار نرم افزار عملکرد آن را زیر نظر داشته باشیم. در این رویکرد، پیامی صرفا برای بررسی عملکرد مولفه ها میان کانال های مختلف رد و بدل می شود.
برای به کار بردن این الگوها نیاز به چارچوبی داریم که آن ها را از قبل پیاده سازی کرده باشد. در قسمت بعد سعی می کنیم یکی از مهمترین ابزارهای این رویکرد را به شما معرفی کنیم.