با این وجود، علیرغم این شک و تردیدها، الگوی معماری میکروسرویس مزایای قابل توجهی دارد، به ویژه هنگامی که با توانایی توسعه سریع و تحویل برنامههای سازمانی پیچیده همراه میشود.
در این مقاله به معرفی میکروسرویسها و اینکه چرا باید از آنها استفاده کنیم میپردازیم.
ساخت برنامههای یکپارچه (Monolithic)
بیایید تصور کنیم که شما شروع به ساخت یک برند جدید برنامه تاکسی کردهاید تا با اسنپ و تپسی رقابت کنید. پس از یک سری جلسات اولیه و جمعآوری نیازها، شما میتوانید یک پروژه جدید را به صورت دستی یا از یک تولیدکننده که با Rails، Spring Boot، Play یا Maven همراه است استفاده کنید. این برنامه جدید ما همانند شکل زیر، یک معماری شش ضلعی ماژولار دارد:
در هسته برنامه business logic است، که توسط ماژولهایی که سرویسها، آبجکتهای دامنه، و رویدادها را تعریف میکند پیادهسازی شده است. اطراف هسته آداپتورهایی هستند که با دنیای خارج در ارتباطند. نمونههایی از آداپتورها شامل مؤلفههای دسترسی به دیتابیس، مؤلفههای پیامرسانی که پیامها را تولید و مصرف میکنند و مؤلفههای وب که APIها یا پیادهسازی UI را نمایش میدهند میباشد.
با وجود داشتن یک معماری ماژولار به صورت منطقی، برنامه به صورت پکپارچه بستهبندی و منتشر میشود. فرمت واقعی به زبان و فریمورک بستگی دارد. مثلا بسیاری از برنامههای جاوا به صورت فایلهای WAR بستهبندی شده و روی برنامههای سرور مثل Tomcat یا Jetty منتشر میشود. سایر برنامههای جاوا به صورت JARهای قابل اجرای مستقل بستهبندی میشوند. به طور مشابه برنامههای Rails و Node.js به عنوان دایرکتوریهای سلسله مراتبی بستهبندی میشوند.
برنامههای نوشته شده به این سبک بسیار متداول هستند. توسعه آنها ساده است زیرا ویرایشگرها و ابزارهای دیگر بر روی ساخت برنامههای واحد متمرکز هستند. این نوع برنامهها برای تست نیز ساده هستند. شما میتوانید تست end‑to‑end را به سادگی با راهاندازی برنامه و تست UI با Selenium پیادهسازی کنید. انتشار برنامههای یکپارچه نیز ساده است. شما فقط باید برنامه بستهبندیشده را برای سرور کپی کنید. همچنین میتوانید برنامه را با اجرای چندین نسخه در پشت یک load balancer مقیاسپذیر کنید. در مراحل اولیه پروژه به خوبی کار میکند.
بررسی دنیای یکپارچگی
متأسفانه این رویکرد ساده محدودیت بزرگی دارد. برنامههای موفق عادت دارند با گذشت زمان رشد کرده و درنهایت بزرگ شوند. طی هر مرحله، تیم توسعه شما کمی موارد بیشتری را پیادهسازی میکند، که البته این به معنای افزودن خطوط کد بسیاری است. بعد از گذشت چند سال برنامه ساده و کوچک شما به یک هیولای بزرگ تبدیل میشود.
وقتی برنامه شما به یک برنامه یکپارچه بزرگ و پیچیده تبدیل شد، سازمان توسعه شما احتمالا در دنیایی از درد و رنج قرار میگیرد. مشکل اساسی این است که برنامه بسیار پیچیده شده است. درک کامل موارد برای هر توسعهدهنده مشکل است. در نتیجه رفع اشکالات و اجرای صحیح ویژگیهای جدید دشوار و وقتگیر میشود. علاوهبراین، این روند یک مارپیچ رو به پایین میشود. اگر درک کد مشکل باشد، تغییرات به درستی انجام نخواهد شد. شما با یک هیولای یکپارچه بزرگ غیرقابل فهم روبهرو خواهید شد.
توسعه کندتر میشود. هر چه برنامه بزرگتر میشود، زمان راهاندازی آن طولانیتر میشود. اگر توسعهدهندگان مجبور باشند سرور را مرتبا راهاندازی مجدد کنند، زمان زیادی از روز را باید منتظر بمانند و بهرهوری آنها دچار مشکل میشود.
مشکل دیگر برنامههای یکپارچه بزرگ و پیچیده این است که مانع انتشار مداوم است. امروزه وضعیت برنامههای SaaS این است که روزانه بارها و بارها تغییرات را به سمت تولید سوق میدهند. انجام این کار با معماری پیچیده monolith یا یکپارچه بسیار دشوار است، زیرا باید برای بهروزرسانی هر بخش آن کل برنامه را مجددا منتشر کنیم. زمانهای طولانی راهاندازی که قبلا به آن اشاره کردیم نیز کمکی نمیکنند. همچنین از آنجایی که تاثیر یک تغییر معمولا به خوبی درک نشده است، احتمالا مجبور هستید تست دستی گستردهای را انجام دهید. درنتیجه، انتشار مداوم در مرحله بعدی غیرممکن است.
برنامههای یکپارچه همچنین وقتی ماژولهای مختلف موردنیاز با یکدیگر تداخل دارند نیز میتوانند برای مقیاسپذیری دشوار باشند. مثلا یک ماژول ممکن است منطق پردازش تصویر متمرکز بر CPU را پیادهسازی کند و به صورت ایدهآل در نمونههای کامپیوترهای بهینهشده Amazon EC2 منتشر شود. یک ماژول دیگر ممکن است یک دیتابیس درون حافظهای باشد و برای نمونههای حافظه بهینهشده EC2 مناسب باشد. با این حال، به دلیل اینکه این ماژولها در کنار هم مستقر شدهاند، باید در انتخاب سختافزار سازش کنید.
یکی دیگر از مشکلات برنامههای یکپارچه قابلیت اطمینان است. از آنجا که همه ماژولها در همان فرآیند در حال اجرا هستند، یک باگ در هر ماژول، مثل نشت حافظه، کل فرآیند را از کار میاندازد. علاوهبراین، از آنجا که تمام نمونههای برنامه یکسان است، این باگ بر دسترسی کل برنامه تأثیر خواهد گذاشت.
آخرین مورد این است که برنامههای یکپارچه به سختی فریمورکها و زبانهای جدید را قبول میکنند. مثلا فرض کنید که شما دو میلیون خط کد را با فریمورک XYZ نوشتهاید. بازنویسی کل برنامه با استفاده از فریمورک جدیدتر ABC بسیار گران خواهد بود ( از نظر زمان و هزینه)، حتی اگر این فریمورک بهتر باشد. درنتیجه، مانع بزرگی برای قبول تکنولوژیهای جدید وجود دارد. شما در هر تکنولوژیی که در ابتدای پروژه انتخاب میکنید، گیر میافتید.
به طور خلاصه، شما یک برنامه تجاری مهم دارید که به یک هیولای بزرگ تبدیل میشود که توسعهدهندگان کمی آن را درک میکنند. مقیاسپذیری نرمافزار دشوار است و غیر قابل اطمینان میباشد. در نتیجه توسعه سریع و تحویل برنامهها غیرممکن است.
پس با این اوصاف چه کار باید کرد؟
میکروسرویسها، مقابله با پیچیدگی
بسیاری از سازمانها مثل Amazon، eBay و Netflix، این مشکل را با الگوی معماری میکروسرویس حل کردهاند. هدف این است که به جای ساخت یک برنامه بزرگ یکپارچه، برنامه را به مجموعهای از سرویسهای کوچکتر و متصل تقسیم کنیم.
یک سرویس به طور معمول مجموعهای از ویژگیها یا قابلیتهای متمایز، مثل مدیریت سفارش، مدیریت مشتری و غیره را پیادهسازی میکند. هر میکروسرویس یک برنامه کوچک است که دارای معماری شش ضلعی خاص خود است که شامل business logic به همراه آداپتورهای مختلف است. برخی از میکروسرویسها میتوانند یک API را که توسط میکروسرویسهای دیگر یا کلاینتهای برنامه استفاده میشود را نمایش دهند. سایر میکروسرویسها ممکن است رابط کاربری وب را پیادهسازی کنند. در زمان اجرا، هر نمونه اغلب یک cloud VM یا Docker container است.
مثلا تجزیه احتمالی سیستم شرح داده شده در تصویر زیر نشان داده شده است:
هر بخش کاربردی برنامه اکنون توسط میکروسرویس خود پیادهسازی شده است. علاوهبراین، برنامه وب به مجموعهای از برنامههای وب سادهتر تقسیم شده است (مثل یکی برای مسافران و یکی برای رانندگان تاکسی). این امر باعث میشود تا تجربیات متمایز برای دستگاهها، کاربران خاص یا موارد استفاده تخصصی آسانتر شود.
هر سرویس backend یک REST API را به نمایش میگذارد و بیشتر سرویسها APIهای ارائه شده توسط سایر سرویسها را مصرف میکنند. مثلا Driver Management از سرویس Notification استفاده میکند تا بگوید یک راننده برای سفر در دسترس است. سرویسهای UI سرویسهای دیگر را فراخوانی میکنند تا صفحات وب را رندر کنند. سرویسها همچنین ممکن است از ارتباطات مبتنی بر پیام، غیرهمزمان استفاده کنند.
برخی REST APIها نیز برای برنامههای موبایل هستند که توسط رانندگان و مسافران استفاده میشوند. با این حال، برنامهها دسترسی مستقیم به backendندارند. در عوض، ارتباط با واسطهای معروف به API Gateway صورت میگیرد. API Gateway مسئول وظایفی همانند load balancing، caching، کنترل دسترسی، سنجش API و نظارت است، و میتواند با استفاده از NGINX به طور موثر پیادهسازی شود.
مزایای میکروسرویسها
الگوی معماری میکروسرویس دارای چندین مزیت مهم است. ابتدا مساله پیچیدگی را برطرف میکند. این معماری برنامههای یکپارچه بزرگ را به مجموعهای از سرویسها تجزیه میکند. در حالی که کل عملکرد تغییر نمیکند، برنامه به بخشها و سرویسهای قابل کنترل تقسیم میشود. الگوی میکروسرویس سطح ماژولار را اجرا میکند که در عمل دستیابی به آن با کد پایه monolithic یا همان یکپارچه بسیار دشوار است. درنتیجه سرویسهای منحصربهفرد سریعتر منتشر میشوند و درک و نگهداری آن بسیار سادهتر است.
دوم اینکه این معماری هر سرویس را قادر میسازد تا به صورت مستقل توسط تیمی که بر آن سرویس تمرکز دارد توسعه یابد. توسعهدهندگان آزاد هستند تا هر تکنولوژی مناسبی را انتخاب کنند، در صورتی که سرویس به قوانین API احترام بگذارد. البته بیشتر سازمانها تمایل به جلوگیری از هرج و مرج کامل و محدود کردن گزینههای تکنولوژی هستند. با این حال این آزادی عمل بدان معناست که توسعهدهندگان دیگر ملزوم به استفاده از تکنولوژیهای احتمالا منسوخشده در شروع پروژه نیستند. هنگام نوشتن یک سرویس جدید، آنها میتوانند از تکنولوژیهای فعلی استفاده کنند. علاوهبراین، از آنجا که سرویسها نسبتا کوچک هستند، بازنویسی سرویس قدیمی با استفاده از تکنولوژی فعلی امکانپذیر است.
سوم اینکه الگوی معماری میکروسرویس هر میکروسرویس را قادر میسازد تا به صورت مستقل منتشر شود. توسعهدهدگان هرگز نیاز به هماهنگکردن تغییراتی که در سرویسهایشان به صورت لوکال هستند ندارند. این نوع تغییرات به محض اینکه آنها تست میشوند منتشر میشوند.
درنهایت، الگوی معماری میکروسرویس هر سرویس را قادر میسازد تا به صورت مستقل مقیاسبندی شود. شما میتوانید فقط تعدادی از نمونههای هر سرویس را که ظرفیت و محدودیتهای دسترسی آن را برآورده میسازد منتشر کنید. علاوهبراین، میتوانید از سختافزاری استفاده کنید که به بهترین شکل با منابع مورد نیاز سرویس مطابقت داشته باشد. مثلا میتوانید یک سرویس پردازش تصویر متمرکز بر CPU را روی نمونه کامپیوترهای بهینهشده EC2 منتشر کنید.
موانع و اشکالات میکروسرویسها
مانند هر تکنولوژی دیگری، میکروسرویس نیز دارای اشکالاتی است. یکی از این اشکالات خود نام آن است. اصطلاح میکروسرویس بیش از حد به اندازه سرویسها تأکید دارد. در حالی که سرویسهای کوچک ترجیح داده میشوند، مهم است که به یاد داشته باشید آنها وسیلهای برای رسیدن به هدف هستند و نه هدف اصلی. هدف میکروسرویسها تجزیه کردن برنامه به منظور تسهیل توسعه و انتشار سریع برنامه است.
یکی دیگر از اشکالات عمده میکروسرویسها پیچیدگی ناشی از این واقعیت است که برنامه میکروسرویسها یک سیستم توزیعشده است. توسعهدهندگان باید یک مکانیسم ارتباطی درون فرآیندی را بر اساس پیامرسانی یا RPC انتخاب و پیادهسازی کنند. همچنین آنها باید کدی را بنویسیند که عدم موفقیت را مدیریت کند، زیرا مقصد درخواست ممکن است کند بوده یا در دسترس نباشد. در حالی که هیچ یک از این کارها علوم مربوط به ساخت و پرتاب موشک نیستند، بسیار پیچیدهتر از برنامههای یکپارچه هستند که ماژولها از طریق فراخوانی متدها و پروسیجرها یکدیگر را فراخوانی میکنند.
چالش دیگر مربوط به میکروسرویسها معماری تقسیمبندی شده بانک اطلاعاتی است. تعاملات تجاری که چندین موجودیت تجاری را به روز میکنند تقریبا متداول هستند. این نوع تعاملات برای پیادهسازی در برنامه یکپارچه بدیهی است زیرا یک بانک اطلاعاتی واحد وجود دارد. با این وجود، در یک برنامه مبتنی بر میکروسرویس شما باید چندین پایگاه داده را که متعلق به سرویسهای مختلف است را به روز کنید.
تست برنامههای میکروسرویس نیز بسیار پیچیدهتر است. مثلا با یک فریمورک مدرن مثل Spring Boot بسیار بدیهی است تا یک کلاس تست بنویسید که با یک برنامه وب یکپارچه نوشته شده و REST API آن را تست میکند. در مقابل، یک کلاس تست مشابه برای سرویس نیاز به راهاندازی آن سرویس و هر سرویسی که به آن وابسته است میباشد. یک بار دیگر میگوییم این موضوع دانش مربوط به پرتاب موشک نیست ولی پیچیدگی آن را نباید دست کم بگیرید.
یکی دیگر از چالشهای مربوط به معماری میکروسرویس پیادهسازی تغییراتی است که چندین سرویس را شامل میشود. در برنامههای یکپارچه شما به سادگی ماژولهای مرتبط را تغییر میدهید، تغییرات را ایجاد میکنید و آنها را منتشر میکنید. در عوض، شما در الگوی معماری میکروسرویس باید با دقت برنامهریزی کرده و تغییرات هر سرویس را ایجاد کنید. خوشبختانه، اکثر تغییرات معمولا بر روی یک سرویس تاثیر میگذارند و تغییرات چند سرویس که نیاز به هماهنگی دارند نسبتا نادر است.
انتشار برنامههای مبتنی بر میکروسرویس نیز بسیار پیچیده است. برنامه یکپارچه به سادگی بر روی مجموعهای از سرویسهای یکسان در پشت تعاملات load balancer انجام میشود.
نتیجهگیری
ساخت برنامههای پیچیده ذاتا دشوار است. یک معماری Monolithic فقط برای برنامههای ساده و کم حجم معنا دارد. اگر از آن برای برنامههای پیچیده استفاده کنید، در دنیایی پر از درد و زحمت به سر خواهید برد. الگوی معماری میکروسرویس با وجود موانع و چالشهای پیادهسازی، بهترین انتخاب برای برنامههای پیچیده و در حال تحول است.
در صورتی که به میکروسرویس ها علاقمند شدید پیشنهاد میکنم دوره آموزش Micro Service ها رو مشاهده کنید .
نظرات کاربران در رابطه با این دوره