Перейти к содержанию

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

Панель помечает прокси-узел/LB-узел не в сети исключительно из-за устаревшего сердцебиения (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 и (на узле кластера) запросы своего агента GET /v1/status. Он никогда ничего не перезапускает и не перенастраивает.

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


Два режима

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

Режим A — дистанционный датчик от ОСНОВНОГО

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

Проверяет целевой узел снаружи и считывает его состояние на панели управления:

Проверять О чем это вам говорит
Включено / Статус / Сердцебиение Как панель в данный момент видит узел (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 — локальная самодиагностика НА узле

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

Запустите это на самом безмолвном узле LB/proxy — причины обычно находятся там. Аргумент не требуется; узел идентифицирует себя по config.ini. Проверки:

  1. Мой собственный ряд панелей — включено/статус/сердцебиение в том виде, в каком их видит основной пользователь.
  2. Могу ли я добраться до ГЛАВНОГО — Подключение к базе данных (неявно подтвержденное), ICMP и TCP к широковещательному порту главного сервера.
  3. Отключил ли я главный брандмауэр? — сканирует цепочку iptables INPUT этого узла на наличие DROP IP-адреса главного узла, а также файла-маркера блокировки потока. Это классическая причина "узел отключился без причины": защита от наводнений автоматически отключает общедоступные IP-адреса, и обратные вызовы главного сервера перестают поступать.
  4. Сервис / nginx — systemctl is-active xc_vm и локальная проверка TCP на собственном широковещательном порту узла.
  5. Демон-сторожевой пес — фактический регистратор сердцебиений: демон watchdog обновляет last_check_ago каждые несколько секунд. Когда его соединение с MySQL-сервером прерывается, он выполняет ожидает возврата базы данных (повторяя попытку каждые 5 секунд) и немедленно возобновляет сердцебиение. Вместо этого были запущены более старые сборки, что приводило к появлению все узлы переходят в автономный режим в один и тот же момент при любом перезапуске / сбое MySQL на главном сервере, пока cron:servers не восстановило их.
  6. Няня крон — три дополнительных проверки, потому что мертвый сторожевой пес остается мертвым только тогда, когда цепь няни разорвана.:
  7. присутствует ли cron:servers в xc_vm кронтаб пользователя (если отсутствует, восстановите с помощью rm -f /home/xc_vm/tmp/crontab и перезапустите службу);
  8. активна ли система служба cron (нет cron → crontab никогда не запускается);
  9. является предыдущим cron:servers экземпляром висел на своем замке cron — зависший экземпляр блокирует каждый последующий запуск на срок до 30 минут (acquireCronLock истекший тайм-аут), что в точности соответствует тому, как один сбой в работе базы данных удерживает узел в автономном режиме в течение получаса. Команда выводит удерживающий PID и команду завершения.
  10. Перекос часов — time_offset против панели.
  11. OPENSSL_EXTRA ОТКРЫВАЕТ — содержит ли этот узел значение main, как в режиме A.
  12. Кластерный 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 as cluster.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 доступ к таблице

Смотрите также: Инструменты интерфейса командной строки, Обновление сервера.