Галоўная / Артыкулы

Чаму падыш узгадчасці спрычыная HTTP 429: што такое частота запуску і ліміты на адного хоста

Збільшэнне колькасці працоўнікаў без кантролю над шчыльнасцю запуску і лімітамі на адного хоста стварае спалахі, які вызываюць памылку 429. Пропускная здатнасць досягаецца за дапамогою рэгульавання паралельнасці, тэхнік звяртання праз час і розумнага праектавання абаранку.

Выдавец: REACTAPP.TOP16 хв чытання3571 слоў

Крыніцы: Why Increasing Concurrency Causes HTTP 429 Errors (It’s Not Just Too Many Requests)

TL;DR: Падыш у роўначаснасці працы адбываецца пад вывескай “бесплатны паралелізм”: больш работнікаў, больш запытоў, больш дадзейнасці. Дзесяць — гэта непарадны показнік, таму дваццаць павінны быць лепей, а пяцьдзесят — непраўдападобны. Але прыбавленне колькасці рэсурсаў не толькі падышвае роўначаснасць; гэта таксама вялікая мера таго, насколькі інтэнсыўна кліент падае запыты на хост з самага пачатку, а ў разе працы з калькама хостоў — якая роўначаснасць за аднаго хоста будзе існаваць без якога-лібо прызначэння. Калі гэтыя “скрытые” настройкі перастаюць працаваць, код статусу часта становіць HTTP 429, што абоўсюды асоціюецца з “занадта большым колікствам роўначасных запытоў”. Тады команды скарочваюць колькасць рэсурсаў, дадаюць проксі або проста пераходзяць да іншага рашэння. Не выявіўшы справжню прычыну, яны втрачаюць можлівасць падняць эфектывнасць працы.

Частка I — Роўначаснасць працы проты швайна запуску: адна настройка пула керуе двумя лімітамі

Размах колькасці працоўнікоў (p-limit(n), семафор, колькасць нітав) абмежвае колькасць операцыяў, якія можа выконвацца ў той момент. Ён не абмежвае швальнасць пачатку новых заданняў. У момент t=0 колькасць п’яцідзiesяты заданняў, якія чакают на выконанне, можа дазволіць запускаць п’яцідзiesят запітоў за адну імпульсную перыод — тэкст спаду швальнасці пачатку, — навет калі стабільная паралельнасць пазней будзе выглядаць “толькі п’яцідзiesятым”. Лімітары швальнасці уважаюць гэты раптовы сплеск так сама, як і стабільную паралельнасць.

Апылкаванне сплеску швальнасці пачатку

Дапамагае інструмент для павтаральных тэстаў. Возьміце невялікі набор URL-адрэсаў статэйкаў на Arch Linux Wiki:

https://wiki.archlinux.org/title/Arch_Linux
https://wiki.archlinux.org/title/Installation_guide
https://wiki.archlinux.org/title/Pacman
https://wiki.archlinux.org/title/Systemd
...and so on

Створыце навантажэння з 100 запітоў, парадуячы спіс:

function buildWorkload(urls, n) {
  return Array.from({ length: n }, (_, i) => urls[i % urls.length]);
}
async function runPooledFetch(urls, concurrencyLimit, agent, options = {}) {
  const limit = pLimit(concurrencyLimit);
  const results = await Promise.all(
    urls.map((url) => limit(() => fetchOne(url, agent)))
  );
  // ...
}

Заўядзейце з разнымі розмерамі басэна, класыфікуйце кожны рэзультат як «годна» або 429 (і іншыя працэзломы), а таксавайце колькасць завершаных запросоў за секунду разам з колькасцю «годных» рэзультатаў. Разлік мае значэнне: швырак 429 таксама спадчынае да метрыкі «завершаных запросоў/секунду», хаця не дастае стораніцы.

Корыстная праўоцяснасць падваічваецца з адным ростам глобальнай канкурантнасці

Калі колькасць запытак фіксаваная і зменшваецца толькі вялічына пула, працэўнае з’ёднанне практычна неэфектывна. Пры канкурэнцыі 1 практычна всі 100 запытакаў выкананы, і колькасць завершаных запытакаў на секунду становіцца або блізка 2,4/с — трэба чакаць на завершэнне апрацоўкі без можлівасці паралельных запускаў. Пры канкурэнцыі 10 корысных дадзеных застаецца мало: выкананыя стораніцы — або блізка 42, а 58% запытакаў вяртае код 429, тады колькасць завершаных запытакаў на секунду паднікае да або блізка 23,5/с. Пры канкурэнцыі 25 і 50 колькасць выкананых запытакаў продовжвае спадзяцца (апошней час — або блізка 24/100, потым 16/100) , тады колькасць завершаных запытакаў на секунду застаецца у дыяпазоне ад 18 да 22 на секунду (~18,2/с і 21,8/с).

Максімум прагізмы даесяць паралельных запускаў пры 23,5 завершаных запітоў/секунду — гэта сама высокая цыфра ў табліце — але разам з аднай з найгорэйшых колькасціў успешных запітоў. Для оптымізацыі па колькасці завершаных запітоў за секунду рэкамендуецца выбраць настройку, якая выкорыстоўвае большую частку «бюджэту» на блакаванні запітоў. Рэальна корыстны показнік — успешных запітоў/секунду, а не проста загальная колькасць завершаных запітоў.

Даадзеўкі ліміту швыроці запуску пры той жа канкурэнцыі вырашае проблему

Зберагце розмер пула без змены і контролюйце, калі можа пачацца наступны запіт. Мінімальную паўзу можна вылучыць на адной з наяўных настаўкаў па максымальнай колькасці запітоў за секунду:

// minGapMs derived from --max-rps; pool concurrency is untouched
if (minGapMs > 0) {
  const now = Date.now();
  const waitMs = Math.max(0, nextStartAt - now);
  if (waitMs > 0) await sleep(waitMs);
  nextStartAt = Math.max(Date.now(), nextStartAt) + minGapMs;
}

За дапамогою такога падходу тая ж канкурэнцыя, якая раней перавантажвала хоста, можа завершыць практычна всі сторанкі, адтаку запускаў зменшыцца. Правільны падход — выкарыстоўваць два параметра: канкурэнцыю (запускаемых запітоў) і швыроцю запуску (запітоў, якія дазволены за секунду). Аднакаванне іх у адна цыфру масківае прычыны неудач.

Чаму кластэрны HTTP-кліент адправляе серыю запыткаў у момант t=0

Кластэры не ведаюць пра адлічаны тэмп выканання запыткаў. Яны ведаюць пра вольныя слоты. Пад час запуску кожны слот ўвесь час вольны, таму кожная задача, якая можа быць выконана, дыржыць і ўжо выконваецца. Павторнае выкарыстоўванне з’язкоў і мультыплексаванне HTTP/2 можа зробіць густоту запыткаў ў канэ лініі ўсё вышэй. Толькі кантроллер дазволаў — такі як кантэйнер з токенамі, правілы мінімальнага інтэрвалу часу, кантэйнер з выцекам — можа кантролюваць пачатак выканання задач незалежна ад лімітаваў, дзеяных пад час ўжо выконваных запыткаў.

Чы рэзідэнцыйскія проксі выправляюць проблему раптовага падвышэння тэхасу запыткаў?

Адлічаны тэмп выканання запыткаў — гэта спосаб выправлення проблем з правільнасцю: сабіраць даныя без раптоваг падвышэння навантажэння на цэль. Але інжынерныя рэаліі іноды вымагаюць такой швалькі, якую не можа забезпечыць ліміт у 2,4 запытка/секунду. Той самы наўмовны падход — без ліміту тэхасу запыткаў, кластэрныя запыткі ў момант t=0 — калі яны праходзяць праз рэзідэнцыйскія проксі, можа даўаць прыблізна 98–99/100 успехоў, практычна без блакаванняў на розных рэвалюцыях паралельнага выканання, тады калі прамой шлях все ўсё равно страждае.

Гэта не значыць, што проксіы пазбегаюць неабходнасці разумець шчытласць запуска. Яны зменяюць рэпутацыю IP-адрэс і тое, насколькі агрэсыўна сайт прызначае трафік. Яны можу маскуваць спрыжчанне, якое могла б заблокаваць адзіну выходную IP-адрэсу. Калі тэхнічная вакалатка продукту — «збіраць даныя без адчування натоўпнага напору», то тэмпы застаюцца главным засобам кантролю; проксіы ўжо ўтвараюць слой магчымасцей і рэпутацыі, а не замену для вімеры колькасці запускаў.

Стварэнне проксі-агента зазвычай запоўняе даныя аб прывілегіях з аптэкі:

function buildProxyAgent() {
  const user = process.env.BRIGHT_DATA_PROXY_RESIDENTIAL_USERNAME;
  const pass = process.env.BRIGHT_DATA_PROXY_RESIDENTIAL_PASSWORD;
  if (!user || !pass) return null;
  const host = process.env.BRIGHT_DATA_PROXY_HOST || 'brd.superproxy.io';
  const port = process.env.BRIGHT_DATA_PROXY_PORT || '33335';
  const proxyUrl = `http://${encodeURIComponent(user)}:${encodeURIComponent(pass)}@${host}:${port}`;
  return new HttpsProxyAgent(proxyUrl);
}
const residentialAgent = buildProxyAgent();
await runPooledFetch(tasks, 50, residentialAgent);

Іспользуйце іх цярпліва, фіксуйце, чы праца была безпосерэдняя чы праз проксі, і ўсё раве фіксуйце зафіксаваную шчытласць запускаў на секунду, каб знаты, які фактор паўлікваў рэзультат.

Частка II — Канкурэнція на адного хоста

Глобальныя пулы таксама маскуюць другі, новападзяўшы ліміт. Разглядзіце:

const limit = pLimit(50);
await Promise.all(urls.map((url) => limit(() => fetchOne(url))));

Пяцьдзесят глобальных слотаў, распадзеленых між большам чысла хостаў, не значыць, што кожны хост бачыць максымум пяцьдзесят запускаемых заданняў. Парадак у чарзе і адхіленьні ў часе адпаведзення вялікай меры вабяць, сколькі запітоў на самай працэ практычна прыймае адны хост. Сумешаны спіс можа выглядаць збалансаваным на паперы:

1. arch
2. github
3. arch
4. mdn
5. npm
6. arch
7. cloudflare

але ўсё равно спрыяе значным навантажэнням на строгі хост, калі яго URL-адрэсы знаходзяцца ў наборэ заданняў, якія можна запусціць.

Аналіз паралельнай працы кожнага хоста

Павтараюць выкарыстоўваеце гэты інструмент з двума хостамі:

  • Строгі хост — Arch Linux Wiki (10 URL-адрэсаў статэйк), які блакуе пад навантажэнням, як і ў частцы I.
  • Благасклонны хост — стораніцы каталогу books.toscrape.com (10 URL-адрэсаў), якія рэдка блакуе і служыць для кантролю. Калі сандбокс не працуе, значы кліент несправны.

Альтэнатыўны спіс дае 20 URL-аў × 5 павтарэнняў = 100 запытоў пры глобальнай канкуранцыі 50. Спісы фіксатуў і канструяторы знаходзяцца ў рэпазітарыі open-concurrency-trap-bench (напрыклад urls-mixed-arch-books.txt).

https://wiki.archlinux.org/title/Arch_Linux
https://books.toscrape.com/catalogue/page-1.html
https://wiki.archlinux.org/title/Installation_guide
https://books.toscrape.com/catalogue/page-2.html
https://wiki.archlinux.org/title/Pacman
https://books.toscrape.com/catalogue/page-3.html
...and so on

Упорадкованыя завадзбы можна выконваць за прынцыпам round-robin, блакаваць па хостах або перасортаваць за дапамогою сэду:

function buildOrderedWorkload(urls, pattern, { repeatsPerUrl = 5, seed = null } = {}) {
  const n = urls.length * repeatsPerUrl;
  let list = Array.from({ length: n }, (_, i) => urls[i % urls.length]);
if (pattern === 'block') {
    // AxN, BxN, and so on. Repeat each URL before advancing.
    const out = [];
    for (const url of urls) {
      for (let i = 0; i < repeatsPerUrl; i++) out.push(url);
    }
    return out;
  }
if (pattern === 'shuffle') {
    // Fisher–Yates with a fixed seed so the run is reproducible
    for (let i = list.length - 1; i > 0; i--) {
      seed = (Math.imul(1664525, seed) + 1013904223) >>> 0;
      const j = seed % (i + 1);
      [list[i], list[j]] = [list[j], list[i]];
    }
  }
  // 'round-robin' leaves the alternating list as-is
return list;
}

Змяроўваецца максімальны пакет заданняў на кожнам хосце на адной з моментаў пачатку/заканчэння:

function maxConcurrentPerHost(results) {
  const eventsByHost = new Map();
  for (const r of results) {
    const host = new URL(r.url).hostname;
    if (!eventsByHost.has(host)) eventsByHost.set(host, []);
    const end = r.startedAt + r.ms;
    eventsByHost.get(host).push({ t: r.startedAt, delta: 1 }, { t: end, delta: -1 });
  }
  // sort events by time, sweep: +1 on start, -1 on finish, track max
}

Глобальная канкуранцыя застаецца стаячай; зменяецца толькі парадак. Чыгунтае цэ гучанне на кожны хост ад размеру пула.

Як парадак у чэрзі зменяе канкуранцыю на кожны хост

Рэальныя краулеры ніколі не выконваюць заданні за прынцыпам perfect round-robin вечна. Сайтмапы, графы залежнасцяў і чэргі на павторны запуск перасортаваюць заданні. Таму ідэнтычныя глобальныя настройкі можа даць разныя максімумы на кожны хост.

1. Round-robin: альтэнатыўнае равныя распадзеленыя хосты

Альтэнатыўны спіс (A B A B …) распрашчае работу. Максімум запрашанняў на строгам хосце застаецца ступеняваным, таму што іншы хост продовжвае займаць вільныя рэсурсы.

2. Блок: агрупаванне запрашанняў з таго ж хоста

Агрупаванне всіх URL-адрэсаў Arch, а пасля ўсіх URL-адрэсаў кніг, дае строгаму хосту моцна длігкі перыяд працы. Максімум запрашанняў на гэтым хосце падыходзіць да розмеру глобальнага пула, нават як «канкурантнасць застаецца 50».

3. Шуфляваўне (сэд 42): абыяковы парадак

Шуфляваўне з заданым сэдам знаходзіцца межа двух крайносцей і відпраўляе абыяковы парадак запрашанняў. Максімумы зменяюцца ў залежнасці ад сэда; урок тут — чувствяўнасць, а не магічная пермутацыя.

Тая ж глобальная канкурантнасць, разны тыроз на кожнага хоста

У разліце з гэтымі шаблонамі, практычны рэйт канектыбілітэта на строгай гульпе парадкавае свой максімум у процэсе выпалоў болей адточна, чым сталягае глобальнае значэнне c=50. Благасклонная гульпа застаецца здаровай. Зніжэнне глобальнага розмеру гульпы, каб «вылечыць» строгую гульпу, таксама зашкодзіць благасклонной гульпе і так і не дапаможаў бы стабілізаваць максімум строгай гульпы пад некаштовным порадкам выпалоў.

Рашэнне: аддзельна лімітувацыя канкурантнасці па гульпе

У Частцы I быў даданы ліміт на швальнасць запуску праз гульпу. У Частцы II дадаўся ліміт па гульпе: внутрані ліміт на тое, сколькіх запускаў у процэсе выпалоў можа маты цяперашній хост.

Памяцайце тры тэрміны:

  • Глобальная канкурантнасць — спяльны розмер гульпы (напрыклад p-limit(50)). Яго задаеце вы.
  • Канкурантнасць па гульпе — тое, што фактычна бачыў адзін хост (peak_inflight). Яго вімерваеце вы.
  • Ліміт на адміністрацыю — адзінэчны максімум, які вы выбіраеце для колькась тымчасовых запыткаў, якія можа прыймаць адна конкрэтная адміністрацыя, якай знаходзіцца пад кераваннем глобальнага пула.
  • Калі такі ліміт на адміністрацыю не існуе, кожны вольны глобальны слот можа быць выкарыстоўаны тымі URL-адрэсамі, якія ў той момент ў доступе — што можа прывесты да перанасылення адной адміністрацыі. Даўжэнне внутрашняга ліміту дазволяе кожной адміністрацыі маты свой саўны:

    async function runPooledFetch(urls, concurrencyLimit, agent, { perHostLimit } = {}) {
      const globalLimit = pLimit(concurrencyLimit);
      const hostLimiters = new Map();
      async function fetchWithLimits(url, execute) {
        return globalLimit(async () => {
          if (perHostLimit && perHostLimit >= 1) {
            const host = new URL(url).hostname;
            if (!hostLimiters.has(host)) hostLimiters.set(host, pLimit(perHostLimit));
            return hostLimiters.get(host)(execute);
          }
          return execute();
        });
      }
      // ...
    }
    

    Такім чынам кластэр URL-адрэсаў з строгімі лімітамі не можа адразу зайняць усе глобальныя слоты. Адміністрацыі з менш строгімі лімітамі все ўсё можа выкарыстоўваць застатковую прыемнасць. Забаны стаюць наследкам тых лімітаваных параметраў, якія вы хацелі кераваць.

    Чаму спяльны пул працоўнікаў концентруе навантажэнне на адной адміністрацыі

    База дадзеных запоўняе асобкі паверхні любымі заданнямі, якія можна выконваць. Шырокаспектныя хосты быстра зваліваюць асобкі паверхні і беруць на сябе больш за сваімі можлівасцямі заданняў — пакуль група URL-адрэсаў строгіх хостоў не стане спроможнаю выконваць заданняя разам і не успадкуе павышаную навантажэння. Размах павышанай навантажэння залежыць ад парадку выконвання, затрымкаў і сумешанні заданняя — нічога з гэтага не практыкуецца ў аднам целым для вырачэння канкурантнасці. Самэ гэтая прычына, чаму лімітар па кожны хост ёсць лепшы, чым слепа зменшэнне глобальной базы дадзеных.

    Практычны чарткі

    • Спрыяйце шчытлу запуску як самастояму настройкі. Семафор не ёсць лімітарам RPS. Дадзіце явны ліміт шчыту запуску па боку канкурантнасці.
    • Спрыяйце канкурантнасці па кожны хост як самастояму настройкі. Заданняя для калько хостоў патрабуюць лімітара па кожны хост унутры глобальной базы дадзеных.
    • Зявіце логі observed_start_rps і паказнік peak_inflight па кожны хост. Нельга аналізаваць ліміты, якія ніколі не былі вымераны.
  • Оптымізавайце корыстны праўерхнёс. Урачыставайце показнік ok-per-second, а не completed-per-second; быстрыя 429s таксама лічыцца як неудачы.
  • Точныя прагі ў кожнай адзіной працы блога не ўсёвыконныя: лімітары залежнаць ад стану сістэмы і залежаць ад часу, історыі трафіку і рэпутаціі IP. Універсальны падход — ізоляцыя. Неудача, якая выглядае як «занадта веліка канкурантнасць», можа быць проблемай швальнага тэмпу запуску, проблемай планавання для кожнага хоста або ж і тым, і іншым. Даколі гэтыя факторы не будуць аддзельнымі, скарчэнне колькасці рэсурсаў падае толькі на сімптам — і часта не на правы.

    Чытанне метрык без абману сабе

    Колькасць завершаных запыткаў за секунду зростае кожны раз, калі кліент можа быстра ачыняць сокеты — нават тады, калі большасць адпаведзей ёсць адмовы. Дашборды, якія фіксуюць працу паўнароўнай паралельнасці без фільтра па статусу „ok“, будуць рэкамендаваць шкодныя настройкі. Паруйце кожную дыяграму праэфектыўнасці з кантэкстам статусу „ok“ і, як толькі можна, з колькасцю байтав корыстнага кантэнту, які засталіся. Калі ваша сістэма прабуе зноў выканаць запыткі, якія вярнулі код 429, пісачыце колькасць такіх спроб окрэма, ўбачліва, каб надмерная колькасць прабаў не выглядала як продуктыва паралельнасць.

    Логі з колькасцю запыткаў, якія былі прыймлены, должны фіксаваць часовы пазнак з кожнага прыймання, а не толькі з кожнага завершэння. На аднойчыных дадзенах вы можэце відтворыць сплескі акывнасці прыбліжна за першыя 100–500 мс, і самэ гэта ёсць тым перыядам, калі багато кліентаў выглядаюць аднакова, незалежна ад установленага розмеру пула. Калі две настройкі маюць аднаковы сплеск пачатку акывнасці, не дзівіцеся, калі ў іх будзе аднаковы патэрн адмов.

    Проксі, рэпутацыя і часовасць ў спраўе компромісаў

    Проксі для жытловых прыемнікаў чы сэрвераў збору дадзеных перадаюць ідэнтыфікацыю. Яны можаць ператварыць атаку з аднаго IP-адрэса на некалькі менш інтэнсыўных трафікаў. Гэта дапамагае праектам збору дадзеных і можа скрыць слабыя механізмы кантролю доступу ад пункта прыема, які ставіць ліміты на IP-адрэсы. Гэта не пазбавляе нас этычных і даговорных абавязакаў па відношэню да сайтаў, з якіх мы запрашываем дадзеныя, а таксама не пазбавляе нас тэхнічной неабходнасці разумець свога сопрацоўніка. Калі вы контролюеце сопрацоўніка, спачатку важліва стабільнасць; выкорыстоўвайце проксі тады, калі продукт практычна выклікае большую загальную праўоцэсу наявнасці праз некалькі ідэнтыфікацый — і продовжайце мераваць навантажэнне на кожную ідэнтыфікацыю і кожны хост, ўбачліва не працаваючы слепа за шаром проксі.

    Аднае ў адно

    Програмы для аналізу працэй зазвычай патрабуюць або ўсіх этых параметраў: глобальны рэзерв для захавання рэсурсаў з вашай стороны, ліміт швырака запуску для адпаведнасці пад час прыемкі, а таксама ліміты на кожнага хоста, калі кантэйнеры дзеляюць аднойчы рэзерв. Ігнараванне хоць якога з іх восстанавляе сітуацыю краху, якая “выглядае як канкуранція” у кодах статусу HTTP. Адлагоджэнне не ўмоўнае; гэта апаратная падтрымка плюс другі лімітар, нацэлёваны на ту зменную, якую вы фактычна заазначылі.

    Прыметкі да дызайну прыладоў, якія забезпечваюць справядлівыя порэванні

    Зберагаеце ідэнтычную таксанамію успеху па всіх працаваннях: статусы «ok», HTML, HTTP 429, іншыя коды 4xx/5xx, працяўкі часу і бягучыя памілкі парсавання должны меткацца аднойчынна ў кожнай практыцы. Зменяйце толькі параметры, якія тэстуеце — велічыну пула, мінімальны прыемлівы інтэрвал, увёмкванне/выключэнне проксі чыста парад у чэрзі. Як толькі можна, адгрэйвайце DNS і TLS, каб першыя пункты графіка не былі занадта адчувальныя да парадоксаў холаднага адключэння, як толькі холадны запуск не ўскладнюецца як частка эксперыменту.

    Павтараюце заведамасці достатню колькасць разоў, каб зменшыць шум, але не так часта, каб адаптатыўны лімітар сайту перманентна зменяўся ў ходзе эксперыменту. Калі лімітары маюць стан, зазначайце час дзяніны і чы можа паказваныя раней забароны ўсё яшчэ вплываць на працу. Публікуйце значэння-семены для перасортавання, каб іншыя моглі відтворыць эфекты параду.

    Адрэсы URL должны быць стабільнымі. Заглавяў у Вікі і стороніцы каталогу сандбокса, якія знікаюць пад час аналізу, спакштуюць лік паводлів. Зберагаюце спісы фіксаў у сістэме кантролю версыйяй разам з іншымі дадзеннямі, як гэта робіць праект concurrency-trap-bench, каб графікі аднасіліся да вядомых вхідных дадзенняў.

    Як выглядае «прыдатны праўерхад» у пайплайне

    Сістэмы, якія працуюць пасля перадачы дадзенняў, актуальныя для ўсвайомлення дакументаў, а не колькасць з’являючыхся і знікаючых соектаў. Калі скрапер падае дадзеныя індэксатору, лічыце дакументы, якія былі індэксаваны за хвіліну. Калі ён падае дадзеныя базе даных цэнаў, лічыце паўнастаўленыя рэкорды. Салідаравайце цель оптымізацыі з задачамі данай бізнес-ячэйкі. Аднойчы больш інжынеры будуць максімізаваць прамежуточны показнік — колькасць завершаных HTTP-звяроўкаў — які включае велічызны колькасць тэлаў з кодам 429.

    Павтаральныя спробы пагубна вплываюць на басейны без рэгулярнага таймінгу. Разгар актывацыяў, які прыводзіць да забаранень, а пасля ягох негайныя павтаральныя спробы, можа ўсё больш збільшыць шчыльнасць запускаў. Павышайце інтэрвал павтаральных спроб у разы 429 з дэфляксам, адказваюце на параграф Retry-After, калі ён прысутны, і ніколі не дазволяйце штормам павтаральных спробаў абійсці правіла шчыльнасці запускаў. Контролер адмашчэння павінен спрыймаць павтаральныя спробы як новыя запускі.

    Распрацоўвальнікі з мнагама аб’ектамі і мнагамі хостамі

    Сэрвісы, якіе выпалююць запускі за аднаковах кліяўцаў, часта ужо маюць глобальныя ліміты паралельнасці для абэрнення небяспек. Ім таксама патрабуюцься бюджэты на кожную мету, каб спіс URL аднаго кліяўца не могаў монапалізаваць канкрэтны хост. Глобальныя, на аднаго аб’екта і на аднаго хоста — гэтыя ліміты складаюцься адна з іншай. Адкалікваўце іх як чыста выражаныя слоі, а не спадзяючыся, што справядліва чэрга будзе створвацца за дапамогою аднаго семафора.

    Калі адмініструемыя машыны значна разлічаюцца па часе адпаведзбы, баскаменты для розпадзелу задаў наклоняюцца да шырокаскорастай машыны. Такі наклон паслядзеюць для кэрыяткі рэсурсаў, але шкодзіць медленай, строгай машыне, калі яе URL-адрэсы нарэшце стануць можлівымі да запуску. Ліміты на адную машыну скарочваюць шкоду; неабяжныя вагі для кожной машыны можаюць дапамогчы выражыць правілы вважлівасці.

    Інтэрпрэтацыя рэзультатаў проксі без магічных выкладак

    Калі прымітны выход не ўдаецца, а выход праз проксі успевае за ідэнтычных настройках баскаменту, магчыма, пункт прызначэння адбірае рашэнні на адвярсе на ідэнтычнасць сеткі. Гэта корыстная практычная інформацыя. Гэта не ўскладненне, што змянілася фізыка частоты запуску. За проксіямі вам яшчэ трэба логаваць запускі па кожнай ідэнтычнасці выходу і па кожной мэтавай машыне. Аднак калі гэта не зрабіць, вы проста перамешчаеце слепую пляму.

    Палітры правіл са адпаведнае дзеянне і працы застаюцца вашай адпаведнае дагадкай. Вышэйшыя загальныя показнікі працяздатнасці праз многа выходы падвайшваюць радыюс уражэння логічных бягаў. Рэгулюванне швайнасці функцый і ліміты на адного хоста дзеяўць нават калі ўвёраны проксі, тады вы можэце зменшыць ступень агрэсіўнасці без перапрацоўкі інфраструктуры айдэнтыкацыі.

    Закрыць цыкл ад эксперыменту да стандартных настаўк

    Калі памеры пакажуць, што швайнасць запуску і максімумы на адного хоста лепшая прыводзяць да забаранень, чым сама глобальная велічына пула, тады неабходна закодаваць гэтыя нараджэнні як стандартныя настаўкі ў бібліятэцы кліента: выкарыстоўваць параметр RPS (або min-gap), задаць ліміт на адного хоста для рэжымаў з колькіма хостамі, а таксама экспортуваць показнікі для обох. Дакументацыя должна паказваць некорэктную панель керування (зростаючыя значэнні completed req/s пад час спаду ok) разам з правільной. Навчанне пра способы абякання запобегае таму, каб наступная команда “вылечыла” проблему са адночаснасцю, чым спрычыніла тыхае перыванне корысных дадзеных.

    Чыстая рээксперыментаванне з эксперыментам працы выхаджэння

    Застаўце конкрэтныя версіі Pin Node і undici (альбо вашага HTTP стаку), каб практыка аб’еднання з’яўленняў залічвалася пахожай. Час адбыцца спрабаў падтрымкі, сэродзеўных браузеру, выключыце пад час адбыцца спрабаў. Ачысціце кэш DNS между працаваннем без посерэдніка і з посерэднікам, калі ваш прыстрой для тэставання разным чынам распрацоўвае хосты. Запісвайце час ад початку да канца для всей пачкі, а таксама часы запуску і завершэння кожнага запіту, ўпрымкі, каб можна было аналізаваць запыткі пры першых паўсекундзе — таму, дзе кліенты з аб’еднанням выглядаюць ідэнтычныя, незалежна ад стабільнага роўня канкурэнцыі, які, як вы смярдзіце, быў установлены.

    Пад час стварэння графіка завжды паказвайце колькасць успешных запыткаў разам з колькасцю завершаных запыткаў/секунду. Графік з двумя восьмамі, які маскіруе колькасць успешных запыткаў, — гэта спосаб, якім марнаваныя показнікі выграюць споры. Экспортуйце CSV з прыстрою для тэставання, каб іншыя моглі пераскладзіць даны без павернення ў спрабах.

    Інтэрпрэтаванне строгасці у стыле Arch Wiki

    Сервары для публічнай документацыі разнаюцца: якія-то обмежваюць працэю па IP-адрэсах і шляхах, якія-то — па User-Agent, якія-то — па канектаціях адночасна, якія-то — па частоце запыткаў у працуючых вакнах. 429-я памылка сёньдзе можа стаць менш выражаным споваленнем завтра, калі зменяецца політыка аператара. Таму цыфры ў стацыі ёсць толькі ілюстратывальнымі прыкладамі, а не вечнымі сталямі. Гэта, што ўсё роўна застаецца, — гэта методалогія: выдзельваеце розныя показнікі — размер басэна, шчытаўку запыткаў і максімумы на кожны сервер, а потым зменяеце адну зменную за раз.

    Калі вы вікорыстаеце свой сувёршана строгі сервер, трэба ў той жа прыем эксперыменту застаўляць сервер з менш строгім кантролем. Калі кантрольны сервер не працюе, ваш кліент таксама не будзе працаваць. Калі не працюе толькі строгі сервер, вы можаце аналізаваць, як іхня політыка вялоўна паўтараецца пад час вашага графіка.

    Дэталі рэалізацыі ліміту начальной шчытаўкі

    Мінімальны прыем, вылічаны з максімальной колькасці запыткаў за секунду, ёсць простым і эфектывным рашэнням для кліентаў з аднам працэсам. Кошкі токенаў дазваляюць короткія спалахі запыткаў, адночасна прабачаючы довгатраўнія срэднія значэння — гэта корыстна, калі хочаце швайнах інтэрактыўных запыткаў, але таксама адпаведальных масовых сканаванняў. Кошкі з выцэчамі спрыяюць болейшай роўнасці. Які бы алгорытм вы не выбралі, прыменяйце яго да пачатку запыткаў, уключаючы праказы. Напор праказ, які амаль не прыводзіцься пад контроль, зноў стварае сітуацыю, падобную да той, якая была ў момент t=0 пасля першага забаранення.

    Многапроцесовыя сканеры патрабуюць распадзеленага замка дазволу (Redis, etcd або цэнтральны раскладчык). Толькі локальныя прыемы не зможу коордынаваць пяць працоўнікаў, кожны з якіх думае, што можа выканаць два запыткі за секунду.

    Дэталі рэалізацыі ліміту на аднаго хоста

    Звычным патэрнам являюцца вкладзеныя семафоры, прыязваныя паведамленням хоста: спачатку захопляецца глобальны семафор, потым — семафор хоста, пасля чаго выконваецца запытка, а ў зворачным парадку — ўзвольненне рэсурсаў. Паказваць, чыя www і apex адналежаць да аднаго ключа. Неабяжна вырашыць, як перэнаправленняя, якія зменшаюць колькасць хостаў, падчыняюцца лімітам. Шаркі таго ж сайту, заснованыя на паце, зазвычай яшчэ дзеліць аднаковы бюджэт хоста, калі толькі няма чынных доказаў ад CDN пра іншае.

    Выдаць метрыкі: inflight_global, inflight_per_host{host}, admissions_per_second, http_429_total{host}. Адмаўляць паведамленні, калі рэштка ліміту 429 падыходзіць да канца, а не толькі калі выкарыстоўваецца ліміт на памілкі 5xx.

    Парадакт у чэргах у продакшн-скедуляроў

    Парадакт схемы сайта, алгорытм BFS з гэтаго «насення», калекулкі прыорытэта для «важлівых» URL-адрэсаў і калекулкі для павторных спроб усе гэта перакраявае максімумы навантажэння на кожны хост. Калекулка для павторных спроб, якая ставіць у пачатак спіс неудачных Arch-URL-адрэсаў, можа случайна зноў стварыць пэракрантаванне блакоў пасля частковага перыяву. Справядлівае распадзеленне у запятах між хостамі — калекулкі прыорытэта у фармаце round-robin для кожнага хоста — зменшае случайную концентрацію навантажэння ўсё раней, чым наступаюць жорсткія ліміты. Жорсткія ліміты заставаюцца неабходнымі, калі сама справядлівасць не можа обмежыць максімумы навантажэння пад асамацельным часу адпаведзення.

    Проксі без самахамання

    Домашнія сеткі зменяюць распадзеленне ідэнтычнасцей. Але яны не скасоўвают законамі фізыкі: калі кожная ідэнтычнасць усё равно праганяе п’ятдэсят запытаў адразу, то серверы, якія вырашаюць пра доступ на адпаведнасць да падзеяў, а не толькі IP-адрэса, можа ўсё равно забаніць доступ. Хроніруйце запыты па кожнай ідэнтычнасці выходу. Адменавацыйна зміняйце іх адзін за другім. Следавайце правілам для робатаў і умовам контракту. Вярнавайцеся да адмеркаванага тэнара нават тады, калі праксі ўвёраны, каб баг не могаў распрасцірацца на вялікі радыус.

    Проксі-серверы датацэнтраў ёсць дэшавейшыя і лёгкія да аўтэнтыфікацыі; проксі для домашніх вычынакоў ёсць дорожэйшыя і маюць этычныя проблемы. Выбірайце ўважна; не вважайце «проксі» сынонімам слова «радчы».

    Ад эксперыменту да стандартных настаўкі бібліятэкі

    Убудуйце два неабходныя параметры ў кэшэруючыя оберткі HTTP-кліентаў, якія вікорыстоўваюцься краулерамі: maxInFlight і maxStartsPerSecond, а таксама maxInFlightPerHost, калі есць больш ад однага хоста. Абмовіцеся ад стварэння кліента для рэжыму з колькіма хостамі без ліміту на кожнага хоста. Прадастыце шаблоны панелі керування, якія відображаюць колькісць успешных запыткаў за секунду. Навчайце працэўнікам на адной часовой шкале: паралельнае відвядзанне 10 запыткаў даходзіць да высокага розміру пропускной здатнасі, але водночас губяцца корыстныя сторанкі.

    Расшырэны спіс пераконтраць

    • Установіце ліміт на запускі, а не толькі на актыўныя запыткі.
    • Установіце ліміт на кожнага хоста ў межах глобальнага пула.
    • Звярняйце увагу на колькісць запыткаў, якія прыймаюцца, і на максімальныя показнікі за кожнага хоста пасля кожнага запуску.
  • Ацэнаваець успех па базе корыстных стораначак, а не па колькасці завершэнных супрацоўкаў.
  • Застаўляць кантроль прыпуску да павторных спробах.
  • У сумешаных тэстах выкорыстоўваць лёгкія правілы кантролю.
  • Успех праексі спрацоўкі расследжваць як змяну рэпутацыі, а не як доказ таго, што планаванне працы ў стане.
  • Перазьвяртатыся да цыфраў, калі змянююцца правілы парадоксу; застаўляць тую ж методыку.
  • Даколі гэтыя прывычкі не стануць неразлучнымі, каманды будуць продаваляць “вылечэнне канкурэнтнасці” ў тых падступных формах абяканняў, якія ўсё раве вяртаюць HTTP 429 і продаюць бюджэты краўлення.