عدم تطابق، صریح بیان میشود
ترافیک وب انسانی شکل مشخصی دارد. انفجاری، وابسته به نشست و خودمحدودکننده است: فردی صفحهای را باز میکند، میخواند، کلیک میکند و در نهایت متوقف میشود. مرورگرها بهصورت موازی به هزار URL پخش نمیشوند و انسانی که با 429 مواجه میشود معمولاً تسلیم میشود یا صبر میکند. برنامهریزی ظرفیت در بیست سال گذشته بر همین فرض بنا شده است.
ترافیک ایجنت شکل متفاوتی دارد. موازی، پایدار و ارزان برای تقویت است. یک ارکستراتور واحد میتواند زیرایجنتهایی ایجاد کند که هرکدام همان الگوی درخواست را از طریق آدرسهای مبدأ متعدد تکرار میکنند، بدون خستگی روی خطا دوباره تلاش میکنند و نشستی را ساعاتی باز نگه میدارند تا برنامه بازیابی خود را پیش ببرند. هزینه ارسال یک درخواست دیگر نزدیک به صفر است، بنابراین تعادل طبیعی «مؤدبانه بخوان و برو» نیست — بلکه «دوباره تلاش کن تا چیزی تسلیم شود» است.
این عدم تطابق اکنون در هر دو طرف قابل مشاهده است. سایتهایی که مطالب مرجع منتشر میکنند گزارش میدهند که توسط کلاینتهای خودکار که هیچ شباهتی به خواننده ندارند، سیلآسا مورد هجوم قرار میگیرند، در حالی که سایتهای دیگر دسترسی ایجنت را پشت شرایط صریح و کنترلهای فنی قرار دادهاند. مجموعه داده هر دو نیمه حالت شکست را نشان میدهد: ایجنتهایی که یک سایت مرجع را تحت فشار قرار میدهند، و اپراتورهایی که با محدود کردن یکجای دسترسی ماشینی پاسخ میدهند. هیچکدام از این نتایج یک طراحی پایدار نیست.
علت ریشهای حجم نیست. این است که سایت هیچ ایدهای ندارد کلاینت چه کاری انجام میدهد، و کلاینت هیچ تعهدی به گفتن آن ندارد.
چرا محدودیت نرخ مبتنی بر IP کلاینت اشتباهی را فرض میگیرد
بیشتر محدودیتهای نرخ برای کلاینتی نوشته شدهاند که مانند مرورگر رفتار میکند. بر آدرس IP یا کلید API کلید میزند، یک سطل توکن اعمال میکند و 429 را با Retry-After برمیگرداند. برای مرورگر این یک حلقه بسته است: انسان خطا را میبیند، تب بارگذاری را متوقف میکند، سطل دوباره پر میشود.
ایجنتها هر بخشی از این حلقه را میشکنند.
- تلاشهای مجدد قصد backoff را نادیده میگیرند. کتابخانه کلاینتی که 429 را بهعنوان خطای گذرا در نظر میگیرد، دوباره تلاش میکند، اغلب با backoff نمایی همراه با jitter که هنوز در میان زیرایجنتها ضرب میشود.
- پخششدگی، کلیدگذاری بر IP را شکست میدهد. باری که در آدرسها، مناطق یا استخرهای خروجی پخش میشود، بهجای یک کلاینت تهاجمی، مانند بسیاری از کلاینتهای خوشرفتار به نظر میرسد.
- آینهسازی، محدودیتهای هر endpoint را شکست میدهد. اگر محدودیت بر مسیر باشد، ایجنت کار را در مسیرها پخش میکند. اگر بر کلید باشد، ایجنت در کلیدها پخش میکند. محدودیت تنها بهاندازه هویتی که به آن گره خورده خوب است.
بدتر از آن، محدودیتهای مبتنی بر IP طرف اشتباه را مجازات میکنند. یک NAT اشتراکی، یک پروکسی سازمانی یا یک CI runner میتواند بهخاطر بدرفتاری یک بار پشت آن محدود شود. محدودیت واقعی است، اما پاسخگویی وجود ندارد.
یک قرارداد پذیرش شامل چه چیزی است
جایگزین این است که درخواستهای ایجنت را بهعنوان HTTP ناشناس در نظر نگیریم و آنها را بهعنوان یک بار مذاکرهشده ببینیم. قرارداد پذیرش یک توافق کوچک و صریح است که پیش از رسیدن اولین درخواست واقعی به سرویس مبدأ برقرار میشود. سه بخش دارد.

هدف و دامنه اعلامشده، گرهخورده به هویت بار کاری
قرارداد نام میبرد که کلاینت چه کاری انجام میدهد و کدام منابع را پوشش میدهد. بهطور حیاتی، به یک هویت بار کاری گره خورده است — یک اعتبارنامه قابلراستیآزمایی برای کار در حال اجرا — نه به یک کلید API ثابت که میتواند کپی، به اشتراک گذاشته یا افشا شود. یک کلید API یک مستأجر را شناسایی میکند؛ یک هویت بار کاری یک وظیفه را شناسایی میکند. این تمایز مهم است زیرا بودجهها، اهداف و ابطالها ویژگیهای وظایف هستند، نه سازمانها.
دامنه باید بهصورت مجموعهای از عملیات مجاز و پیشوندهای منابع بیان شود، نه یک توصیف متنآزاد. «بازیابی مستندات زیر /docs/» قابلاجراست. «دستیار پژوهشی» نیست.
بودجه همزمانی و درخواست به زبان سایت
بودجه باید به واحدهایی باشد که سایت کنترل میکند، نه واحدهایی که کلاینت ترجیح میدهد. این یعنی:
- حداکثر تعداد درخواستهای در پرواز، نه فقط درخواست در ثانیه؛
- یک سهم کل درخواست برای طول عمر قرارداد، تا یک کار طولانیمدت نتواند بیسروصدا ظرفیت نامحدود مصرف کند؛
- یک سهم جداگانه و کوچکتر برای عملیات تغییردهنده وضعیت.
بیان بودجه به زبان سایت همان چیزی است که آن را قابل دفاع میکند. یک کلاینت نمیتواند استدلال کند که تصور خودش از «یک پرسوجوی منطقی» باید به پنجاه فراخوانی بالادستی نگاشت شود.
انقضا و ابطالی که در میانه اجرا کار میکنند
قراردادها بهطور پیشفرض منقضی میشوند. مهمتر از آن، میتوان آنها را در حین اجرای یک کار باطل کرد، و ابطال در لبه روی درخواست بعدی اعمال میشود نه در پنجره صدور بعدی. این همان بخشی است که بیشتر پیادهسازیها اشتباه میکنند: آنها پذیرش را بهعنوان یک دروازه یکباره در زمان صدور توکن در نظر میگیرند، که یعنی یک کلاینت بدرفتار دسترسی خود را تا انقضای توکن حفظ میکند.
یک دسته ابطال یک شناسه کوتاه است که سایت میتواند آن را بیاعتبار کند، بههمراه یک control plane که آن بیاعتباری را به هر گره لبه منتشر میکند. انتظار میرود کلاینت ابطال را بهعنوان یک نتیجه عادی و غیرقابلتلاشمجدد بپذیرد — نه

قرارداد را در لبه خاتمه دهید
تصمیمات پذیرش به لایه gateway یا CDN، در جلوی سرویسهای مبدأ تعلق دارند. مبدأها هرگز نباید ترافیک مذاکرهنشده را ببینند؛ تا زمانی که یک درخواست به سرور اپلیکیشن میرسد، قرارداد قبلاً بررسی شده، بودجه کاهش یافته و تصمیم ثبت شده است. این اجرا را در سراسر سرویسها یکنواخت نگه میدارد و از شکست رایجی جلوگیری میکند که در آن مبدأ یک تیم محافظتشده و دیگری محافظتنشده است.
لبه همچنین تنها جایی است که دید کافی برای اعمال محدودیتهای همزمانی دارد، زیرا همه درخواستهای در پرواز برای یک هویت بار کاری را میبیند، صرفنظر از اینکه کدام مبدأ را هدف گرفتهاند.
تصمیمات پذیرش را بهعنوان رویدادهای ساختاریافته ثبت کنید
هر اجازه، رد، throttle و ابطال باید یک رویداد ساختاریافته با هویت بار کاری، شناسه قرارداد، کلاس عملیات و دلیل منتشر کند. هدف قابلیت تشخیص است: سوءاستفاده باید مانند یک نقض سیاست با یک قرارداد نامدار به نظر برسد، نه یک جهش ترافیک توضیحنشدنی که یک ساعت طول میکشد تا به کسی نسبت داده شود.
این همچنین گفتوگوی عملیاتی را تغییر میدهد. بهجای پرسیدن «چرا ترافیک بالا رفته؟»، سؤال میشود «کدام قرارداد از بودجهاش فراتر رفت، و آیا این انتظار میرفت؟» — سؤالی با یک مالک و یک پاسخ.
بازیابی فقطخواندنی را از فراخوانیهای تغییردهنده وضعیت جدا کنید
خواندنها و نوشتنها پروفایلهای ریسک متفاوتی دارند و باید مجوزهای متفاوتی داشته باشند. یک قرارداد بازیابی میتواند گسترده، ارزان و بهراحتی باطلشدنی باشد. قراردادی که وضعیت را تغییر میدهد به مجوز قویتر، بودجه جداگانه و در حالت ایدهآل یک مرحله تأیید انسانی یا سیاستی صریح نیاز دارد. یکیکردن آنها همان چیزی است که باعث میشود ایجنتی که قرار بود صفحهای را خلاصه کند، بهخاطر اعتبارنامه بیشازحد دامنهدارش، به یک endpoint ارسال کند.
یک مکانیزم مشخص: توکنهای کوتاهعمر و دامنهدار بر اساس عملیات را از قرارداد صادر کنید، و لبه هر درخواستی را که متد و مسیرش خارج از کلاس عملیات اعلامشده توکن باشد رد کند، حتی اگر هویت بار کاری زیربنایی معتبر باشد.
این چه چیزی را حل نمیکند
یک قرارداد پذیرش ایجنتها را قابلاعتماد نمیکند. آنها را پاسخگو و قابلتوقف میکند. کلاینتی که درباره هدفش دروغ میگوید همچنان دروغ خواهد گفت — اعلام یک مکانیزم هماهنگی است، نه یک مرز امنیتی.
دقیقاً به همین دلیل مسیر ابطال مهمتر از اعلام است. اگر تنها چیزی که بین یک کلاینت ناصادق و مبدأ ایستاده، یک رشته هدف خودگزارششده باشد، سیستم نمایش است. اگر سایت بتواند بار کاری را در میانه اجرا قطع کند، تصمیم را به یک قرارداد نامدار نسبت دهد و نقض را در لاگهای ساختاریافته ببیند، آنگاه اعلام به یک سیگنال مفید تبدیل میشود نه یک فرض باربر.
معاوضه صادقانه اصطکاک است. مذاکره یک قرارداد یک مرحله راهاندازی اضافه میکند، از کلاینتها میخواهد هویت بار کاری حمل کنند و سایتها را مجبور میکند یک control plane برای ابطال نگه دارند. سایتهایی که آن را نادیده میگیرند، همچنان ترافیک ایجنت را مانند ترافیک وب جذب میکنند و همچنان کشف میکنند که کلاینت آنطرف خسته نمیشود.
