Files
XC_VM/docs/ru/administration/server-diagnostics.md
T
Divarion-D 8954721562 docs: sync server-diagnostics guide with the real heartbeat mechanics
The heartbeat is written by the watchdog daemon (which now waits out DB
outages), not by cron:servers; the babysitter section documents the
crontab/cron-service/hung-lock sub-checks, and the cheat-sheet covers
the 'all nodes drop at the same moment' scenario. cli-tools blurbs
updated to match (en/ru).
2026-07-10 13:42:09 +03:00

11 KiB
Raw Blame History

Диагностика серверов (server:diagnose)

Панель помечает proxy/LB-ноду как офлайн исключительно по устаревшему heartbeat (enabled + status = 1 + свежий last_check_ago), но никогда не объясняет, почему нода перестала отчитываться. Команда server:diagnose отвечает именно на этот вопрос.

/home/xc_vm/console.php server:diagnose [server_id]

Команда работает только на чтение: выполняет пробы ping/curl/fsockopen, SELECT-запросы и sudo -n iptables -nL. Ничего не перезапускает и не перенастраивает.

Реализована в src/Cli/Commands/ServerDiagnoseCommand.php. Команда входит и в MAIN, и в LB сборку — локальный режим и есть основная причина её наличия на ноде.


Два режима

Режим выбирается автоматически по месту запуска (server_id из config.ini → is_main в таблице servers):

Режим A — удалённая проверка с MAIN

sudo /home/xc_vm/console.php server:diagnose <server_id>

Проверяет целевую ноду снаружи и читает её состояние в панели:

Проверка Что показывает
Enabled / Status / Heartbeat Как панель сейчас видит ноду (status = 4 — упавшая установка/провижининг)
ICMP ping Жив ли хост вообще
TCP на http_broadcast_port Доступен ли nginx или порт дропается
HTTP GET /api Отвечает ли PHP за nginx
Clock offset time_offset относительно панели (расхождение > 30 с может «мигать» нодой онлайн/офлайн)
Signal queue Неразобранные строки в signals для этой ноды (бэклог > 120 с — цикл обработки сигналов на ноде завис)

Комбинации проб указывают на причину:

  • Нет ICMP + порт закрыт — нода выключена, сетевой разрыв или полностью закрыта файрволом.
  • ICMP отвечает, но порт дропается — классика: собственный iptables ноды заблокировал IP главного сервера (ложное срабатывание flood-защиты RootSignals), либо упал nginx/сервис. Для точной причины запустите локальный режим на самой ноде.
  • Порт открыт, но /api молчит — nginx работает, PHP нет: проверьте php-fpm на ноде.
  • /api отвечает, но heartbeat устарел — на ноде не работает демон watchdog (писатель heartbeat) либо он не может писать в БД панели. Запустите локальный режим на ноде.

Режим B — локальная самодиагностика НА ноде

sudo /home/xc_vm/console.php server:diagnose

Запускается на самой «молчащей» LB/proxy-ноде — причины обычно живут именно там. Аргумент не нужен: нода определяет себя по config.ini. Проверяет:

  1. Собственную строку в панели — enabled/status/heartbeat глазами main.
  2. Доступность MAIN — связь с БД (доказана самим запросом), ICMP и TCP до broadcast-порта main.
  3. Не заблокировала ли нода main? — ищет DROP c IP главного сервера в цепочке iptables INPUT этой ноды плюс файл-маркер flood-блокировки. Это классическая причина «нода замолчала без причины»: flood-защита молча дропает публичные IP, и коллбэки main перестают доходить.
  4. Сервис / nginx — systemctl is-active xc_vm и локальная TCP-проверка собственного broadcast-порта.
  5. Демон watchdog — настоящий писатель heartbeat: демон watchdog обновляет last_check_ago каждые несколько секунд. При обрыве MySQL-соединения с main он ждёт возвращения базы (повтор каждые 5 с) и сразу возобновляет heartbeat. Старые сборки вместо этого завершались — поэтому рестарт/сбой MySQL на main ронял все ноды одновременно, пока cron:servers их не поднимал.
  6. Крон-«нянька» — три подпроверки, потому что мёртвый watchdog остаётся мёртвым, только если сломана цепочка «няньки»:
    • есть ли cron:servers в crontab пользователя xc_vm (если нет — перегенерировать: rm -f /home/xc_vm/tmp/crontab и перезапустить сервис);
    • активен ли системный сервис cron (нет cron — crontab вообще не срабатывает);
    • не завис ли предыдущий экземпляр cron:servers на своём локе — зависший экземпляр блокирует все последующие запуски до 30 минут (stale-таймаут acquireCronLock); именно так один сбой БД держит ноду офлайн полчаса. Команда печатает PID держателя лока и команду kill.
  7. Расхождение часов — time_offset относительно панели.

Примечание: проверка iptables требует беспарольного sudo (sudo -n). Без него проверка выводит cannot check (need sudo iptables), а не падает — для полной картины запускайте команду от root.


Вывод и коды выхода

Каждая проверка печатает одну выровненную строку [OK]/[WARN], затем идёт нумерованная сводка Probable cause(s) с точной командой исправления, где она есть (например, строка разблокировки iptables -D INPUT ... -j DROP).

Код выхода Значение
0 Явная причина не найдена (или цель — сам MAIN, диагностировать нечего)
1 Ошибка использования: не указан/не найден server_id
2 Найдена и выведена одна или несколько вероятных причин

Пример (локальный режим, нода сама заблокировала main):

Self-diagnosis on node #3 — LB-Frankfurt (type 1)
----------------------------------------------------------------
[OK]   Enabled          yes
[OK]   Status           1 (online)
[WARN] Heartbeat        last check-in 641s ago (limit 180s)
[OK]   DB → main        reachable (this query ran)
[OK]   Ping main        reply (203.0.113.10)
[WARN] Main :8080       closed/timeout
[WARN] Main in iptables DROP present (+flood marker)
[OK]   Service xc_vm    active
[OK]   nginx :8080      listening
[OK]   watchdog daemon  running
[OK]   cron:servers     in xc_vm crontab
[OK]   Clock offset     2s vs panel
----------------------------------------------------------------
Probable cause(s):
  1. Heartbeat is stale (641s > 180s): the node stopped reporting — the checks below narrow down why.
  2. This node has DROPPED the main's IP 203.0.113.10 in its own iptables (flood/block false-positive). Unblock: `sudo iptables -D INPUT -s 203.0.113.10 -j DROP && sudo rm -f /home/xc_vm/tmp/flood/block_203.0.113.10`.

Шпаргалка — типичные причины

Симптом Вероятная причина Исправление
Пингуется, порт дропается iptables ноды заблокировал IP main sudo iptables -D INPUT -s <main_ip> -j DROP + удалить маркер block_<ip> (команда печатает точную строку)
Нет пинга и порта Хост выключен / сетевой разрыв / внешний файрвол Проверить консоль хостинга, маршруты, файрвол провайдера
Порт открыт, /api мёртв Упал php-fpm Перезапустить сервис xc_vm на ноде
/api в порядке, heartbeat устарел Демон watchdog мёртв (завершается при обрыве соединения с БД) sudo -u xc_vm console.php watchdog на ноде; проверить гранты БД (tools mysql на main)
Все ноды отвалились в один момент Рестарт/сбой MySQL на main ударил по watchdog всех нод разом (фатально для старых сборок; текущие пережидают сбой) Смотреть error log MySQL на main в момент падения; обновить ноды, чтобы watchdog переживал сбои
Нода «мигает» онлайн/офлайн Расхождение часов > 30 с (или повторяющиеся сбои MySQL) Синхронизировать NTP на ноде; проверить стабильность MySQL на main
Status = 4 Ошибка установки/провижининга Повторить server:install с main

Связанные файлы

Файл Роль
src/Cli/Commands/ServerDiagnoseCommand.php Команда диагностики (оба режима)
src/Cli/Commands/WatchdogCommand.php Демон watchdog — пишет heartbeat (last_check_ago)
src/Cli/CronJobs/ServersCronJob.php Крон-«нянька» — перезапускает умерший watchdog
src/Cli/CronJobs/RootSignalsCronJob.php Ставит блокировки iptables (источник ложных срабатываний)
src/Domain/Server/ServerRepository.php Доступ к таблице servers

См. также: CLI-инструменты, Обновление сервера.