Несколько серверов для глубокого обхода (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ограничивают число обработчиков ещё раз — берётся меньшее. Первыми обслуживаются обходы, у которых занято меньше обработчиков от допустимого.
Что нужно для нескольких серверов
- PostgreSQL (см.
docs/POSTGRES.md) или MySQL/MariaDB (см.docs/MYSQL.md): все узлы подключаются к одной базе. SQLite годится только для одного сервера (или для узлов на общем диске — как в тестах). - Одинаковый
config.php/переменные окружения на всех узлах, кромеSEOMASTER_NODE_ID— у каждого узла своё имя (msk1,spb1; буквы, цифры, дефис, до 16 знаков). Без него узел работает как единственный. - Расписание на каждом узле одинаковое:
* * * * * php /var/www/seomaster/bin/deepcrawl.php. Лидера выбирать вручную не нужно. - (По желанию) Redis для координации:
SEOMASTER_COORD=redis,SEOMASTER_REDIS_URL=redis://:пароль@хост:6379/0(для шифрованияrediss://). Расширение php-redis не нужно — клиент встроен. Если Redis недоступен, узлы автоматически работают через базу и раз в 30 секунд пробуют вернуться; причина видна в «Администрирование → Кластер». - Часы. С Redis решения принимает сервер Redis по своему времени. Без Redis (координация через базу) часы узлов должны быть синхронизированы по NTP (расхождение в секунды ничего не ломает, но сдвигает паузы и аренды).
Настройки
| Переменная | По умолчанию | Смысл |
|---|---|---|
SEOMASTER_NODE_ID | — | имя узла |
SEOMASTER_COORD | db | db или redis |
SEOMASTER_REDIS_URL | — | адрес Redis |
SEOMASTER_REDIS_PREFIX | seomaster: | префикс ключей (если Redis общий с другими программами) |
SEOMASTER_DEEP_HOST_INFLIGHT | 24 | одновременных запросов к одному сайту со всех узлов |
SEOMASTER_DEEP_WORKERS | 1 | процессов на узле (один запуск bin/deepcrawl.php порождает их сам) |
SEOMASTER_DEEP_RUN_WORKERS | как DEEP_WORKERS | обработчиков на один обход по всем узлам (узлов × процессов) |
SEOMASTER_DEEP_RECLAIM | 120 | через сколько секунд адреса упавшего обработчика возвращаются в очередь |
Пример для трёх узлов по 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— многоузловой тест.