Пять оставшихся требований эпика Э4 закрыты, выкачены на боевой сервер и проверены на живой нагрузке. Главное подтвердилось: ограничитель действительно ограничивает, потолок растёт от нового адреса без перезапуска, а китайская площадка перестала жечь адреса. Осталось купить.
Теперь переезд возможен, только когда физических адресов два и больше. При одном — честная пауза площадки и отдельное событие в колокольчике админки: «единственный маршрут — переезжать некуда». Событие описывает состояние пула, а не происшествие, поэтому повторяется не чаще раза в полчаса. Скрапер перестал обещать в журнале переезд, которого не будет.
Счёт адресов для этого решения нарочно не вычитает остывающие: переезд происходит именно с адреса, который только что заблокировали, и счёт живых в этот момент всегда отвечал бы «остался один».
Теперь маршрут выбирается по здоровью и загрузке — тем же порядком, что у китайских и корейской площадок. Каждый запрос через адрес занимает слот физической машины и отчитывается о результате: 403, 429 и редирект на капчу читаются как «площадка ругается на этот адрес», обрыв — как транспортный сбой. Слот берётся на запрос, а не на весь сбор: листинг живёт минутами, и удержание слота означало бы, что один сбор выкупает треть ёмкости машины, ничего с ней не делая между страницами.
Прямой канал остался первой ступенью. Адрес нужен как запасной путь при ограничении по скорости, а не вместо прямого хода: с адреса сервера идут ещё фотографии, Telegram и спецификации китайской площадки, и разгружать его важнее, чем гонять через прокси то, что и так проходит.
Побочная находка: в админке вообще не было секций для этих двух площадок — их строки не отображались. Купленный российский адрес было бы не видно, и не понять, почему он «не работает». Секции добавлены, обе площадки есть во всех формах.
Система сама нащупывает безопасный темп для каждого адреса, но стартовала от чисел, посчитанных из времени запроса 7,4 секунды. Замер даёт 2,5–4,0. Занижённый старт не «безопаснее»: темп растёт на 10 % за полсотни успехов подряд, то есть от 24 до 72 адрес разгоняется часами — и всё это время отдаёт треть того, что может.
| Площадка | Было | Стало | Откуда |
|---|---|---|---|
| Китайская первая | 24 | 72 | 3 места × 60 с ÷ 2,5 с |
| Китайская вторая | 24 | 50 | 3 × 60 ÷ 3,6 |
| Корейская | 40 | 45 | 3 × 60 ÷ 4,0 |
| Немецкая | 12 | 40 | оценка: не парсилась с 20.08 |
Именно ложные срабатывания и были исходной болезнью: у трёх адресов накопилось по 2846 «сбоев» против 15 успехов. Механизм починен — метрика сторожит возврат.
Событие считается ложным, когда адрес выведен из работы для одной площадки, а другая площадка по тому же адресу ответила в ту же минуту. Судим с двух сторон: порядок наблюдений внутри минуты произволен (проверки идут пачкой), поэтому на выводе смотрим назад, а на успешной проверке — вперёд, на уже записанные выводы. Один вывод считается ложным ровно один раз.
Горячий путь не подорожал: боевые успехи только ставят отметку, читают и судят лишь редкие выводы и минутные проверки. Доля выведена в админку рядом со списком адресов — зелёная ниже одного процента, красная выше.
Список адресов переписан. Сверху — таблица физических машин: одна строка на адрес с отметками площадок вместо трёх одинаковых строк. Единица учёта в коде давно адрес, а не строка таблицы; список наконец показывает ту же единицу — четыре машины читались как двенадцать прокси.
| ID | Требование | Статус | Когда |
|---|---|---|---|
| Э4.1 | Лимиты считаются от числа живых адресов | закрыто | 02.09 |
| Э4.2 | Корейская площадка под ограничителем | закрыто | 02.09 |
| Э4.3 | Один счётчик на физическую машину | закрыто | 02.09 |
| Э4.4 | Пер-площадочные таймаут и кулдаун проверки | закрыто | 02.09 |
| Э4.4м | Метрика ложных выводов | закрыто | 03.09 |
| Э4.5 | Переезд только при двух и более адресах | закрыто | 03.09 |
| Э4.6 | Российские площадки через маршруты | закрыто | 03.09 |
| Э4.7 | Стартовые темпы из замера | закрыто | 03.09 |
| Э4.8 | Групповое добавление адреса в админке | закрыто | 03.09 |
| Э4.9 | Фотографии идут напрямую, мимо прокси | инвариант | не трогали |
Первый проход — по правкам этого дня. Второй — по всему эпику, включая сделанное накануне, и по соседним модулям. Все находки починены и закрыты проверками. Три из них поймал не глаз, а честно упавший чужой тест — поэтому ниже отдельно сказано, что тесты в этой области тоже пришлось чинить.
| Что нашлось | Чем это грозило |
|---|---|
| Слот адреса брался другим потолком | Единственное место в системе, читавшее не ту настройку. Сегодня обе равны трём, но их две, и первое же поднятие одной дало бы на одном счётчике держателей с разными пределами. Ровно эту ошибку ревью уже ловило вчера в другом месте. |
| Ответы 5xx и 407 считались успехом | 502 и 503 отдаёт сам прокси, 407 значит «пароль не принят». Мы растили бы темп ровно тому адресу, который перестал работать. |
| Заглушка с кодом 200 не доезжала до реестра | Главная. У drom страница защиты приходит с обычным кодом 200 и коротким телом. Записывалось как успех — значит сгоревший адрес никогда бы не ушёл в конец очереди, и требование «система заметит смерть адреса» не выполнялось. |
| Учёт прямого канала — мусор | Записи, которые не читает никто, ценой трёх обращений к Redis на каждый запрос пути, который раньше туда вообще не ходил. |
| Метрика обнулялась в полночь | Приёмка «доля за сутки» считалась по календарному дню: в 00:05 один ложный вывод из трёх проверок дал бы 33 % — красную карточку на пустом месте. Окно стало скользящим, плюс порог «мало данных». |
| Метрика могла унести основной учёт | Побочная запись стояла внутри общей транзакции: сбой в ней откатил бы и учёт самого запроса. |
| Порядок маршрутов считался дважды | Лишняя работа и две строки в журнале с разным первым адресом — читать журнал стало бы труднее, чем выбирать маршрут. |
| Строки без площадки пропадали из админки | Два вида одной таблицы показывали разное: в сводке по машинам строка есть, в секциях — нет. |
| Панель ёмкости завышала потолок втрое | Показывала «когда площадка работает одна». В залпе из трёх администратор увидел бы девять и не понял, почему в кампании три. |
| Обещанный откат требовал правки файла | Спецификация назвала пороги настройками — «откат одной переменной». Ни одна из них не была проброшена в конфигурацию: откат означал бы ту же выкатку. Проброшены. |
| Что нашлось | Чем это грозило |
|---|---|
| Пароли прокси лежали в именах ключей и в логах | Самая серьёзная. Один модуль эту опасность знал и обходил, соседний — клал полный адрес с логином и паролем прямо в имя ключа хранилища, а шесть мест печатали его в журнал, который уезжает в сборщик логов. Правило в проекте давно записано — про него просто не знали. Теперь пароль не попадает ни туда, ни туда. |
| Проверка живости без площадки выводила адрес «для всех» | Слабый сигнал проверки проваливался в жёсткий общий запрет — ту самую связку площадок, от которой весь эпик и уходит. |
| Два разных ответа на вопрос «сколько у нас адресов» | Решение о переезде и решение о паузе читали РАЗНЫЕ списки, один ещё и с минутной задержкой. По одному сигналу они могли ответить противоположно. Свели к одному источнику. |
| Строка журнала роняла обработку машины | Моя же правка про маскировку пароля брала функцию из модуля, который в проверках подменяется — и обработка падала на строке лога. Машина терялась. Взяли из модуля, который никто не подменяет. |
| Ёмкость делилась и на площадки, стоящие на паузе | Площадка на паузе не делает ни одного запроса, но занимала долю адресов: при паузе одной из трёх оставшиеся получали по трети вместо половины — ровно когда им нужнее всего. |
| Три обращения к хранилищу там, где хватает одного | Проверка здоровья спрашивает три вида запрета по отдельности, а зовётся на каждый адрес при каждом выборе: на девяти адресах — двадцать семь обращений на один запрос. |
| Имена: функция-константа и приватное имя как публичный API | Мелочи, но обе против записанных правил проекта; вторая — функция, которую зовут из двух площадок и четырёх проверок, всё это время притворялась внутренней. |
Отдельно — сами проверки. Одна падала на функции, которой в коде нет и не было: месяцами не проверяла ничего. Другая закрепляла поведение, намеренно изменённое накануне, — код поправили, оракул забыли. Ещё две собирали имя ключа хранилища вручную, то есть проверяли устройство, а не поведение, и молча переставали что-либо проверять при его смене. И в одиннадцати тестах жила скопированная заглушка хранилища, умеющая ровно один ключ вместо нескольких: такая либо роняет проверку, либо — хуже — тихо пропускает её. Всё это починено: иначе постоянно красные проверки прячут настоящие поломки.
Сверка с базой: прогон тридцати четырёх оракулов, задевающих изменённые модули, до и после — три улучшения, ни одной регрессии.
Раньше эти вещи проверить было нельзя: ограничитель работает на механизме хранилища, которого в тестовой заглушке нет. Теперь проверены на боевом сервере, под одновременной работой шести площадок.
| Проверка | Результат |
|---|---|
| Ограничитель действительно ограничивает | Три обращения к адресу разрешены, четвёртое и пятое — нет. Освобождение возвращает место. Под нагрузкой шести площадок замеры каждые шесть секунд: больше трёх ни разу. |
| Потолок растёт от нового адреса без перезапуска | С девяти до двенадцати. Проверено вставкой строки в отменяемой операции — боевая таблица не тронута. Это и есть доказательство, что покупка превратится в пропускную способность. |
| Лимиты сходятся с числом мест | Три адреса дают девять мест; когда работают три площадки — по три каждой, ровно девять. Раньше каждая независимо считала, что ей можно двенадцать-шестнадцать. |
| Китайская площадка перестала жечь адреса | Главный результат. Проверка занимала ровно восемь секунд — то есть упиралась в таймаут; теперь около секунды. Счётчик подряд идущих сбоев был 1616, 1650 и 1656 — стал ноль. Доля успеха выросла с 1,4 % примерно до 60 %, постоянные отключения адресов прекратились. |
| Пароли ушли из хранилища | До выкатки там лежал ключ с логином и паролем прокси открытым текстом. После — ни одного. |
| Соседние площадки не страдают | Пока китайская площадка держит адрес в отключении, корейская по тому же адресу набирает 38 успехов подряд. Раньше отключение было общим. |
Счётчик ошибочных отключений показывает 4 % при норме 1 % — и это правда, а не поломка. Все случаи — от китайской площадки: она отвергает наши адреса тогда, когда корейская и вторая китайская по ним спокойно работают. Вывод для покупки: этой площадке нужны другие адреса, а не ещё три таких же.
Локально зелены 50 групп проверок — 174 утверждения, по одной группе на каждую найденную ошибку. Но счётчики одновременности работают на серверных скриптах Redis, а в тестовой заглушке их нет: запрос слота всегда «пропускает». Проверки подтверждают правильность подключения — какой ключ, какой счёт, какой предел. Что счёт действительно ограничивает, видно только на боевом Redis.
| Проверить на бою | Как | Признак нормы |
|---|---|---|
| Счётчик действительно ограничивает | ключи слотов адреса под нагрузкой кампании | не больше трёх держателей на адрес |
| Ложных выводов нет | карточка в админке | меньше 1 % от проверок |
| Темпы не занижены | события роста и среза темпа за сутки | средний темп не ниже стартового, без всплесков блокировок |
| Ротация честная | события админки «единственный маршрут» | при одном адресе — пауза, при двух — переезд |
| Российские площадки через адрес | поле маршрута в журнале за сутки | ≥ 90 % запросов не с адреса сервера |
| Лимиты сходятся с числом мест | панель ёмкости в админке | сумма лимитов не превышает адреса × 3 |
Выложено вручную, четыре изменения. Первый час: 226 карточек по пяти площадкам, аварий нет, сайт отвечает за 0,08 с. Точка отката записана. Осталось досмотреть сутки — в первую очередь счётчик ошибочных отключений и то, как система сама поднимает темп.
Это не про скорость, а про отказоустойчивость: у немецкой площадки появляется куда переезжать, а фотографии, Telegram и российские площадки перестают зависеть от одного адреса сервера. После покупки — завести строки российским площадкам (теперь для них есть и секции, и групповая форма).
Брать по два за раз, наблюдая за выводом адресов из работы. Групповое добавление и стартовые темпы уже готовы — новые адреса заводятся одной формой и выходят на измеренный темп сразу, а не за часы.
Прогнать одну кампанию немецкой площадки (её темп сейчас — оценка), разобрать стоимость обращения к Avito и понаблюдать, как система сама поднимает темп адреса. После этого решение по третьему немецкому адресу и по устройствам становится обоснованным, а не оценочным.
Отдельная программа: наблюдаемость, жизнь рабочих процессов, вынос сети из обработки, разгрузка диска. Она поднимает долю времени, когда адрес реально занят, с 0,22 почти до 0,9 — и тогда те же площадки потребуют вдвое больше адресов. Покупать под неё нужно в тот же заход, что и выкатывать её.
Адрес 79.172.218.165 отключён с августа как неотвечающий и, вероятно, продолжает оплачиваться. Починить у провайдера или заменить — это четверть ёмкости трёх площадок, которая сейчас не работает. Кнопка «включить обратно» теперь есть и возвращает все строки адреса разом; само решение — ваше.
Разрешение на выкатку. Код лежит в рабочем дереве незакоммиченным. Ничего не выкачено и не тронуто на бою.