Домклик: критерий обрыва по доле блоков — нужна своя калибровка (один прокси без ротации, цена ошибки другая) #3189

Closed
opened 2026-08-28 18:21:32 +00:00 by bot-backend · 1 comment
Collaborator

Отделено от #3184 по требованию ревью. Не начинать, пока нет замера по Домклику — вся суть задачи в калибровке, а калибровать сейчас не на чем.

Почему Домклик не поехал вместе с Авито

В #3184 критерий обрыва заменён с «N блоков подряд» на долю блоков в скользящем окне (20 попыток, порог 0.7). Изначальная постановка говорила «то же самое для Домклика». Ревью это сняло, и правильно.

data/sql/175_scrape_schedules_seed_domclick_detail_backfill.sql:41-44 документирует, почему у Домклика max_consecutive_blocks=3, а у Авито 5:

DomClick has no IP-rotation recovery on block (one dedicated residential proxy, not a pool) — aborting sooner avoids hammering an already-reputation-damaged proxy/session

То есть у Авито блок означает «сменим узел и продолжим», у Домклика — «мы жжём единственный узел». Ранний обрыв там не грубость критерия, а защита ресурса.

Калибровка 20/0.7 сделана на 40 прогонах Авито, то есть на пуле с ротацией. Перенеси её на Домклик — при устойчивой доле около 0.65 прогон не оборвался бы никогда: batch_size=200 × ~12 с = порядка 130 заблокированных запросов по QRATOR с одного репутационного адреса. Ровно то, что порог 3 был призван предотвратить.

Чего не хватает для решения

Данных. По Авито у нас 40 прогонов с долями 25-100%, по Домклику — ни одного разбора. Неизвестно:

  • какова у него типичная доля блоков в здоровом прогоне;
  • идут ли блоки пачками так же, как у Авито, или у единственного узла картина другая;
  • через сколько блоков подряд узел реально портится (это и есть цена ошибки, а у Авито её нет).

BlockRatioBreaker (app/services/backfill_block_breaker.py) написан источник-агностично, так что механика переиспользуется. Вопрос только в порогах и в том, нужен ли Домклику вообще критерий по доле, а не по серии.

Порядок

  1. Сначала — гистограмма пачек в counters для Домклика (механика из #3184, без смены критерия обрыва). Собрать данные, ничего не меняя в поведении.
  2. Дать накопиться прогонам, посмотреть распределение.
  3. Только потом решать: свои пороги окна/доли, или у Домклика серия остаётся правильным критерием из-за цены выжигания единственного узла.

Шаг 1 безопасен и его можно делать сразу. Шаги 2-3 — после данных.

Приёмка

  • Домклик пишет block_streak_histogram в counters, поведение обрыва не изменено
  • Собрано не меньше 20 прогонов, распределение долей и длин пачек описано в тикете
  • Принято обоснованное решение: свои пороги либо сохранение критерия по серии
  • Решение записано в vault со ссылкой на 175 и на этот замер

Оценка: шаг 1 — S, шаги 2-3 — после данных. Refs #3184, #3177

Отделено от #3184 по требованию ревью. **Не начинать, пока нет замера по Домклику** — вся суть задачи в калибровке, а калибровать сейчас не на чем. ## Почему Домклик не поехал вместе с Авито В #3184 критерий обрыва заменён с «N блоков подряд» на долю блоков в скользящем окне (20 попыток, порог 0.7). Изначальная постановка говорила «то же самое для Домклика». Ревью это сняло, и правильно. `data/sql/175_scrape_schedules_seed_domclick_detail_backfill.sql:41-44` документирует, почему у Домклика `max_consecutive_blocks=3`, а у Авито 5: > DomClick has no IP-rotation recovery on block (one dedicated residential proxy, not a pool) — aborting sooner avoids hammering an already-reputation-damaged proxy/session То есть у Авито блок означает «сменим узел и продолжим», у Домклика — «мы жжём единственный узел». Ранний обрыв там не грубость критерия, а защита ресурса. Калибровка 20/0.7 сделана на 40 прогонах Авито, то есть на пуле **с** ротацией. Перенеси её на Домклик — при устойчивой доле около 0.65 прогон не оборвался бы никогда: `batch_size=200` × ~12 с = порядка 130 заблокированных запросов по QRATOR с одного репутационного адреса. Ровно то, что порог 3 был призван предотвратить. ## Чего не хватает для решения **Данных.** По Авито у нас 40 прогонов с долями 25-100%, по Домклику — ни одного разбора. Неизвестно: - какова у него типичная доля блоков в здоровом прогоне; - идут ли блоки пачками так же, как у Авито, или у единственного узла картина другая; - через сколько блоков подряд узел реально портится (это и есть цена ошибки, а у Авито её нет). `BlockRatioBreaker` (`app/services/backfill_block_breaker.py`) написан источник-агностично, так что механика переиспользуется. Вопрос только в порогах и в том, нужен ли Домклику вообще критерий по доле, а не по серии. ## Порядок 1. Сначала — гистограмма пачек в `counters` для Домклика (механика из #3184, без смены критерия обрыва). Собрать данные, ничего не меняя в поведении. 2. Дать накопиться прогонам, посмотреть распределение. 3. Только потом решать: свои пороги окна/доли, или у Домклика серия остаётся правильным критерием из-за цены выжигания единственного узла. Шаг 1 безопасен и его можно делать сразу. Шаги 2-3 — после данных. ## Приёмка - [ ] Домклик пишет `block_streak_histogram` в `counters`, поведение обрыва не изменено - [ ] Собрано не меньше 20 прогонов, распределение долей и длин пачек описано в тикете - [ ] Принято обоснованное решение: свои пороги либо сохранение критерия по серии - [ ] Решение записано в vault со ссылкой на 175 и на этот замер Оценка: шаг 1 — S, шаги 2-3 — после данных. Refs #3184, #3177
bot-backend added the
scope/backend
scrapers
status/needs-analysis
tradein
labels 2026-08-28 18:21:32 +00:00
Owner

Закрываю: посылка задачи опровергнута кодом и продом.

«У Домклика один выделенный резидентный прокси, пула нет» — неверно. Свип ходит через пул: providers/domclick/serp.py:359-361 строит фетчер как build_browser_fetcher(self._config, "domclick", proxy_provider=self._proxy_provider), провайдер прокинут из orchestration/pipeline.py:4379, а providers/_base.py:227-232 ставит use_pool=config.use_proxy_pool_browser — в контейнере tradein-scraper это USE_PROXY_POOL_BROWSER=true (проверено printenv на проде 29.08).

Прод на 29.08: 4 включённых узла — 1 (asocks-residential-1), 9, 10, 11 (asocks-mobile-1..3). У всех четырёх provider_affinity='any'. Домклик-бан ровно один, на узле 1, banned_until 2026-08-29 09:20 UTC — уже истёк. Ротировать есть куда.

Источник неверной посылки, судя по всему — докстринг serp.py:332 («в пуле 3 включённых узла, 2 забанены Домкликом»). Он устарел, поправим отдельно.

Мобильные узлы QRATOR проходят — это и было главным «чего не хватает» в теле задачи. Замер 29.08: 6 карточек подряд через узел 11 (asocks-mobile-3) с reuse_context=true → первая 401/7086 байт (челлендж PoW), остальные 5 — HTTP 200 и __SSR_STATE__, 540-847 КБ. Контроль без reuse_context: каждая вторая карточка — страница блока ровно 26 625 байт, и так на всех четырёх узлах. То есть прежние отказы объяснялись выбрасыванием browser context (#3212), а не качеством узлов.

Тем самым исчезает и обоснование раннего обрыва «мы жжём единственный узел» — жечь нечего, узлов четыре и они рабочие. Калибровка порога по доле блоков в текущей постановке смысла не имеет.

Продолжение — в #2854: там правка не в пороге, а в serp.py:419, где break кладёт весь свип на первой же корзине (отсюда buckets_completed=0 в каждом прогоне).

Закрываю: посылка задачи опровергнута кодом и продом. **«У Домклика один выделенный резидентный прокси, пула нет» — неверно.** Свип ходит через пул: `providers/domclick/serp.py:359-361` строит фетчер как `build_browser_fetcher(self._config, "domclick", proxy_provider=self._proxy_provider)`, провайдер прокинут из `orchestration/pipeline.py:4379`, а `providers/_base.py:227-232` ставит `use_pool=config.use_proxy_pool_browser` — в контейнере `tradein-scraper` это `USE_PROXY_POOL_BROWSER=true` (проверено `printenv` на проде 29.08). Прод на 29.08: **4 включённых узла** — 1 (`asocks-residential-1`), 9, 10, 11 (`asocks-mobile-1..3`). У всех четырёх `provider_affinity='any'`. Домклик-бан ровно один, на узле 1, `banned_until 2026-08-29 09:20 UTC` — уже истёк. Ротировать есть куда. Источник неверной посылки, судя по всему — докстринг `serp.py:332` («в пуле 3 включённых узла, 2 забанены Домкликом»). Он устарел, поправим отдельно. **Мобильные узлы QRATOR проходят** — это и было главным «чего не хватает» в теле задачи. Замер 29.08: 6 карточек подряд через узел 11 (`asocks-mobile-3`) с `reuse_context=true` → первая 401/7086 байт (челлендж PoW), остальные 5 — HTTP 200 и `__SSR_STATE__`, 540-847 КБ. Контроль без `reuse_context`: каждая вторая карточка — страница блока ровно 26 625 байт, и так на всех четырёх узлах. То есть прежние отказы объяснялись выбрасыванием browser context (#3212), а не качеством узлов. Тем самым исчезает и обоснование раннего обрыва «мы жжём единственный узел» — жечь нечего, узлов четыре и они рабочие. Калибровка порога по доле блоков в текущей постановке смысла не имеет. Продолжение — в #2854: там правка не в пороге, а в `serp.py:419`, где `break` кладёт весь свип на первой же корзине (отсюда `buckets_completed=0` в каждом прогоне).
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3189
No description provided.