زالاندو لود بالانسینگ رو برد داخل کلاینت
خلاصهٔ کاملتر
نویسنده میگه پرمصرفترین API زالاندو یعنی PRAPI میلیونها درخواست در ثانیه رو با تأخیر تکرقمی (برحسب میلیثانیه) تو ۲۵ بازار اروپایی سرو میکنه و هر صفحهٔ محصول، نتیجهٔ جستوجو و پرداخت بهش وابستهست. این تأخیر کم با مسیریابیِ هش ثابت به دست میاد: Skipper (لود بالانسر لبهٔ کلاستر) همون شناسهٔ محصول رو همیشه به همون پاد میفرسته تا کش محلیِ پاد استفاده بشه. مشکل اینجا بود که Skipper هم مسیریابی لبه رو انجام میداد هم ترافیک داخلی رو، و این «سرنوشت مشترک» باعث میشد موقع بروز مشکل نشه فهمید تأخیر از Skipperه یا از کد خودشون.
به گفتهٔ نویسنده، مؤلفهٔ دستهایِ PRAPI یه درخواست رو به تا ۱۰۰ فراخوانی موازی به پادهای محصول باز میکنه و هر کدوم از Skipper رد میشه. Skipper به هر هاپ فقط چند صد میکروثانیه اضافه میکنه، ولی یه درخواست دستهای منتظر کندترینِ اون صد هاپ میمونه، نه هاپ معمولی. Skipper هم زیرساخت مشترکه با پیکربندی سراسریای که ارثی گرفتنش. برای همین تصمیم گرفتن مسیریابیِ ترافیک داخلیِ پرشاخه رو ببرن داخل خودِ پروسه (CSLB) و Skipper رو فقط برای ترافیک لبه نگه دارن.
مهمترین قید، برابریِ هش بود: باید دقیقاً همون حلقهٔ Skipper رو تو پروسهٔ خودشون میساختن، وگرنه یه محصول ممکن بود به پاد دیگهای بره، کشها تکهتکه بشن و بار DynamoDB دو برابر بشه. پس همون الگوریتم Skipper رو پیاده کردن — xxHash64 روی حلقهای با ۱۰۰ نود مجازی به ازای هر endpoint — و با یه دسته تست واحد مطمئن شدن که حلقهشون همون کلیدها رو روی همون پادها میذاره. تو کاناری هم دیدن نرخ اصابت کش تو هر دو مسیر یکسان مونده.
برای کشف پادها، اول سراغ پولینگِ چندثانیهای EndpointSlice رفتن ولی از پولینگ زخمخورده بودن؛ قبلاً پولینگِ پرتکرارِ صدها پاد کنترلپلینِ Kubernetes رو از پا درآورده بود. برای همین به یه informer مبتنی بر watch سوییچ کردن که موقع استارت لیست فعلی رو میگیره و بعد تغییرات رو زنده استریم میکنه، با یه debounce دوثانیهای که رگبار تغییرات موقع اسکیلآپ رو تو یه بهروزرسانیِ حلقه جمع میکنه. اگه API قطع بشه، آخرین مجموعهٔ سالم سر جاش میمونه.
ولی نویسنده میگه اول باید پایپلاین دیپلوی رو درست میکردن، چون هیچکدوم از این آزمایشها بدون دیپلویِ سریع ممکن نبود. پایپلاین بعد از سالها احتیاط چنان کند شده بود که میانهٔ اجراش ۴ ساعت و ۴۹ دقیقه و بدترین رکورد حدود ۵ روز بود. با سه تا PR — کشِ بیلد، جمع کردن بیش از ۴۰ مرحلهٔ دستیِ ترافیک تو یه مرحله، و حذف گیتهای تأیید و جایگزینیشون با رولاوت مرحلهایِ بازارها — میانهٔ دیپلوی از ۲۸۹ به ۱۲۸ دقیقه رسید و سرعت آزمایش کردن ترکید.
رولاوت رو با سه کلید (روشن/خاموش، درصد ترافیک، و فالبک شفاف به Skipper) و بهصورت پلهای ۱، ۱۰، ۵۰ و ۱۰۰ درصد انجام دادن. اثرش فوری بود: تأخیر افتاد و اسپایکهایی که به «شبکه» نسبت داده بودن ناپدید شدن و بیش از یک میلیون درخواست در ثانیه از Skipper برداشته شد. عارضهٔ جانبیِ پیشبینینشده این بود که ناوگان Skipper از بیش از ۵۰ پاد به حداقل ۸ پاد کوچیک شد و هزینهٔ روزانه از حدود ۴۵۰ به ۱۱۰ دلار رسید — پروژهٔ تأخیر تبدیل شد به پروژهٔ هزینه.
بعدش چند بهینهسازی اضافه کردن: fade-in چند-حلقهای که پادهای تازه رو دقیقاً با همون محصولهایی که قراره سرو کنن گرم میکنه و کش هدر نمیده؛ و بار کراندار با سیگنالِ بهترِ اشغالبودگی که باعث شد توزیع بار پادها یکنواختتر بشه، آستانهٔ اتواسکیلر از ۵۰٪ به ۶۵٪ بره بالا و بیش از ۲۵٪ پاد کمتر لازم بشه (بیش از ۱۰۰۰ دلار صرفهجویی روزانه). مسیریابیِ آگاه به Availability Zone هم هزینهٔ انتقال بینزون رو کم کرد ولی در نهایت فعلاً متوقف شد. نویسنده میگه سود اصلیِ مالکیتِ الگوریتم، دیدِ کاملی بود که به دست آوردن — مثلاً حالا میبینن که حتی صدک ۹۹اُم درخواستها فقط چهار پاد جابهجا میشن.
نکات کلیدی:
- ترافیک داخلیِ پرشاخه از لود بالانسر مشترکِ لبه جدا و به داخل خودِ پروسه منتقل شد
- کلید کار، بازسازیِ دقیقِ همون حلقهٔ هشِ Skipper (xxHash64) بود تا کشها تکهتکه نشن
- کشف پاد با informerِ مبتنی بر watch بهجای پولینگِ خطرناک انجام شد
- درست کردنِ پایپلاینِ کند، پیششرطِ سرعت آزمایش بود
- نتیجه: حذف اسپایک تأخیر و کاهش بزرگ هزینه (ناوگان Skipper و پادهای خودشون هر دو کوچیک شدن)




