▤ Руководства

Несколько серверов для глубокого обхода (Deep Crawl 3.1)

Содержание

Один обход можно вести сразу с нескольких серверов («узлов»). Очередь адресов лежит в общей базе данных, а узлы договариваются через координатор: общую базу или Redis. Гарантии вежливости к чужому сайту не зависят от числа узлов.

Что гарантируется

  • Общий предел запросов к сайту. Одновременно к одному сайту идёт не больше SEOMASTER_DEEP_HOST_INFLIGHT запросов (по умолчанию 24) — со всех обходов всех пользователей и всех узлов. Подготовка обхода (главная, robots.txt, sitemap) тоже идёт через этот предел.
  • Профиль обхода сохраняется. Число одновременных запросов обхода делится между его обработчиками на всех узлах; предел «запросов в секунду» (профиль «Бережный») общий для всех узлов; сайт, ответивший 429 или «подождите», замедляет обход целиком.
  • Страница не запрашивается дважды. Адреса занимаются заявками: в SQLite — условным UPDATE, в PostgreSQL — одним запросом FOR UPDATE SKIP LOCKED, узлы не ждут друг друга.
  • Падение узла не теряет работу. Адреса, занятые обработчиком, который не отчитался SEOMASTER_DEEP_RECLAIM секунд (по умолчанию 120), возвращаются в очередь и берутся другим узлом (страницы, которые были «в полёте» у упавшего узла, запрашиваются повторно — не больше предела сайта).
  • Один лидер. Расписание автообходов, закрытие зависших обходов и проверка JS выполняются только на узле-лидере (аренда на 90 секунд, при падении переходит к другому узлу).
  • Справедливость по тарифам. Лимиты тарифа deep_parallel (сколько обходов одного пользователя идут одновременно; остальные ждут) и deep_workers (сколько обработчиков на всех узлах ведут один обход) задаются в «Тарифах». Профиль обхода и SEOMASTER_DEEP_RUN_WORKERS ограничивают число обработчиков ещё раз — берётся меньшее. Первыми обслуживаются обходы, у которых занято меньше обработчиков от допустимого.

Что нужно для нескольких серверов

  1. PostgreSQL (см. docs/POSTGRES.md) или MySQL/MariaDB (см. docs/MYSQL.md): все узлы подключаются к одной базе. SQLite годится только для одного сервера (или для узлов на общем диске — как в тестах).
  2. Одинаковый config.php/переменные окружения на всех узлах, кроме SEOMASTER_NODE_ID — у каждого узла своё имя (msk1, spb1; буквы, цифры, дефис, до 16 знаков). Без него узел работает как единственный.
  3. Расписание на каждом узле одинаковое: * * * * * php /var/www/seomaster/bin/deepcrawl.php. Лидера выбирать вручную не нужно.
  4. (По желанию) Redis для координации: SEOMASTER_COORD=redis, SEOMASTER_REDIS_URL=redis://:пароль@хост:6379/0 (для шифрования rediss://). Расширение php-redis не нужно — клиент встроен. Если Redis недоступен, узлы автоматически работают через базу и раз в 30 секунд пробуют вернуться; причина видна в «Администрирование → Кластер».
  5. Часы. С Redis решения принимает сервер Redis по своему времени. Без Redis (координация через базу) часы узлов должны быть синхронизированы по NTP (расхождение в секунды ничего не ломает, но сдвигает паузы и аренды).

Настройки

ПеременнаяПо умолчаниюСмысл
SEOMASTER_NODE_ID—имя узла
SEOMASTER_COORDdbdb или redis
SEOMASTER_REDIS_URL—адрес Redis
SEOMASTER_REDIS_PREFIXseomaster:префикс ключей (если Redis общий с другими программами)
SEOMASTER_DEEP_HOST_INFLIGHT24одновременных запросов к одному сайту со всех узлов
SEOMASTER_DEEP_WORKERS1процессов на узле (один запуск bin/deepcrawl.php порождает их сам)
SEOMASTER_DEEP_RUN_WORKERSкак DEEP_WORKERSобработчиков на один обход по всем узлам (узлов × процессов)
SEOMASTER_DEEP_RECLAIM120через сколько секунд адреса упавшего обработчика возвращаются в очередь

Пример для трёх узлов по 4 процесса: SEOMASTER_DEEP_WORKERS=4, SEOMASTER_DEEP_RUN_WORKERS=12, SEOMASTER_DEEP_HOST_INFLIGHT=24.

Проверка и мониторинг

  • php bin/cluster.php check — проверяет базу и координацию (аренда, слоты, пауза) на временных ключах; запускайте после настройки Redis/PostgreSQL. Тот же отчёт — кнопка «Проверить координацию» на странице Администрирование → Кластер.
  • php bin/cluster.php status — способ координации, лидер, узлы, число активных обходов.
  • Страница «Кластер»: узлы и время последней отметки, лидер, очередь обходов с причиной ожидания, занятые слоты по сайтам, предупреждение, если Redis недоступен.

Soak-тест перед запуском в работу

php bin/cluster.php soak --nodes=3 --workers=2 --runs=3 --pages=240 --host-cap=8
php bin/cluster.php soak --nodes=3 --db=pg --coord=redis --redis=redis://127.0.0.1:6379/5 --kill=3 --pages=400 --latency=80

Тест поднимает подставной сайт на порту 8080 (разрешённый обходом), запускает несколько процессов-«узлов», несколько пользователей обходят один сайт, а сам сайт считает одновременные запросы. Проверяется: все обходы завершены, страницы просмотрены, ни одна не запрошена дважды, одновременных запросов не больше предела, после kill -9 узла остальные доделывают работу, нет ошибок базы. --db=pg берёт настройки из SEOMASTER_DB_* (временная схема удаляется после теста). Код возврата 0 — всё в порядке, 1 — нарушения (их список печатается).

Для проверки на своём железе увеличьте --pages, --nodes, --workers и --latency (задержка ответа сайта, мс). Тест не заменяет проверку на реальных серверах, но ловит нарушения вежливости и потерю заявок до запуска.

Как это устроено

  • Cluster\Coord — интерфейс: аренда (lease), пауза (gate), слоты (acquire/releaseSlots), отметки узлов (beat/nodes).
  • Cluster\DbCoord — таблицы cluster_lock, cluster_gate, cluster_slot, cluster_node; слоты считаются под блокировкой (BEGIN IMMEDIATE в SQLite, pg_advisory_xact_lock в PostgreSQL).
  • Cluster\RedisCoord — Lua-скрипты на стороне Redis (атомарно, по часам сервера), собственный клиент RESP (Cluster\Redis).
  • Cluster\Failover — Redis как основной, база как запасной.
  • Deep\Fair — выбор обходов для обработчика; Deep\Soak — многоузловой тест.