معماری میکروسرویس نسل جدیدی از معماری‌های نرم‎افزاری است که خیلی جدیدا راجع بهش میشنویم، مثل خیلی چیزهای جدید که اسمی برای خودشون دارند. در این نوشته، به این معماری به اختصار اشاره خواهیم کرد و کارهایی که در آویهنگ در این حوزه انجام شده و دستاوردهاش رو بیان میکنیم.

معماری میکروسرویس چیست؟

معماری میکروسرویس عموما در مقابل معماری monolithic اسم برده میشه. خوب حالا سوال پیش میاد که معماری monolithic چی هست؟

نرم افزاری رو تصور کنید که از ماژول‌های مختلف که توی هرکدومش کامپوننت‌های گوناگونی در کنار هم نشستن رو، دارید با تیم خودتون طراحی می‌کنید یا توسعه میدید، یا پشتیبانی میکنید. این نرم‌افزار رو میتونیم مثل یک کشتی خیلی خیلی بزرگ که از طبقات مختلف و بخش‌های گوناگون، از موتورخانه خیلی خیلی بزرگ و منبع سوخت بسیار حجیم و کارکنان مختلف تصور کنیم. خوب پس با این شرایط باید یک کشتی خیلی خیلی بزرگ رو اول طراحی کنیم، با یک تیم که المانهای مختلف این کشتی رو شناختن در فاز اول، همراه بشیم، بعد این تیم رو مدیریت کنیم تا در نهایت این کشتی رو تولید کنه. خوب یک روشی که خیلی‌ها میدونن، این هست که در نهایت این کشتی شکسته میشه به بخش‌های کوچکتر و بخش‌های کوچکتر تولید میشن. بعد این بخش‌ها در کنار هم دوباره قرار میگیرن و در دنیای نرم‌افزار، این بخش‌ها با هم integrate میشن و حالا تست‌های مختلف integration هم انجام میشه و در نهایت کشتی، بعد از مثلا 6 ماه یا بعد از یکسال، آماده به آب انداختن میشه.

 

 
 

حالا انشالله که وقتی کشتی رو به آب انداختیم اجزائش در همون ضربه اولی که از آب دریافت میکنه از هم متلاشی نشه با این آرزو کشتی به آب انداخته خواهد شد و در واقع نرم‌افزار در محیط عملیاتی مستقر خواهد شد. خوب شاید تا اینجا بگیم روال همینه و مشکلی نیست.

 
 

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

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

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

فرض کنیم برای اینکه 1000 تا کانتینر یا مسافر رو با یک کشتی خیلی خیلی بزرگ جابجا کنیم این کشتی خیلی بزرگ رو بشکنیم به قایق‌های تندروی کوچک، اما تعداد زیاد. شاید از این مثال بشه با مفهوم scalability یا دقیقتر با مفاهیمی همچون Horizontal Scalability یا scale out هم مقایسه کرد. (بعدا توی یک نوشته دیگه راجع به این دو مفهوم در معماری‌های نرم‌افزاری، توضیح خواهم داد) توی این معماری جدید شما میتونی چندتا کار انجام بدی:

 
 

  1. هر قایق تندرو رو بدی یک تیم جدا توسعه بده یا شاید دقیقترش اینکه هر کشتی تندرو رو بدی یک دولوپر توسعه بده!!! (سوالهایی پیش میاد که آقا مگه میشه یک دولوپر همه کار یک قایق تندرو رو انجام بده؟)
  2. هر قایق تندرو رو میشه جداگانه تستش کرد.
  3. هر قایق تندرو المان‌های مستقل خودش رو داره، از جمله موتور جدا، باک جدا، بدنه جدا و ...
  4. مطمئننا به آب انداختن یک قایق کوچک (استقرار یک قایق) بسیار ساده‌تر از به آب انداختن یک کشتی اقیانوس‌پیماست.

حالا فرض میکنیم که همه اون بار کشتی بزرگ رو تقسیم کردیم به کشتی های کوچکتر:

 
 

  1. فرض میکنیم که در شرایط مشابه یکی از قایق‌ها با مشکلی در باکش یا موتورش مواجه شده. در این حالت چه اتفاقی میفته؟ بقیه قایق‌ها یا در واقع المان‌ها دارن همچنان به کار خودشون ادامه میدن و به سمت مقصد حرکت میکنند. توی این مدل یک مفهوم دیگه رو هم توضیح بدیم و اون redundancy یا افزونگی هست. به چه معنی؟ به این معنی که فرض میکنیم برای حمل 20 تا جعبه، به جای اینکه هر 20 تا رو توی یک قایق بذاریم، اینها رو در دو قایق به صورت 10 تایی تقسیم میکنیم (load balancing) و این دو قایق با هم و در کنار هم به سمت مقصد حرکت میکنند. حالا اگر یکی از قایق‌ها به هر دلیلی دچار مشکل بشه، میشه 10 تا جعبه‌اش رو به قایق دوم منتقل کرد و اون قایق بره برای تعمیر و هر وقت برگشت، دوباره تقسیم بار انجام بشه. حالا ممکنه در این حالت قایقی که داره 20 تا جعبه رو میبره، نتونه با سرعتی که 10 تا جعبه رو میبرد حرکت کنه (طبیعی هست) ولی مهم اینه که سرویس‌دهی متوقف نشده و در این حالت سرویس شما همچنان کار میکنه، اما کمی کندتر.

    معماری میکروسرویس، مزایای مختلفی رو به همراه داره. اما یادمون باشه که هر نرم‌افزار بر اساس نیازمندی‌ها (عموما non functional) و عرض و عمقش، معماری مختص خودش رو خواهد داشت و یک تجویز نمیتونه همه بیماری‌ها رو درمان کنه.

    در مقالات دیگه، سایر المان‎های معماری‎های میکروسرویس رو توضیح خواهم داد.