Диагностика сервера (server:diagnose)¶
Панель помечает прокси-узел/LB-узел не в сети исключительно из-за устаревшего сердцебиения (enabled + status = 1 + недавнее last_check_ago), которое никогда не сообщает вам, почему узел перестал сообщать. Команда server:diagnose отвечает на этот вопрос.
Это команда доступен только для чтения: она выполняет только проверки ping/curl/fsockopen, SELECT запросы, sudo -n iptables -nL и (на узле кластера) запросы своего агента GET /v1/status. Он никогда ничего не перезапускает и не перенастраивает.
Реализовано с помощью src/Cli/Commands/ServerDiagnoseCommand.php. Команда поставляется в сборках оба MAIN и LB — локальный режим - вот и весь смысл ее размещения на узле.
Два режима¶
Режим автоматически выбирается из того, в котором выполняется команда (server_id в config.ini → is_main в таблице servers).:
Режим A — дистанционный датчик от ОСНОВНОГО¶
Проверяет целевой узел снаружи и считывает его состояние на панели управления:
| Проверять | О чем это вам говорит |
|---|---|
| Включено / Статус / Сердцебиение | Как панель в данный момент видит узел (status = 4 означает сбой установки/подготовки) |
| Пинг по протоколу ICMP | Жив ли вообще носитель |
TCP к http_broadcast_port |
Доступен ли nginx, или порт удален |
HTTP GET /api |
Действительно ли PHP отвечает за nginx |
| Смещение часов | time_offset против панели (перекос > 30 с может привести к переключению узла в режим онлайн/оффлайн) |
| Очередь сигналов | Неиспользованные строки в signals для этого узла (задержка > 120 секунд = цикл обратного вызова узла застрял) |
| OPENSSL_EXTRA ОТКРЫВАЕТ | Содержит ли узел main значение OPENSSL_EXTRA (см. ниже). unknown (node not updated) / unknown (main not updated): эта сторона запускает сборку, которая еще не публикует ее. Не проверено наличие прокси-серверов |
Комбинации датчиков соответствуют причинам:
- Порт ICMP + не закрыт — узел выключен, разделен сетью или полностью защищен брандмауэром.
- ICMP отвечает, но порт удален — классический вариант: собственные iptables узла заблокировали основной IP-адрес (RootSignals наводняют/блокируют ложные срабатывания) или nginx/служба не работает. Запустите локальный режим на узле, чтобы выяснить точную причину.
- Порт открыт, но
/apiмолчит — nginx запущен, PHP - нет: проверьте php-fpm на узле. /apiотвечает, но сердцебиение затихает — сторожевой демон узла (программа записи сердцебиений) не запущен или он не может выполнить запись в базу данных панели. Запустите локальный режим на узле.
Для узла, зарегистрированного в cluster API, из его строки cluster_nodes следует раздел Кластерный API:
| Проверять | О чем это вам говорит |
|---|---|
| Узел кластера | Состояние и работоспособность (ok / suspect / offline, или enrolling / quarantined / revoked), режим и потоки |
| Агент услышал | Когда MAIN в последний раз общался с агентом узла, против cluster_offline_after_sec |
| Знак | Новейшая эпоха и ее завершение |
| Окно забора | Как долго узел работает без MAIN: истечение срока действия токена + lb_partition_tolerance_h, затем lb_fence_drain_min и включено ли lb_lease_fence |
| Смещение часов | Собственные часы узла отличаются от основных, начиная с его сердцебиений (агент до xc_vm_fanout 0.14.0 сообщает о 0). Его агент исправляет свои собственные запросы, но его PHP, crons и журналы используют эти часы. По истечении 30 секунд появляется предупреждение, и страница узлов кластера и список серверов помечают узел; по истечении 300 секунд он отображается как "деградированный (часы)". Ни то, ни другое не защищает его |
| Очередь команд | Команды для узла, который еще не активирован, и возраст самого старшего из них (более 120 секунд: узел не опрашивается) |
| Курсоры событий | Применяются последние номера событий P0 и P1 |
При включенном потоке ТЕЛЕМЕТРИИ узла его агент поддерживает его в рабочем состоянии: устаревшее сердцебиение и time_offset не оцениваются.
Режим B — локальная самодиагностика НА узле¶
Запустите это на самом безмолвном узле LB/proxy — причины обычно находятся там. Аргумент не требуется; узел идентифицирует себя по config.ini. Проверки:
- Мой собственный ряд панелей — включено/статус/сердцебиение в том виде, в каком их видит основной пользователь.
- Могу ли я добраться до ГЛАВНОГО — Подключение к базе данных (неявно подтвержденное), ICMP и TCP к широковещательному порту главного сервера.
- Отключил ли я главный брандмауэр? — сканирует цепочку
iptables INPUTэтого узла на наличиеDROPIP-адреса главного узла, а также файла-маркера блокировки потока. Это классическая причина "узел отключился без причины": защита от наводнений автоматически отключает общедоступные IP-адреса, и обратные вызовы главного сервера перестают поступать. - Сервис / nginx —
systemctl is-active xc_vmи локальная проверка TCP на собственном широковещательном порту узла. - Демон-сторожевой пес — фактический регистратор сердцебиений: демон
watchdogобновляетlast_check_agoкаждые несколько секунд. Когда его соединение с MySQL-сервером прерывается, он выполняет ожидает возврата базы данных (повторяя попытку каждые 5 секунд) и немедленно возобновляет сердцебиение. Вместо этого были запущены более старые сборки, что приводило к появлению все узлы переходят в автономный режим в один и тот же момент при любом перезапуске / сбое MySQL на главном сервере, покаcron:serversне восстановило их. - Няня крон — три дополнительных проверки, потому что мертвый сторожевой пес остается мертвым только тогда, когда цепь няни разорвана.:
- присутствует ли
cron:serversвxc_vmкронтаб пользователя (если отсутствует, восстановите с помощьюrm -f /home/xc_vm/tmp/crontabи перезапустите службу); - активна ли система служба cron (нет cron → crontab никогда не запускается);
- является предыдущим
cron:serversэкземпляром висел на своем замке cron — зависший экземпляр блокирует каждый последующий запуск на срок до 30 минут (acquireCronLockистекший тайм-аут), что в точности соответствует тому, как один сбой в работе базы данных удерживает узел в автономном режиме в течение получаса. Команда выводит удерживающий PID и команду завершения. - Перекос часов —
time_offsetпротив панели. - OPENSSL_EXTRA ОТКРЫВАЕТ — содержит ли этот узел значение main, как в режиме A.
- Кластерный API (узел с агентом) — собственный отчет агента,
GET /v1/statusна его сокете (config/cluster/agent.sock): отвечает ли агент; состояние, режим и потоки последнего ответа MAIN; отказывается ли MAIN от сеанса из-за отсутствия лицензии; последний импульс MAIN ответил; время работы этой машины совпадает с временем работы MAIN; окна токена и аренды (и почему в последней аренде было отказано, если таковая была); список невыполненных работ по каждому каналу событий (файлы, байты, самые старые, пакет в полете, курсор MAIN); и вердикт об аренде - PHP узла. действует на (serving,drainingилиfencedи почему).
При включенном потоке ТЕЛЕМЕТРИИ шаги 1 и 7 остаются на усмотрение агента. В режиме 2 узел не считывает данные из базы данных MAIN: он использует серверы из своей реплики, а когда он вообще не может их прочитать, отчет агента все равно выполняется.
Примечание: для проверки iptables требуется sudo без пароля (
sudo -n). Без этого проверка выдает сообщение оcannot check (need sudo iptables)вместо сбоя — запустите команду какrootдля получения полной картины.
Устранение несоответствия OPENSSL_EXTRA¶
OPENSSL_EXTRA (config/openssl_extra или встроенное значение по умолчанию, когда этот файл отсутствует) определяет токены потока, которые являются основными точками для перенаправлений, обслуживаемых LB (/auth, /vauth, /tsauth, /thauth, субтитры). Main и его LBs должны содержать одно и то же значение; LB, содержащий другой токен, отклоняет все эти токены, поэтому воспроизведение, перенаправленное с main, завершается неудачей. Текущий установщик присваивает новому main случайное значение, и LBs, добавленный с помощью server:install перед отправкой этого файла, запускается по умолчанию.
Каждый узел cron:servers публикует отпечаток своего значения (но не само значение) в servers.server_hardware, а проверка OPENSSL_EXTRA сравнивает значение узла с основным. Чтобы устранить несоответствие, запустите главный:
sudo /home/xc_vm/console.php server:sync-openssl-extra <server_id>
sudo /home/xc_vm/console.php server:sync-openssl-extra --all
- Команда помещает в очередь один корневой сигнал со значением main для каждого потокового сигнала, который сообщает о другом отпечатке пальца. Значение
cron:root_signalsв LB применяется в течение минуты: оно записываетconfig/openssl_extra(0600, принадлежитxc_vm), и php-fpm использует его при следующем запросе без перезапуска. До тех пор значение остается в таблицеsignals. - В течение 10 минут после этого LB по-прежнему принимает токены, которые он отчеканил со своим старым значением (сохраненным в
config/openssl_extra.prev), поэтому ссылки, которые он только что раздал, продолжают воспроизводиться. Токены устаревшего формата (secure_stream_tokensотключены) все еще могут быть отклонены в этом окне, примерно в 1 случае из 256. - LBS, которые уже синхронизированы, LBS, которые не публикуют отпечатки пальцев (еще не обновлены), и автономные LBS пропускаются.
--forceв любом случае они помещаются в очередь; автономный LB применяет сигнал, если он возвращается в течение дня (срок действия сигналов, поставленных в очередь, истекает через 24 часа). Прокси-серверы и основные никогда не отправляют это значение. - Когда в main есть нет
config/openssl_extra, он запускается по встроенному умолчанию, и отправлять нечего. У LB, который по-прежнему сообщает о несоответствии, есть собственный устаревшийconfig/openssl_extra: удалите его в этом LB (sudo rm -f /home/xc_vm/config/openssl_extra); изменение применяется при следующем запросе. - Команда ничего не отправляет, когда main публикует другой отпечаток, отличный от того, который содержит
config/openssl_extra: либоxc_vmне может прочитать этот файл, поэтому php-fpm main запускается по умолчанию (sudo chown xc_vm:xc_vm /home/xc_vm/config/openssl_extra && sudo chmod 600 /home/xc_vm/config/openssl_extra), либо файл изменился в течение последней минуты (дождитесьcron:servers). Он также ничего не отправляет, если основной сервер еще не опубликовал отпечаток пальца.
Проверьте результат с помощью server:diagnose <server_id> через минуту или две, после следующего запуска LB cron:servers.
Отчет об узлах STARTING (пулы API кластера)¶
На ГЛАВНОМ сервере cluster API (/cluster/v1/) работает в двух собственных пулах PHP-FPM, cluster_ctl и cluster_ingest, расположенных рядом с пулами панели. До тех пор, пока оба не ответят, API отвечает 503 STARTING на каждый вызов, кроме health, и агенты узлов отключаются и сообщают о том, что MAIN поврежден. После загрузки, перезагрузки или обновления это длится до тех пор, пока status не запустит миграцию и не обнаружит, что оба пула отвечают, обычно это занимает несколько секунд.
Когда это продлится дольше, проверьте на ГЛАВНОМ:
sudo /home/xc_vm/console.php status # ends with "Cluster API pools are ready." or "... not answering yet."
sudo -u xc_vm /home/xc_vm/console.php cluster:pools # starts or resizes the pools, as xc_vm; exit code 0 once both answer
ls -l /home/xc_vm/tmp/cluster_ready # present while the API serves
ls -l /home/xc_vm/bin/php/etc/cluster/ # cluster_ctl.conf, cluster_ingest.conf
ps -eo pid,user,args | grep 'master process (/home/xc_vm/bin/php/etc/cluster/'
- Два мастера запускаются как
xc_vmи называют свою конфигурациюphp-fpm: master process (/home/xc_vm/bin/php/etc/cluster/cluster_ctl.conf). Имя мастера панелиbin/php/etc/<n>.conf. cron:serversпроверяет пулы каждую минуту: запускает пул, у которого нет главного сервера, и изменяет размеры обоих при добавлении или удалении серверов. Изменение размера перезагружает пул и не прерывает работу API.cluster:poolsотказывается запускаться от имени пользователя root. Запустите его от имениxc_vm, как указано выше.- Пул, который не запускается: запустите
sudo -u xc_vm /home/xc_vm/bin/php/sbin/php-fpm -t -y /home/xc_vm/bin/php/etc/cluster/cluster_ctl.conf, чтобы узнать причину.
Конфигурация nginx кластерного API¶
В ОСНОВНОМ, маршрут nginx для cluster API написан XC_VM, а не зафиксирован в nginx.conf:
Файл в /home/xc_vm/bin/nginx/conf/ |
Что в нем содержится |
|---|---|
cluster_locations.conf |
Маршрут /cluster/v1/, включенный главным веб-сервером. Он передается в пулы кластеров и позволяет выполнять каждые 100 запросов в секунду (пакеты по 400; выше этого nginx отвечает на 429) |
cluster.d/listen.conf |
Только если Порт кластерного API не является 0: это обычный HTTP-сервер на этом порту. Он обслуживает /cluster/v1/ и отвечает 404 на все остальные запросы |
cluster.d/old_port.conf |
В течение 7 дней после изменения порта LBs использует изменения (широковещательный порт HTTP, порт Cluster API или широковещательный порт HTTPS, в то время как LBs отправляются на HTTPS): старый порт продолжает обслуживать только /cluster/v1/, поэтому LB, пропустивший изменение, все равно находит ОСНОВНОЙ. Старый HTTPS-порт сохраняет HTTPS с сертификатом главного веб-сервера (ssl.conf). С помощью агента LB, который сообщает, какие адреса он использует, он может закрываться быстрее, как только каждый LB использует новый порт (см. ниже). |
status записывает эти файлы при каждой загрузке, а после обновления при смене порта они записываются сразу, и задание проверяет их на соответствие настройкам каждую минуту. Изменения сохраняются только по истечении nginx -t времени. Новый порт Cluster API также должен быть свободен, и nginx должен обслуживать его сразу после перезагрузки. В противном случае предыдущие файлы будут возвращены, а сохранение нового порта завершится ошибкой с указанием причины. Чтобы записать их снова и посмотреть, что скажет nginx, запустите на главном сервере.:
sudo -u xc_vm /home/xc_vm/console.php cluster:nginx # exit code 0 when the files are current
ls -l /home/xc_vm/bin/nginx/conf/cluster.d/
- Не редактируйте эти файлы: при следующей записи они будут заменены.
cluster:nginxотказывается запускаться от имени пользователя root. Запустите его от имениxc_vm, как указано выше.- Порт Cluster API, отличный от
0, должен быть открыт от LBs до MAIN в каждом брандмауэре между ними. - Первая запись удаляет
cluster_legacy.conf, который в предыдущих версиях использовался для старых портов;cluster.d/old_port.confзаменяет его. - Когда на главной странице сервера меняется значение IP-адрес сервера или Частный IP-адрес или когда XC_VM обновляет IP-адрес сервера через сетевой интерфейс, LBS получает новый адрес. Старый адрес остается в их списке на срок до 7 дней. Он продолжает работать только до тех пор, пока не достигнет ГЛАВНОГО. Установите Имя ГЛАВНОГО хоста в настройках кластера (DNS-имя), может ли IP-адрес ГЛАВНОГО сервера измениться.
- Когда Имя ГЛАВНОГО хоста изменяется или сбрасывается в настройках, LBs также сообщается, и старое имя остается в их списке на срок до 7 дней: только его HTTPS-адрес, пока LBs отправляются на HTTPS (Кластерный транспорт
https_preferredилиhttps_required), а его обычный -HTTP-адрес, за исключениемhttps_required. Изменение на Кластерный транспорт само по себе ничего не меняет. Каждое изменение записывается в таблицуcluster_auditкакcluster.endpoint_change. - Чтобы увидеть старые адреса и порты, которые все еще есть в LBs, и до каких пор, запустите
sudo -u xc_vm /home/xc_vm/console.php cluster:endpointна главном сервере. - When you give up an old host name or address (the domain is dropped, transferred or compromised, or the IP goes to someone else), remove it from the LBs' list at once:
sudo -u xc_vm /home/xc_vm/console.php cluster:endpoint drop old.example.com. Give a host name or address to remove all of its entries, or one entry exactly as listed. The LBs are told within a heartbeat, and the change is recorded ascluster.endpoint_dropped. Otherwise whoever holds the name or address next receives the LBs' requests. It cannot read them or answer in a way the LBs accept, but after each outage of the MAIN it can keep today's LB agents from reaching the MAIN for up to 10 minutes. - Старый порт может закрыться раньше, чем истечет 7 дней, как только каждый LB начнет использовать новый. Для этого нужен агент LB, который сообщает, какой список ОСНОВНЫХ адресов он использует, который будет выпущен в более поздней версии агента. С современными агентами каждый старый порт остается открытым в течение полных 7 дней. Как только LBs запустит такой агент:
- Каждый LB в режиме 1 или 2 (столбец Режим в Серверы → Узлы кластера) должен быть подключен к сети, должен сообщать о последнем списке MAIN и должен в последний раз подключаться к MAIN через другой порт. Проверка выполняется каждую минуту, поэтому порт может закрыться через минуту или две после внесения изменений.
- LB, который находится в автономном режиме или все еще регистрируется, задерживает закрытие до тех пор, пока он снова не подключится к сети, или пока его регистрация не завершится, или пока срок ее действия не истечет. То же самое происходит с регистрационным кодом, срок действия которого не истек, и, в течение 30 минут, с запросом, который ожидает подтверждения.
- LB, использующая более старый агент, сохраняет старый порт открытым в течение полных 7 дней.
- LB, который по-прежнему подключается к MAIN только на старом порту, сохраняет его открытым: откройте новый порт с этого LB на MAIN. LB в режиме 0 сохраняет открытым порт, на котором он в последний раз подключался к MAIN, пока он подключен к сети.
- Пока значение Кластерный транспорт равно
https_required, старый обычный HTTP-порт работает в течение полных 7 дней. LB использует его для восстановления, если HTTPS не работает и вы переключаетесь обратно наauto. - Каждое досрочное закрытие регистрируется в таблице
cluster_auditкакcluster.endpoint_released.
Коды вывода и выхода¶
При каждой проверке выводится одна выровненная строка [OK]/[WARN], за которой следует пронумерованная сводка Вероятная причина (причины) с указанием точной команды исправления там, где она существует (например, строка разблокировки iptables -D INPUT ... -j DROP).
| Код выхода | Значение |
|---|---|
0 |
Очевидная причина не обнаружена (или цель сама по себе является ОСНОВНОЙ — диагностировать нечего). |
1 |
Ошибка использования: отсутствует/неизвестно server_id |
2 |
Была найдена и напечатана одна или несколько вероятных причин |
Пример (локальный режим, самоблокирующийся основной):
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-адрес | sudo iptables -D INPUT -s <main_ip> -j DROP + удалить маркер block_<ip> (команда выводит точную строку) |
| Ни пинга, ни порта | Отключен хост / сетевой раздел / внешний брандмауэр | Проверьте консоль хостинга, маршруты, брандмауэр провайдера |
Порт открыт, /api отключен |
сбой php-fpm | Перезапустите службу xc_vm на узле |
/api отлично, сердцебиение замедлилось |
Сторожевой демон мертв (завершает работу при потере соединения с базой данных) | sudo -u xc_vm console.php watchdog на узле; проверьте разрешения базы данных (tools mysql на главном сервере) |
| All nodes drop at the same moment | Перезапуск/ сбой MySQL на главном сервере приводит к одновременному сбою сторожевого таймера каждого узла (фатально для сборок с предварительным исправлением; текущие сборки переждут это). | Проверяйте журнал ошибок main в MySQL примерно во время отключения; обновляйте узлы, чтобы сторожевой таймер переживал перебои в работе |
| Закрылки узлов онлайн/оффлайн | Перекос часов > 30 с (или повторяющиеся сбои в работе MySQL) | Синхронизируйте NTP на узле; проверьте стабильность MySQL на главном сервере. |
| Статус = 4 | Произошла ошибка установки/обеспечения | Повторный запуск server:install из основного |
| Воспроизведение, перенаправленное с основного, завершается сбоем на одном LB | OPENSSL_EXTRA несоответствие (проверка сообщает об этом) |
sudo /home/xc_vm/console.php server:sync-openssl-extra <server_id> на главной странице (см. выше) |
Каждый узел сообщает о STARTING |
Пулы кластерных API на главном сервере не отвечают | sudo -u xc_vm /home/xc_vm/console.php cluster:pools на главной странице (см. выше) |
| Сбой при сохранении нового порта Cluster API: nginx отказал в этом | nginx -t произошел сбой с новым портом (в сообщении указан nginx), или nginx не обслуживал порт после перезагрузки |
Исправьте имена nginx, проверьте, работает ли nginx, затем сохраните еще раз (см. выше). |
| Сбой при сохранении нового порта Cluster API: его прослушивает другая программа | Служба на ГЛАВНОМ сервере уже использует этот порт | Выберите другой порт или остановите эту службу (ее имя указано в ss -ltnp 'sport = :<port>'). |
cluster:nginx говорит nginx.conf predates the rendered cluster config |
При обновлении nginx.conf произошел сбой nginx -t, и предыдущее обновление было восстановлено |
Найдите причину сбоя nginx.conf в выпуске nginx -t (в журнале обновлений записан откат), исправьте это, затем обновите снова |
Связанные файлы¶
| Файл | Роль |
|---|---|
src/Cli/Commands/ServerDiagnoseCommand.php |
Диагностическая команда (в обоих режимах) |
src/Cli/Commands/WatchdogCommand.php |
Сторожевой демон — записывает сердцебиение (last_check_ago) |
src/Cli/CronJobs/ServersCronJob.php |
Няня крон — перезапускает мертвого сторожевого пса |
src/Cli/CronJobs/RootSignalsCronJob.php |
Применяет блоки iptables (источник ложных срабатываний) и сигнал восстановления OPENSSL_EXTRA |
src/Cli/Commands/ServerSyncOpensslExtraCommand.php |
server:sync-openssl-extra — ставит в очередь OPENSSL_EXTRA main для поиска несовпадающих LBS (только для MAIN). |
src/Core/Config/OpensslExtra.php |
OPENSSL_EXTRA отпечаток пальца, сигнал восстановления и 10-минутный запасной вариант |
src/Domain/Cluster/ClusterPool.php |
Пулы FPM кластерного API для основного и STARTING-маркера |
src/Cli/Commands/ClusterPoolsCommand.php |
cluster:pools — запускает или изменяет размер пулов на xc_vm (только ОСНОВНОЙ). |
src/Domain/Cluster/ClusterNginxConfig.php |
Конфигурация nginx cluster API на главной странице: маршрут, порт Cluster API и старые порты |
src/Cli/Commands/ClusterNginxCommand.php |
cluster:nginx — записывает эту конфигурацию как xc_vm, проверяет ее с помощью nginx -t и перезагружает nginx (только для MAIN) |
src/Domain/Cluster/ClusterEndpoint.php |
Старые порты и адреса MAIN сохраняются в списке LBs после внесения изменений, истечения срока их действия и досрочного закрытия |
src/Cli/Commands/ClusterEndpointCommand.php |
cluster:endpoint — выводит список этих старых портов и адресов или удаляет один из них (только ОСНОВНОЙ). |
src/Domain/Server/ServerRepository.php |
servers доступ к таблице |
Смотрите также: Инструменты интерфейса командной строки, Обновление сервера.