آن حادثه واقعاً چه چیزی مصرف کرد
یک ازدحام ایجنت طولانیمدت، وب باز را بهعنوان یک مخزن اسناد تجربه نمیکند. آن را بهعنوان یک جدول جستوجو با تعداد بسیار زیادی سطر تجربه میکند که بیشترشان پشت endpointهایی قرار دارند که مالکشان شخص دیگری است. وقتی از ازدحام خواسته میشود حقایق مبهم را طی هفتهها یا ماهها حل کند، منبع غالب مصرفیاش inference نیست. حجم درخواست علیه زیرساخت شخص ثالث است.
پیامد مهندسی این است که یک بودجه تجمیعی واحد نمیتواند محدودیتی را بیان کند که واقعاً اهمیت دارد. «این میزبان N درخواست در دقیقه را تحمل میکند و نه بیشتر» یک گزاره بهازای هر هدف است. یک سقف توکن سراسری یا سقف هزینه سراسری، گزارهای درباره مصرف خود ازدحام است و از نظر ساختاری ناتوان از بازنمایی محدودیتی است که در rate limiter شخص دیگری زندگی میکند.
چرا بودجههای سراسری بهعنوان کنترل شکست میخورند
سقفهای توکن و سقفهای هزینه، شاخصهای تأخیری هستند. آنها از کاری محاسبه میشوند که ازدحام پیشتر انجام داده است. تا زمانی که یک بودجه سراسری فعال شود، درخواستهای خارجی پیشتر صادر شدهاند، هدف پیشتر آنها را جذب کرده است و هر آسیب ناشی از آن — افت کیفیت سرویس برای سایر کلاینتها، مسدودسازی دفاعی، گزارش سوءاستفاده — پیشتر رخ داده است. بودجه پس از رویدادی فعال میشود که قرار بود از آن جلوگیری کند.
این یک مسئله تنظیم نیست. یک خطای مقولهای است. یک بودجه سراسری به این پرسش پاسخ میدهد: «چقدر مجازیم مصرف کنیم؟» یک محدودیت نرخ بهازای هر هدف به این پرسش پاسخ میدهد: «همین حالا چقدر مجازیم اینجا بفرستیم؟» تنها پرسش دوم پاسخی کراندار دارد که شخص ثالث میتواند از تجاوز به آن آسیب ببیند.
این شکست با fan-out تشدید میشود. فرض کنید یک ازدحام ایجنتهای زیادی را اجرا میکند که هرکدام با نرخی درخواست میفرستند که هر اپراتور معقولی آن را مؤدبانه میداند. نرخ هر ایجنت متعادل است. نرخ تجمیعی علیه یک هدف واحد، نرخ هر ایجنت ضربدر تعداد ایجنتهایی است که در آن لحظه روی آن هدف کار میکنند، و زمانبند هیچ دلیل ذاتیای ندارد که این حاصلضرب را کوچک نگه دارد. ایجنتها معمولاً برای پیشرفت بهینه میشوند، نه برای حفظ یک منبع خارجی مشترک که نمیتوانند ببینند. بدون دید مشترک از هدف، هر ایجنت درست رفتار میکند و سیستم بهعنوان یک کل بد رفتار میکند.

تشدیدکننده دوم، رفتار retry است. وقتی هدفی شروع به رد درخواستها میکند، ایجنتهایی که رد را یک خطای گذرا میپندارند، دوباره تلاش میکنند، اغلب با backoffی که محلی هر ایجنت است. backoff محلی در میان ایجنتهای زیاد، فشار تجمیعی را کاهش نمیدهد؛ آن را به باری هموارتر و پایدارتر بازشکل میدهد که ریختن آن برای هدف دشوارتر است.
طراحی یک بودجه نرخ بهازای هر هدف
کنترلی که کار میکند، یک پوشش نرخ متصل به هر شناسه منبع خارجی است — scheme، host و در صورت لزوم یک مسیر یا کلاس کوئری — نه متصل به ازدحام بهعنوان یک کل.
در لایه خروجی اعمال کنید، نه در promptها. دستورالعملهای داخل system prompt جنبه توصیهای دارند. ایجنتی که در میانه مسیر است، تحت فشار ضربالاجل است، یا صرفاً با دستورالعمل همراستا نیست، درخواست را بههرحال صادر میکند. اعمال محدودیت به لایه خروجی تعلق دارد: یک نقطه گلوگاه واحد که هر درخواست خروجی از آن عبور میکند و برای هر هدف یک token bucket نگه میدارد و درخواستهایی را که از پوشش فراتر میروند رد یا صفبندی میکند. promptها میتوانند قصد را توصیف کنند؛ لایه خروجی تصمیم میگیرد.
یک سازوکار مشخص: یک token bucket را با کلید شناسه نرمالشده هدف نگه دارید، آن را با نرخ تحملشده هدف پر کنید و مجوز burst را به اندازه تحمل مشاهدهشده هدف تعیین کنید، نه به اندازه اشتهای ازدحام. هر فراخوانی HTTP خروجی پیش از ترک فرایند یک توکن میگیرد. اگر توکنی موجود نباشد، فراخوانی نه بیصدا شکست میخورد و نه میچرخد؛ بلکه یک تعویق ساختاریافته به فراخوان بازمیگرداند.
به زمانبند دید نسبت به بودجه باقیمانده بدهید. یک تعویق تنها زمانی مفید است که ارکستریتور بتواند بر اساس آن عمل کند. زمانبند باید بتواند توکنهای باقیمانده هر هدف را کوئری کند و از آن برای بازچینش کار استفاده کند: گامهای مسیری که به هدفهای بدون محدودیت میخورند را همین حالا اجرا کند و گامهای مربوط به هدف تمامشده را به بعد موکول کند. این کار rate limiting را از یک توقف به یک ورودی زمانبندی تبدیل میکند. بدون این دید، یک پوشش تمامشده دقیقاً مانند یک هدف خراب به نظر میرسد و ایجنتها بودجه باقیماندهشان را صرف کاوش آن میکنند.
با backoff بهعنوان یک وضعیت زمانبندی درجهیک رفتار کنید. بیشتر سیستمها backoff را بهعنوان یک مسیر خطا مدل میکنند: چیزی اشتباه شد، صبر کن، دوباره تلاش کن. این چارچوب برای یک منبع خارجی مشترک نادرست است. هدفی که در backoff است شکست نخورده؛ هدفی است که پوشش آن در حال حاضر خالی است و پاسخ درست این است که همه کارهای مربوط به آن را تا پر شدن مجدد پوشش، کماولویت کنیم. مدلکردن backoff بهعنوان یک وضعیت در زمانبند — در کنار queued، running و complete — به ارکستریتور اجازه میدهد بهجای انباشتن retry علیه آن، از کنارش مسیریابی کند.
معاوضه صادقانه، throughput است. یک پوشش بهازای هر هدف وقتی هدفی لحظهای تمامشده است اما ازدحام کاری دارد که میتوانست انجام شود، ظرفیت را بیاستفاده میگذارد. یک بودجه سراسری آن ظرفیت را خرج میکرد؛ پوشش عمداً این کار را نمیکند. تیمهایی که این طراحی را برمیگزینند، انتخاب میکنند که ایجنتهای خودشان را کماستفاده کنند تا در محدوده تحمل شخص دیگری بمانند، و این انتخاب هزینه واقعیای در زمان واقعی برای وظایف افقبلند دارد. هیچ پیکربندیای این معاوضه را حذف نمیکند؛ فقط پی

معاوضه دوم، سرباز coordination است. bucketهای بهازای هر هدف باید میان همه ایجنتها و فرایندها مشترک باشند، که یعنی یک مخزن مشترک با مشخصههای سازگاری و تأخیر خودش. یک bucket محلی بهازای هر ایجنت ارزانتر و نادرست است؛ مسئله fan-out را در سطح خود limiter بازمیگرداند.
ابزارسازی که آن را قابل حسابرسی میکند
یک بودجه نرخ تنها زمانی یک کنترل است که مصرفش پس از واقعه قابل مشاهده باشد.
تعداد درخواستها را بهازای هر هدف در هر پنجره ثبت کنید و آنها را به گام مسیری که هر درخواست را تولید کرده متصل کنید. این اتصال همان چیزی است که لاگ را مفید میکند. شمارش درخواستها علیه یک میزبان به شما میگوید فشار رخ داده است؛ گام مسیری به شما میگوید کدام ایجنت، کدام هدف و کدام گام استدلال آن را تولید کرده، که همان چیزی است که برای تغییر رفتار لازم دارید، نه فقط مشاهده آن.
هشدار را روی تمامشدن پوشش تنظیم کنید، نه روی کل هزینه. هشدار کل هزینه زمانی فعال میشود که ازدحام گران است، که ممکن است کاملاً مشروع باشد. هشدار تمامشدن زمانی فعال میشود که یک هدف مشخص در نرخ تحملشدهاش یا نزدیک به آن است، که همان شرطی است که مقدم بر آسیب خارجی است. هشدار دوم قابل اقدام است؛ اولی یک سیگنال صورتحساب است.
تعویقها را بهعنوان یک متریک درجهیک رصد کنید. نرخ فزاینده تعویق علیه یک هدف، نشانگر زودهنگامی است از اینکه تقاضای ازدحام برای آن هدف از آنچه هدف تحمل میکند فراتر رفته — پیش از آنکه خود هدف با ردها پاسخ دهد و بسیار پیشتر از آنکه هر بودجه تجمیعی فعال شود. تعویقها همچنین کیفیت زمانبندی را آشکار میکنند: ازدحامی که بهشدت علیه یک هدف تعویق میکند در حالی که هدفهای دیگر بیکار ماندهاند، خوب زمانبندی نمیکند و این متریک آن را قابل مشاهده میسازد.
در نهایت، خود پوشش را در کنار ترافیک ثبت کنید. وقتی تحمل یک هدف بازنگری میشود — چون با اپراتور تماس گرفته شده یا چون رفتار مشاهدهشده تغییر کرده — شمارشهای تاریخی درخواست تنها در برابر پوششی که در آن زمان در نیرو بوده قابل تفسیرند. بدون آن، یک بازبینی پس از حادثه نمیتواند ازدحامی را که بودجهاش را رعایت کرده از ازدحامی که تحت بودجهای هرگز درست کار میکرده، تشخیص دهد.
نکته گستردهتر این است که ازدحامهای ایجنت که در افقهای بلند فعالیت میکنند، در درجه اول مصرفکننده compute خودشان نیستند. آنها مصرفکننده سرویسهای دیگراناند و منبع کمیاب، نرخی است که آن سرویسها درخواستها را میپذیرند. ارکستراسیونی که بر اساس سقفهای سراسری زمانبندی میکند، کمیت اشتباه را بهینه میکند. زمانبندی بر اساس بودجههای نرخ بهازای هر هدف، که در لایه خروجی اعمال و برای زمانبند قابل مشاهده باشند، همان کنترلی است که با محدودیت واقعی مطابقت دارد.
