مقیاس بندی محیط ها با OpenTelemetry و Service Mesh

در ابتدا توسط انیرود راماناتان در TheNewStack ارسال شد.
مش های Otel Baggage و سرویس مانند Istio و Linkerd می توانند با هم برای پیاده سازی محیط های توسعه دهنده، پیش نمایش و آزمایش بسیار مقیاس پذیر استفاده شوند.
با میکروسرویسها، هر تیم در یک زمان با بخشهای کوچکتری از برنامه سروکار دارد که توسعه و پیچیدگی عملیاتی را مدولار میکند. با این حال، از طرف دیگر، نیاز به اعتبارسنجی و آزمایش اینکه همه قطعات به خوبی با هم کار می کنند ایجاد کرده است. این نیاز در چند سال گذشته باعث پیدایش دستههای جدیدی از راهحلها شده است – محیطهای زودگذر، محیطهای درخواستی، محیطهای پیشنمایش، و غیره. چرخه عمر توسعه تا حد امکان
تمام این کلاسهای محیطهای میکروسرویس بهطور سنتی بهعنوان نسخههای کاملاً مجزا از کل مجموعه میکروسرویسها تنظیم شدهاند. این پشتهها در واقع ممکن است زیرساختهای زیر را به اشتراک بگذارند – مانند اجرای در یک خوشه Kubernetes در فضاهای نام مختلف، یا اجرا بر روی خوشههای تک گره، یا حتی (در مقیاس کوچکتر)، به عنوان کانتینرهای Docker در برخی از گرههای محلی یا راه دور. با این حال، همین مفهوم اجرای پشتههای هر میکروسرویس و تمام وابستگیهای آن به طور جداگانه از یکدیگر دارای اشکالاتی است:
- مقیاس بندی هزینه: آنها از نظر هزینه با تعداد ریز سرویسها مقیاس میشوند و اغلب در نهایت به راهحلهایی برای کنترل هزینهها نیاز دارند، هم از نظر تلاش برای نگهداری و هم هزینههای زیرساختی. پیامدهای هزینه ممکن است باعث شود توسعه دهندگان در برخی از محیط های مشترک صف بکشند تا آزمایش خود را انجام دهند.
- وابستگی های کهنه و واگرایی از تولید: هر محیط حاوی کپی مخصوص به خود از هر وابستگی است که به سختی می توان آن را هماهنگ کرد، به خصوص که تغییرات در هر میکروسرویس ایجاد می شود و به طور مداوم فشار داده می شود. علاوه بر این، شکل دیگری از واگرایی که رخ میدهد این است که وابستگیها و ادغامهای شخص ثالث با سرویسهای ابری ممکن است در این محیطها رفتار متفاوتی نسبت به مرحلهبندی یا تولید داشته باشند، که احتمال بروز مشکل در کلاس «در تست کار میکرد اما نه در تولید» را افزایش میدهد.
- افزایش سربار عملیاتی: هزینه های عملیاتی افزایش می یابد حتی اگر شخصی فقط یک میکروسرویس در پشته داشته باشد.
- تجربه توسعه دهنده غیر بهینه: پشتیبانی از هر یک از این محیط ها برای یک تیم پلتفرم دشوار است که اغلب منجر به تجربه ضعیف توسعه دهنده و استفاده کم می شود. زمان لازم برای راه اندازی محیط نیز بر بهره وری توسعه دهندگان تأثیر می گذارد. هرچه میکروسرویس های بیشتری داشته باشید، این محیط ها کندتر ظاهر می شوند. راهحلهای زیادی برای کمک به مقابله با این موارد در عمل مورد بررسی قرار گرفتهاند، اما من میخواهم شیوه متفاوتی از تفکر در مورد محیطها را معرفی کنم که مزایای متعددی نسبت به رویکردهای قبلی دارد.
بازاندیشی در محیط های میکروسرویس
هنگامی که ما در حال توسعه میکروسرویس ها هستیم، هر توسعه دهنده یا تیم توسعه در حال کار بر روی تغییر بخش کوچکی از کل کلی است. صرف نظر از اینکه هر چند وقت یکبار زمین را در مرحله تولید آزاد می کند، برای هر میکروسرویس معمول است که فرآیند CI/CD مخصوص به خود را داشته باشد که به روز رسانی ها را به برخی از محیط های بالاتر مانند مرحله بندی ارسال می کند. با توجه به این تنظیمات و تمایل به آزمایش در اوایل چرخه عمر توسعه، میتوانیم هر محیط توسعه/پیشنمایش/تست میکروسرویس را ترکیبی از آنچه تغییر کرده و «آخرین» نسخههای هر چیز دیگری تصور کنیم.
همانطور که در بالا نشان داده شده است، آخرین نسخههای همه میکروسرویسهای موجود در پشته را به عنوان محیط پایه تعریف میکنیم. محیط پایه به عنوان نسخه پیشفرض هر وابستگی میکروسرویس برای هر محیطی که راهاندازی میشود و به طور مداوم از هر فرآیند CI/CD بهروزرسانی میشود، عمل میکند. این اغلب یک خوشه Kubernetes منفرد است، مانند صحنهسازی (یا حتی تولید). برای هر محیط برنامهنویس/تست/پیشنمایش جدید، ما فقط «آنچه تغییر کرد» را به کار میگیریم (به عنوان جعبه ایمنی در بالا به آن اشاره میشود)، که اغلب تعداد کمی از میکروسرویسها در مقایسه با تعداد کلی است، و هر گونه وابستگی بدون تغییر را با محیط پایه به اشتراک میگذاریم. .
این روش شباهت هایی با قناری در تولید دارد، اما در این مورد، تأکید بیشتری بر جداسازی میکروسرویس ها به اندازه کافی برای ایجاد جعبه های ماسه ای است که می توانند در طول فرآیند توسعه استفاده شوند. در بخش بعدی به چگونگی ساخت چنین سیستمی از محیط های sandbox در عمل خواهیم پرداخت.
درخواست اجاره
در بخش قبل، ساختار منطقی یک جعبه شنی را بررسی کردیم که چیزهای تحت آزمایش را با مجموعهای از وابستگیهای مشترک از محیط پایه ترکیب میکند. در عمل، چنین سیستمی بر دو ایده کلیدی متکی است: درخواست اجاره و مسیریابی.
با در نظر گرفتن شکل بالا، فرض می کنیم که یک درخواست می تواند با یک شناسه خاص برچسب گذاری شود، چیزی که نشان می دهد کدام مستاجر درخواست را ارسال می کند. تا زمانی که این اطلاعات اجاره در امتداد زنجیره از سرویسی به سرویس دیگر به عنوان تماس از طریق سیستم منتقل میشود، ما میتوانیم با استفاده از آن اجاره خاص تصمیم مسیریابی بگیریم تا تصمیم بگیریم که یک درخواست خاص باید توسط یک سرویس svcA “sandboxed” برآورده شود. از آخرین نسخه آن از نسخه پایه svcA. بنابراین، برای ایجاد این نوع جریان به دو جزء نیاز داریم:
- راهی برای برچسب گذاری درخواست ها با اجاره با استفاده از یک شناسه خاص در حالی که از طریق شبکه ای از ریزسرویس ها جریان دارند.
- راهی برای تصمیم گیری برای مسیریابی محلی بر اساس وجود شناسه مشخص شده در بالا.
خوشبختانه، به لطف OpenTelemetry، این مفهوم ارسال یک قطعه درخواست در میکروسرویس های مدرن ساده شده است. با ابزار ابزار OpenTelemetry در میکروسرویس ها، این قابلیت در حال حاضر در دسترس است. یک هدر مخصوص چمدان به طور خودکار به میکروسرویس بعدی ارسال می شود. بنابراین، تا زمانی که OpenTelemetry برای ابزار دقیق ریزسرویسهای ما استفاده میشود، ما میتوانیم یک درخواست را به صورت خودکار بدون هیچ تلاش اضافی برچسب گذاری کنیم.
در حال حاضر، زمانی که صحبت از تصمیم گیری در مورد مسیریابی به میان می آید، طبیعی ترین راه حل، مش های سرویس مانند ایستیو، لینکرد و غیره است. این مش ها ایجاد قوانینی را امکان پذیر می کنند تا دقیقاً این نوع تصمیمات مسیریابی محلی را اتخاذ کنند. بنابراین، ما با چیزی شبیه به این نتیجه می گیریم:
یکی از دستاوردهای بزرگ استفاده از چنین سیستمی این است که آزمایش چندین میکروسرویس با هم بسیار ساده می شود. اغلب، ویژگیها چندین میکروسرویس را در بر میگیرند، که آزمایش آنها را با هم سخت میکند تا زمانی که همه آنها در یک محیط مشترک مشترک قرار بگیرند. در اینجا، تنها با کنترل شناسه ای که درخواست را با آن برچسب گذاری می کنیم، می توان یک مستاجر جدید ایجاد کرد که ترکیبی از دو مستاجر دیگر است، که به معرفی روش های جدید همکاری در طول فرآیند ساخت میکروسرویس کمک می کند.
جداسازی داده ها
در بالا از یک میکروسرویس ساده بدون حالت استفاده کردیم، جایی که از پروتکل L7 مانند HTTP یا gRPC استفاده میکردیم که برچسبگذاری و مسیریابی درخواست را آسان میکرد. در عمل، پایگاههای داده، صفهای پیام، وابستگیهای ابری، وبقلابها و غیره وجود دارند که جداسازی با استفاده از اجاره درخواست برای آنها کافی نیست.
برای مثال، آزمایش تغییرات طرحواره در پایگاه دادهای که یک میکروسرویس از آن استفاده میکند، ممکن است نیاز به راهاندازی یک نمونه پایگاه داده زودگذر یا پایگاههای داده منطقی برای درک جداسازی لازم داشته باشد. در این موارد که درخواست اجاره کافی نیست، می توانید از سطح ایزوله بالاتر استفاده کنید. به طور معمول، دو سطح بالاتر از انزوا وجود دارد که به طور معمول استفاده می شود: انزوا منطقی و جداسازی زیرساخت.
جداسازی منطقی زمانی است که از یک زیرساخت زیربنایی (مثلاً خوشه پایگاه داده PostgreSQL) استفاده میکنید، اما برخی از واحدهای اجاره را در زیر آن تنظیم میکنید، مانند یک پایگاه داده جدید یا یک طرح برای آن مستاجر خاص. جداسازی زیرساخت همه چیز را به خود اختصاص می دهد و زیرساخت اختصاصی را برای آن مستاجر خاص ارائه می دهد، مانند راه اندازی یک خوشه پایگاه داده جداگانه PostgreSQL. در هر صورت، میتوانید از مکانیسمهای پیکربندی مانند متغیرهای محیطی/نقشههای پیکربندی در Kubernetes استفاده کنید تا منبع منطقی یا فیزیکی زودگذر را با بقیه جعبههای ماسهبازی متصل کنید.
سطح ایزوله برای انتخاب بستگی به مورد استفاده دارد، اما یک مبادله واضح وجود دارد: سطوح بالاتر کار عملیاتی مربوط به راه اندازی و مدیریت زیرساخت را افزایش می دهد، در حالی که تداخل کمتری از سوی دیگر بازیگران در بقیه سیستم ارائه می دهد. در عمل، در بیشتر موارد، جداسازی منطقی کافی است، به جز در مواردی که خود ذخیره داده فاقد چنین شرایطی باشد، یا در سناریوهای خاص عملکرد/آزمایش بار.
صف های پیام
برای صفهای پیام، سادهترین کار این است که اطلاعات اجارهای را در خود پیامها بسازیم (همانطور که OpenTelemetry فعال کرده است) و در میکروسرویس مصرفکننده تصمیم بگیرید که آیا یک پیام خاص به خودش مربوط است یا خیر. ایده کلیدی در اینجا این است که مصرفکنندگان را قادر به مصرف انتخابی پیامها کنیم تا در نهایت پیامهای در نظر گرفته شده برای مستاجر دیگری را پردازش نکنند.
در سیستمی مانند آپاچی کافکا، این کار با راهاندازی یک گروه مصرفکننده مجزا به ازای هر مستأجر، و سپس ایجاد تغییرات لایه کاربردی در کتابخانههای مصرفکننده برای پیادهسازی این نوع منطق برای مصرف انتخابی پیامها انجام میشود.
مشاغل Async و وابستگی های شخص ثالث
در برخی موارد، یک میکروسرویس ممکن است در جریانهای درخواست مشارکت نداشته باشد، اما به شیوهای کاملاً ناهمزمان عمل میکند، مانند یک کار cron که برخی عملیات را به صورت دورهای انجام میدهد، یا خود نقطه منشأ درخواستها باشد. در این مورد، هنوز هم میتوانید یک «sandbox» برای نسخه جدیدی از آن ایجاد کنید، اما اجارهنشینی برای آن نمونه Sandbox خاص خود میکروسرویس مشخص میشود. اساساً، “مستاجر” ما در این زمینه به جای یک درخواست، به یک ریز سرویس کامل تبدیل می شود.
این روش مشابه در مواردی نیز اعمال میشود که وابستگی شخص ثالثی وجود دارد که به هدرهای اجارهای احترام نمیگذارد، یا اگر از پروتکل سفارشی استفاده میکنید که در آن افزودن ابرداده سرصفحه ممکن نیست. ایده اصلی این است که هر جا که امکان استفاده از اجاره درخواست وجود ندارد، به استفاده از پیکربندی برای جداسازی بازگردید.
نتیجه گیری
رویکرد ایجاد محیطها با استفاده از اجاره درخواست و جداسازی قابل تنظیم، چندین اشکال راهاندازی سنتی محیطهای پیشنمایش، آزمایش و توسعهدهنده را در Kubernetes برطرف میکند. به طور خاص، از آنجایی که ما به تعداد کمی از میکروسرویس ها برای هر محیطی نیاز داریم، این امر حتی در مقیاس بسیار مقرون به صرفه است، همانطور که توسط شرکت هایی که صدها سیستم از این قبیل را به صورت داخلی اجرا می کنند مانند Uber's SLATE، Lyft's Staging Overrides و Doordash نشان می دهد.
همچنین تست وفاداری بالا را در برابر جدیدترین وابستگیها تضمین میکند و به سرعت تنظیم میشود و از نظر تجربه توسعهدهنده و بهرهوری برندهها را به ارمغان میآورد. با این رویکرد راههای جدیدی برای همکاری یکپارچهتر بین توسعهدهندگان و تیمهای توسعهای که روی میکروسرویسهای مختلف کار میکنند، وجود دارد.
ما در Signadot در حال ساخت یک راه حل بومی Kubernetes هستیم که ایجاد این نوع محیط ها و استفاده از آنها برای پیش نمایش، توسعه دهنده و محیط های آزمایشی در Kubernetes را آسان می کند. ما مشتاقیم که به این امکان کمک کنیم و پیچیدگی موجود در عملیاتی کردن موارد فوق را کاهش دهیم. میتوانید درباره رویکرد Signadot در اسناد ما بیشتر بخوانید یا بیایید در کانال Slack جامعه ما با ما صحبت کنید!