بریم سمت معماری مایکروسرویس یا نه؟!

تو دنیای امروز خیلی ترند شده که معمولا هرکسی یه محصول تکنولوژی توسعه میده و کمی از عمرش میگذره یا حتی از همون اولش، میخواد بره سمت معماری مایکروسرویس و سیستمی که توسعه دادن رو به یک سیستم توزیع شده تبدیل کنن! افرادی که دانش مهندسی نرم افزار دارن یا توی این رشته تحصیل کردن در جریان هستن که این مفهوم درباره ی چه چیزی صحبت میکنه و احتمالا باهاش روبرو هم شدن. اما در کل ما چند روش برای توسعه و راه اندازی سیستم های نرم افزاری داریم که دوتا از معروف ترین هاش معماری مونولیتیک (Monolithic architecture) و معماری مایکروسرویس (Microservice) هستن.

قبل از اینکه ادامه مطلب رو بخونید پیشنهاد میدم ویدیو زیر که با همکاری مجموعه سون لرن تهیه شده رو ببینید بعد ادامه مطلب رو مطالعه کنید:

https://www.aparat.com/v/tz21x

از اوایل تاریخ توسعه ی نرم افزار معمولا نرم افزارها رو به صورت مونولیتیک یا مجتمع توسعه میدادن و کل قسمت ها و ماژول ها روی یک پروژه ی مشترک پیاده سازی و اجرا میشد. در نتیجه معمولا هم همه چیز روی یک سرور اجرا میشد و پاسخ درخواست های دریافتی رو میداد. بعد از مدتی که تعداد کاربران فعال روی اینترنت بیشتر شد و محصولات نرم افزاری هم مشتری های بیشتری برای پاسخ دادن پیدا کردن، شرکت هایی که الان دیگه بزرگ تر شده بودن دیدن که انگار نمیشه مثل قبل صرفا با افزایش منابع سرور ها، قدرت و توانایی عملکرد نرم افزار هارو بهتر کرد که بتونن درخواست های بیشتری رو پاسخ بدن. مثلا نمیشه مدام رم یا پردازنده یا بقیه ی منابع سرور رو اضافه کنیم و اصطلاحا Vertical Scaling یا افزایش مقیاس عمودی منطقی نبود.

اصولا ما دو نوع مقیاس بندی داریم: عمودی و افقی یا همون Horizontal and vertical scaling.

در کل وقتی که نیاز داریم نرم افزارمون منابع بیشتری داشته باشه و به کاربران بیشتری پاسخ بده، مجبوریم که به نوعی منابع اون محصولمون رو افزایش بدیم. در حالت عمودی یا ورتیکال به سادگی میشه با افزایش منابع فیزیکی سرور یا به اصطلاح سرور بزرگ تر گرفتن این مشکل رو تا حدودی رفع کرد که البته کاملا منطقی هست. اما از جایی به بعد نرم افزار ما انقدر ممکنه بزرگ بشه که دیگه نشه روی یک سرور مدام این منابع رو ببریم بالا و اینجوری ما یک سرور خیلی بزرگ داریم که ممکنه مشکلات بزرگی برای ما به وجود بیاره و ریسک هایی رو برای کسب و کارها ممکنه به دنبال داشته باشه مثل خطر از بین رفتن اطلاعات یا ایجاد گلوگاه (Bottleneck) که میتونه عملکرد و سرعت نرم افزار مارو تحت تاثیر قرار بده.

با پیشرفت دنیای نرم افزار و بزرگ تر شدن کسب و کارها، اومدن و دنبال راه حل هایی برای این مشکلات گشتن و دیدن که میشه به جای یک سرویس بزرگ که روی یک سرور داره کار میکنه، همون سرویس رو شکست به بخش های کوچک تر و هر ماژول یا سرویس کوچیک رو میشه روی سرور های جداگانه اجرا کرد و اینطوری وظایف هر بخش رو جداگانه به خود همون سرویس بسپاریم و این سرویس ها در عوض با همدیگه در ارتباط باشن و اطلاعاتی که لازم دارن رو رد و بدل کنن (Inter service communication). با این روش میشه فشاری که به کل سیستم میاد رو تا حدودی بین سرویس های کوچیک تری که داریم تقسیم کرد که سیستممون بتونه در تئوری به درخواست های بیشتری پاسخ بده و تحمل فشار بالاتری داشته باشه. چرا گفتم تئوری؟ چون همیشه هم اینطور نیست و ممکنه خود مایکروسرویس مشکلات دیگه ای رو هم ایجاد کنه که ممکنه در معماری متمرکز وجود نداشته باشه!

مزیت دیگه ی مایکروسرویس اینه که وقتی تیم های شرکت ها خیلی بزرگ میشن و تعداد توسعه دهنده ها و در کل افرادی که روی سرویس کار میکنن خیلی زیاد میشه، اگر معماریمون مونولیت یا متمرکز باشه ممکنه توی کار این تیم ها به مشکلاتی بخورن مثلا وابستگی بین تیم ها زیاد بشه و زمان تلف شده برای توسعه ی سرویس ها خیلی بالا بره چون ممکنه هر تیم نتونه به صورت مستقل روی بخش مربوط به خودش کار کنه و یا مجبور باشه مدام منتظر کار بقیه بمونه یا اصطلاحا به تداخل (Conflict) برخورد کنن. اما اگر معماری مایکروسرویس باشه(البته اگر درست و اصولی پیاده بشه!) هر تیم به صورت تقریبا مستقل میتونه روی سرویس های خودش کار کنه و حتی به صورت مستقل ریلیز انجام بده و تغییرات خودش رو زودتر و مستقل از بقیه وارد مدار کنه که کاربران بتونن استفاده کنن. در حالی که توی معماری متمرکز ممکنه مثلا برنامه ی ریلیز شرکت دو هفته یکبار باشه و این باعث میشه که حتی اگر یک تیم کارش رو هم انجام داده باشه نتونه تا زمان ریلیز مشترک شرکت، تغییراتش رو بفرسته بالا و اصطلاحا روی محیط پروداکشن بره! از خوبی ها گفتیم از چالش های مایکروسرویس هم بگیم!

یکی از چالش هایی که ممکنه تیم هایی که مایکروسرویس کار میکنن بهش برخورد کنن مدیریت منابع مخصوصا منابع انسانیه! چون سرویس هایی که جدا میکنیم بخاطر مستقل بودنشون میتونن هر کدوم با یک زبان برنامه نویسی جدگانه یا حتی با دیتابیس ها و در کل با ابزار های متفاوتی توسعه داده بشن و توی مایکروسرویس این انعطاف وجود داره. اما برای مثال وقتی برای یک سرویس یک زبان یا ابزار خاصی رو انتخاب میکنیم ممکنه بعدا برای پیدا کردن نیروی کار متخصص و جایگزین کردن نیروی انسانی به چالش بخوریم. مثلا ما در حال حاضر برای این سرویس جدید ممکنه نیروی متخصص داشته باشیم اما اگر نیروی مورد نظر ما به هر دلیلی قصد قطع همکاری با شرکت رو داشته باشه نیازمند جایگزینیش خواهیم بود و اینجاست که مخصوصا توی جایی مثل ایران ممکنه برای این کار به دردسر دچار بشیم و نیرویی که میخوایم رو نتونیم در زمان مناسب پیدا کنیم.

دومین چالش مهم اینه که بدونیم چطوری و با چه حساب و کتابی هر سرویس رو جداسازی کنیم! بهتره که اول از نظر کسب و کار به سرویس ها و ماژول هامون نگاه کنیم و با همفکری و تحلیل های دقیق اقدام به جداکردن محدوده ی سرویس های مختلف کنیم. اگر حساب شده سرویس هارو جدا نکنیم بعدا ممکنه متوجه بشیم که برای مثال دو سرویسی که جدا کردیم منطقا نباید جدا میبودن و جدا کردنشون بر خلاف تصور باعث تضعیف عملکرد یا باعث افزایش وابستگی بین تیم ها شده! پس باید خیلی روی نحوه ی جدا کردن سرویس ها تحقیق کنیم و بی گدار به آب نزنیم. همین مساله برای خود من پیش اومده و توی دنیای واقعی در یکی از شرکت هایی که کار میکردم این مورد پیش اومد و وقتی که در پروسه ی تفکیک سرویس ها بودیم بعد از جلسه های فراوان متوجه شدیم که جداکردن یک سرویس که قصد تفکیکش رو داشتیم کار درستی نبود و بعد از شنیدن نظرات مختلف و با ارائه ی دلیل و تحلیل، تصمیم گرفتیم که این کار رو نکنیم!

چالش دیگه ای که در معماری مایکروسرویس وجود داره و ممکنه کار مارو کمی سخت تر بکنه بحث Tracing هست که ما توی معماری مونولیت راحت تر میتونیم این کار رو انجام بدیم. وقتی کل سرویس های ما روی یک پروژه هستن و ما هر تکه از پروژه رو جداگانه اجرا نکردیم و کل پروژه با یک ابزار متمرکز توسعه داده شده، ردیابی خطاهایی که داره در سیستم رخ میده راحت تره و همه چیز دم دست ما داره اتفاق می افته و لاگ میشه. اما وقتی ما معماری مایکروسرویس داریم، درخواست هایی که داخل سیستم ما میان از مسیر های مختلفی داخل سیستم ما عبور میکنن و هر سرویس به صورت جداگانه پردازش های مخصوص خودش رو روی اون درخواست انجام میده و ردیابی خطاها در محیط مایکروسرویس به سادگی مونولیت اتفاق نمی افته و به ابزارهای مخصوصی مثل open tracing نیاز داریم که بتونه امکان ردیابی توزیع شده یا همون Distributed Tracing رو به ما بده. به همین خاطر ممکنه تشخیص و برطرف کردن خطاها و مشکلات سیستم سخت تر و زمان بر تر بشه چون پیچیدگی سیستم ما بسیار بالاتر رفته!

زیرساخت مایکروسرویس نیاز به ابزارهایی داره که در حالت عادی معمولا مورد نیاز نیستن مثل service mesh یا انواع ابزار های message queue و ... که تمام این ابزارها نیاز به صرف هزینه ی نگهداری دارن و ما به طور خاص ممکنه تیمی رو برای نگهداری همین ابزار ها نیاز داشته باشیم. به همین دلیل بهتره قبل از رفتن به سمت مایکروسرویس منابع این کار رو داشته باشیم. در اکثر مواقع توسعه ی ورتیکال و همون افزایش منابع زیرساخت و همون مونولیت نگه داشتن سرویس کار منطقی تر و عقلانی تری هست!

در آخر هم اینکه، در دام ترند ها گرفتار نشین و صرفا بخاطر ترند شدن خودتون و تیمتون رو گرفتار کلی هزینه و چالش نکنین. با تحلیل و تحقیق پیش برین و فقط در صورتی به مهاجرت به مایکروسرویس فکر کنین که توجیه خوبی براش پیدا کرده باشین :)