mirror of
https://github.com/Vateron-Media/XC_VM.git
synced 2026-10-01 12:02:06 +02:00
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).
126 lines
11 KiB
Markdown
126 lines
11 KiB
Markdown
# Диагностика серверов (`server:diagnose`)
|
||
|
||
Панель помечает proxy/LB-ноду как **офлайн** исключительно по устаревшему heartbeat (`enabled` + `status = 1` + свежий `last_check_ago`), но никогда не объясняет, *почему* нода перестала отчитываться. Команда `server:diagnose` отвечает именно на этот вопрос.
|
||
|
||
```bash
|
||
/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
|
||
|
||
```bash
|
||
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 — локальная самодиагностика НА ноде
|
||
|
||
```bash
|
||
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):
|
||
|
||
```text
|
||
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-инструменты](ru-ru/guides/cli-tools.md), [Обновление сервера](ru-ru/administration/server-update.md).
|