یک برنامه کاربردی مبتنی بر معماری میکروسرویس خوش ساخت می تواند با مقیاس پذیر بودن، انعطاف پذیری و قابلیت اطمینان در برابر اکثر مسائلی که ممکن است در راه است، در تست زمان مقاومت کند.
این معماریها به دلیل مولفههای جفتشده آزاد که میتوانند به طور مستقل اجرا شوند، به سطح بالایی از انعطافپذیری دست مییابند، بنابراین تحت تأثیر سایر میکروسرویس های درون برنامه قرار نمیگیرند.
با این حال، همیشه راههایی وجود دارد که یک معماری میکروسرویس میتواند شکست بخورد و ناکارآمد شود.
در این مقاله، ما به برخی از رایجترین ضد الگو (آنتی پترن) یا طراحی که میتوانند مشکلاتی را در معماری مبتنی بر میکروسرویس نشان دهند، بررسی میکنیم.
1. Monolith در میکروسرویس ها
اگر میخواهید با حفظ معماری یکپارچه (monolith)، میکروسرویس بسازید، با مشکلات مقیاسپذیری، تحمل خطا و بسیاری موارد دیگر مواجه خواهید شد. این اغلب ناشی از:
پایگاه های داده مشترک: هنگامی که در حال ساخت میکروسرویس هستید، اغلب ایده خوبی است که برای هر سرویس یک پایگاه داده داشته باشید. این به شما امکان می دهد نوع پایگاه داده، قوانین اسکیما، ظرفیت IOPS را بر روی یک قانون هر سرویس کنترل کنید، بنابراین به شما امکان می دهد کنترل دقیق تری بر مقیاس بندی داشته باشید. اما، اگر از یک پایگاه داده واحد برای تمام سرویس های خود استفاده کنید، رشد برنامه خود را سخت تر می کنید.
استقرار پیچیده: با وجود اینکه به سرویس های کوچکتر تجزیه می شود، روند استقرار هنوز پیچیده و زمان بر است و به هماهنگی بین تیم های مختلف و مشارکت دستی نیاز دارد. این چابکی و انعطاف پذیری حاصل از اجرای میکروسرویس ها را محدود می کند.
مرزهای سرویس ناکافی: مرزهای سرویس مشخص نشده منجر به همپوشانی عملکرد و مالکیت نامشخص می شود. این امر می تواند منجر به تکرار کارها و مشکلات در کنترل و بهبود معماری شود.
بنابراین، برای جلوگیری از یکپارچگی در میکروسرویسها، توصیه میکنم با یک پایگاهداده واحد در هر میکروسرویس همراه با تعریف مالکیت واضح میکروسرویس های خود از طریق طراحی Domain Driven پیش بروید.
برای آشنایی با معماری میکروفرانت اند می توانید این مقاله را بررسی کنید.
2. میکروسرویس های چتی
به دلیل ماهیت جدا از هم، میکروسرویس ها اغلب برای پردازش حجم کاری برنامه با یکدیگر ارتباط برقرار می کنند. در حالی که ارتباطات کلیدی است، ارتباط بیش از حد ناکارآمد بین میکروسرویس ها باعث کاهش کارایی آنها می شود.
بیایید به سناریوهایی نگاه کنیم که میتوانند به میزان قابل توجهی کارایی را کاهش دهند و در عین حال به میکروسرویسهای چتی (Chatty Microservices) کمک کنند:
ارتباطات بین سرویس های مکرر: مواردی که در آن میکروسرویس ها در سیستم تعداد زیادی درخواست را برای انجام وظایف جزئی یا به دست آوردن مقادیر کمی داده به میکروسرویس های دیگر ارسال می کنند. این می تواند ترافیک شبکه زیادی ایجاد کند و تاخیر پاسخ را افزایش دهد.
Fine-Grained API: در Microservice ها API های fine-grained را ارائه می دهند که برای تکمیل یک درخواست کاربر یا تراکنش تجاری به تماس های متعدد نیاز دارند. هر تماس ممکن است نیاز به سریال سازی، سربار شبکه و حتی مسدود کردن عملیات I/O داشته باشد که باعث افزایش مشکلات عملکرد می شود.
آبشار تماسها: یک درخواست یا تراکنش کاربر، یک سری تماسها را در میان چندین میکروسرویس آغاز میکند و هر سرویس برای تکمیل پردازش خود به سرویسهای دیگر متکی است. این می تواند یک اثر دومینو ایجاد کند که در آن شکست یا تأخیر یک سرویس به سرویس های دیگر سرایت می کند و منجر به زوال سیستم می شود.
بنابراین، برای جلوگیری از این مشکل، باید معماری خود را به گونه ای طراحی کنید که سرویس های شما جدا شده و مقیاس پذیرتر باشد. با استفاده از سرویس هایی مانند Amazon SQS، Amazon SNS و Amazon EventBridge میتوانید صفهای پیام، event busses یا موضوعات رویداد را معرفی کنید.
با انجام این کارها، می توانید از جدا شدن ارتباط بین سرویس ها، ارتباط بین سرویس های خود جلوگیری کنید.
3. Monolith توزیع شده
این آنتی پترن به برنامهای اشاره دارد که بهعنوان یک سیستم توزیعشده طراحی و پیادهسازی میشود، اما از چندین مؤلفه یا سرویسهای به هم پیوسته تشکیل شده است که بهطور محکم متصل هستند و بنابراین میکروسرویسها فاقد استقلال واقعی هستند.
برخی از ویژگی های کلیدی این ضد الگو عبارتند از:
عدم استقلال سرویس: هر جزء در سیستم توزیع شده فاقد استقلال کامل است زیرا برای عملکرد خود به شدت به اجزای دیگر متکی است. این عدم استقلال، مقیاس، استقرار، و تکامل عناصر مختلف را به طور مستقل چالش برانگیز می کند.
وابستگیهای متقابل پیچیده: اجزای سیستم توزیعشده وابستگیهای متقابل پیچیدهای دارند که یکی از آنها برای عملکرد صحیح به تعداد زیادی دیگر متکی است. این منجر به شبکه ای از روابط می شود که مدیریت و درک آن دشوار است و پیچیدگی و ریسک را افزایش می دهد.
حالت اشتراکی: اجزای یک سیستم توزیع شده، وضعیت یا داده ها را مستقیماً از طریق پایگاه داده مشترک، حافظه پنهان یا ارتباط مستقیم به اشتراک می گذارند. این حالت مشترک می تواند باعث چالش های سازگاری داده ها، شرایط مسابقه و مشکلات مقیاس شود.
به عنوان مثال، این معماری را در نظر بگیرید:
شما در حال فراخوانی سه سرویس هستید - OrderService، PaymenrService و InvoiceService. این سه سرویس برای عملکرد مستقل ساخته شدهاند، اما با زنجیر کردن فراخوانی به این صورت، سرویس های را با این یک عملیات مرتبط میکنید. با این کار مسائلی مانند مقیاس بندی خطی را معرفی می کنید و وابستگی های متقابل غیر ضروری ایجاد می کنید.
باز هم، می توانید با جدا کردن میکروسرویس های خود با سرویس هایی مانند SNS، SQS از شر چنین مشکلی خلاص شوید.
برای آشنایی با تزریق وابستگی می توانید این مقاله را بررسی کنید.
4. Over-Microservices
یکی از رایجترین تصورات غلط در طراحی معماریهای مبتنی بر میکروسرویس، تقسیم هر توابع به یک میکروسرویس است. حتی ساده ترین توابع!
این میکروسرویس ها را در جایی که نیازی به آن نیست معرفی میکند و فراتر از آنچه ضروری یا مفید است برای کاهش توابع کلی برنامه عمل میکند. بسیار مهم است که در حین پیروی از اصول طراحی Domain-Driven، میکروسرویس ها را در مورد آنچه ضروری است، تجزیه کنید.
ویژگی های کلیدی آنتی پترن "Over-Microservices" عبارتند از:
تکه تکه شدن بیش از حد: سیستم به تعداد قابل توجهی میکروسرویس تقسیم می شود که ممکن است منجر به ده ها یا حتی صدها سرویس شود. هر میکروسرویس ممکن است تنها بخش کوچکی از عملکرد را در خود جای دهد، که منجر به تجزیه بسیار fine-grained می شود.
پیوستگی کم: میکروسرویس های اجزای فاقد انسجام هستند، به این معنی که ممکن است مجموعهای از توابع منطقی متصل یا منسجم را شامل نشوند. این می تواند منجر به منطق تجاری پراکنده شود و درک و مدیریت سیستم به عنوان یک کل را دشوار کند.
اتصال بالا: علیرغم تقسیم شدن به میکروسرویس ها، سرویس های ممکن است به دلیل تعاملات و وابستگی متقابل قابل توجه بین سرویس ها به شدت با هم مرتبط شوند. تغییرات در یک میکروسرویس ممکن است نیاز به تغییرات در بسیاری از میکروسرویس های دیگر داشته باشد که باعث افزایش پیچیدگی و ریسک میشود.
یکی از راههای رفع این مشکل، استفاده از Domain Driven Design در میکروسرویسهای خود و ایجاد میکروسرویسها برای دامنههای خاص برنامهتان است.
5. نقض اصل تک مسئولیتی
این نقض اساسی مسئولیت یک تابع در طراحی شی گرا است. این زمانی اتفاق میافتد که یک تابع یا میکروسرویس مسئولیتها یا نگرانیهای متعددی را بر عهده بگیرد که در حالت ایدهآل باید از هم جدا شوند. به عنوان مثال، هنگامی که یک میکروسرویس پردازش پرداخت همراه با ثبت نام کاربر را انجام می دهد.
بیایید به سناریوهایی نگاه کنیم که این آنتی پترن را ترویج می کنند:
عدم آگاهی از اصول طراحی: توسعه دهندگان ممکن است به طور کامل از مفاهیم طراحی مانند اصل تک مسئولیتی (SRP) آگاه نباشند یا درک نکنند، یا ممکن است برنامه خود را در پایگاه کد اولویت بندی نکنند.
برنامه ریزی ناکافی: برنامه ریزی یا تجزیه و تحلیل ناکافی در مراحل اولیه طراحی نرم افزار می تواند منجر به تعیین نامشخص وظایف اجزاء شود که منجر به اختلاط نگرانی های متعدد در داخل یک جزء می شود.
تفسیر نادرست الزامات: درک نادرست یا درک نادرست الزامات می تواند منجر به معرفی توابع غیر ضروری یا نامربوط در یک جزء شود که اصل تک مسئولیتی (SRP) را نقض می کند.
برای آشنایی با پارادیم برنامه نویسی فانکشنال و شی گرایی این مقاله را بررسی کنید.
6. معماری اسپاگتی
برخی از الگوهای آنتی پترن درست مانند معماری اسپاگتی، که در آن به معماری نرم افزاری که فاقد ساختار و سازماندهی واضح است، اشاره دارد که منجر به آشفتگی پیچیده ای از اجزا، ماژول ها یا لایه های به هم پیوسته می شود.
ویژگی های کلیدی آنتی پترن Spaghetti Architecture (معماری اسپاگتی) عبارتند از:
عدم تفکیک نگرانیها: معماری نمیتواند بین دغدغهها یا وظایف مختلف تفکیک کند، که منجر به اختلاط منطق تجاری، منطق ارائه، منطق دسترسی به دادهها و سایر ویژگیها در داخل یک جزء یا ماژول میشود.
جریان کنترل پیچیده: جریان کنترل معماری پیچیده و سخت است، با وابستگی ها و تعاملات بین اجزایی که ردیابی یا درک آن دشوار است. این ممکن است منجر به رفتار غیرقابل پیش بینی و پیامدهای ناخواسته شود.
اتصال بالا: مانند آنچه که قبلاً به آن نگاه کردیم، اجزا یا ماژولها در معماری به هم متصل هستند، به این معنی که آنها به شدت به یکدیگر وابسته هستند. تغییرات در یک جزء گاهی اوقات نیاز به تغییر در چندین مؤلفه دیگر دارد که باعث ایجاد یک اثر موج دار در سراسر سیستم می شود.
7. ناسازگاری داده های توزیع شده
این زمانی است که دادهها در چندین گره یا سرویس تکثیر میشوند، و ناهماهنگیها به دلیل تأخیر یا عدم موفقیت در هماهنگسازی بهروزرسانیها در بین این نسخهها ایجاد میشود که منجر به دسترسی به اطلاعات نادرست یا قدیمی توسط بخشهای مختلف سیستم میشود و در نتیجه رفتار نادرست، خرابی دادهها، یا نقض یکپارچگی.
ویژگیهای کلیدی ضد الگوی «ناسازگاری دادههای توزیعشده» عبارتند از:
به روز رسانی ناهمزمان: به روز رسانی داده ها به طور ناهمزمان در سراسر نسخه ها یا گره های سیستم توزیع شده منتشر می شود. این می تواند باعث تاخیر بین اجرای یک تغییر و انعکاس آن در تمام کپی های داده شود.
پارتیشنهای شبکه: پارتیشنها یا خرابیهای شبکه ممکن است به دلایل پیشبینینشدهای رخ دهد که مانع از انتشار بهروزرسانیها به همه نسخهها میشود یا به دلیل بهروزرسانیهای ناقص منجر به ایجاد اختلاف بین ماکتها میشود.
عملیات متناقض: عملیات همزمان بر روی داده های یکسان از بسیاری از گره ها ممکن است باعث درگیری هایی شود که به اندازه کافی مدیریت نمی شوند و منجر به داده های متناقض یا آسیب دیده می شود.
برای رفع چنین مشکلاتی، مهم است که از الگوهای Microservice مانند Saga Pattern برای ایجاد و مدیریت تراکنش های توزیع شده در میکروسرویس های خود استفاده کنید.
8. کوپلینگ محکم
اتصال محکم ممکن است به خودی خود به عنوان یک آنتی پترن دیده نشود، اما یک ویژگی کلیدی در بسیاری از آنتی پترن ها است که قبلاً به آنها نگاه کردیم. با این حال، وابستگی شدید میکروسرویسها به یکدیگر یا خروجیهای آنها ممکن است باعث ایجاد مشکلاتی در سیستم در هنگام افزایش مقیاس شود.
این به بسیاری از الگوهای آنتی پترن کمک می کند، مانند:
معماری یکپارچه
معماری اسپاگتی
God Object
ناسازگاری داده های توزیع شده
Vendor Lock-in
9. عدم مشاهده پذیری
این موردی است که برنامه بینش کافی در مورد وضعیت داخلی، عملیات و عملکرد ارائه نمی دهد. مشاهده عملکرد برنامه یا حتی عیب یابی کارآمد یک مشکل را برای توسعه دهندگان یا مدیران چالش برانگیز می کند.
ویژگی های کلیدی آنتی پترن Lack of Observability (عدم مشاهده پذیری) عبارتند از:
ثبت نام محدود: سیستم فاقد مکانیسم های ثبت جامع برای ثبت رویدادها، خطاها و اقدامات مهمی است که در آن رخ می دهد. این امر ردیابی جریان اجرا و شناسایی مشکلات را دشوارتر می کند.
معیارهای ناکافی: این سیستم معیارهای مفید یا داده های تله متری را در مورد عملکرد، استفاده از منابع و سایر شاخص های حیاتی خود ارائه نمی دهد. بدون این اطلاعات، ارزیابی سلامت سیستم و شناسایی گلوگاههای احتمالی یا زمینههای بهبود دشوار است.
ردیابی پراکنده: سیستم فاقد قابلیت های ردیابی توزیع شده برای ردیابی جریان درخواست ها و تراکنش ها در بسیاری از سرویس ها یا مؤلفه ها است. این امر تشخیص جهش های عملکرد، نگرانی های تاخیر و خرابی ها در سیستم های توزیع شده را دشوارتر می کند.
استفاده از ابزارهای بومی ابری مانند AWS X-Ray یا پلتفرم های شخص ثالث مانند New Relic را در نظر بگیرید.
با انجام این کار، می توانید بینش های کلیدی در مورد خطاهای سیستم به دست آورید و مسائل مربوط به عملکرد و مقیاس پذیری را به شیوه ای فعال شناسایی کنید.
10. نادیده گرفتن هزینه های انسانی
این زمانی است که هدف اولیه بر روی دستیابی به اهداف فنی و تسک ها بدون در نظر گرفتن تأثیر کافی بر رفاه، روحیه و تعادل کار و زندگی تیم یا افراد درگیر در پروژه متمرکز است.
ویژگی های کلیدی آنتی پترن «نادیده گرفتن هزینه انسانی» عبارتند از:
کار بیش از حد: اعضای تیم اغلب مجبور می شوند ساعت های طولانی کار کنند، از جمله عصرها، آخر هفته ها و تعطیلات، تا تسک های پروژه را برآورده کنند یا چالش های پیش بینی نشده را حل کنند. این می تواند باعث فرسودگی، خستگی و کاهش بهره وری شود.
انتظارات غیر واقعی: جدول زمانی پروژه و موارد قابل تحویل بدون توجه به منابع، مهارت ها یا قابلیت های موجود تیم تعریف می شوند. این باعث ایجاد انتظارات غیرمنطقی می شود و فشار غیرضروری را بر اعضای تیم وارد می کند تا در مهلت های زمانی فشرده اجرا کنند.
مدیریت میکرو: مدیران یا رهبران تیم از کنترل یا مدیریت میکرو بیش از حد بر کار اعضای تیم استفاده می کنند که استقلال، خلاقیت و انگیزه را تضعیف می کند.
عدم حمایت: هنگامی که اعضای تیم با مشکلات یا باگ ها در کار مواجه می شوند، احساس می کنند که توسط مدیران یا همکاران حمایت نمی شوند. این می تواند احساسات تنهایی، تنش و جدایی را افزایش دهد.
برای آشنایی با انواع روش های جلوگیری از آنتی پترن در گیت لب این مقاله را بررسی کنید.
نتیجه
ما به برخی از رایجترین آنتی پترن هایی که میتوان در سازمانهایی که یا به تازگی سفر میکروسرویس خود را شروع کردهاند یا در حال تغییر شیوههای خود از معماریهای سنتیتر هستند، مشاهده کردهایم.
این آنتی پترن ها نه تنها باعث ایجاد گلوگاه در برنامهها میشوند، بلکه به دلیل محدودیتهای مختلفی که بهدلیل بدرفتاریهای دنبال شده معرفی میشوند، باعث عملکرد ضعیف و خرابی آنها میشوند.
بنابراین، ما باید از چنین مسائلی اجتناب کنیم تا اطمینان حاصل کنیم که معماریهای میکروسرویس ما با ایجاد مقیاسپذیری، انعطافپذیری و انعطافپذیری، طبق خواستهمان عمل میکنند.
امیدوارم این مقاله برای شما مفید بوده باشد، اگر پیشنهادی نیز داشتید در قسمت نظرات با ما به اشتراک بگذارید.