Границы материала

В статье я разбираю, как связываю доступность магазина с состоянием PHP-FPM, базы данных, Redis и фоновых заданий. Пороги, интервалы, пути и состав метрик подбираю под конкретный магазин и проверяю до включения оповещений.

Официальная документация проверена 2026-09-03. Примеры рассчитаны на современный WordPress, WooCommerce с Store API, Action Scheduler, PHP-FPM, MySQL либо MariaDB, Redis и Zabbix current (7.4 на дату проверки), но не являются непосредственно импортируемым production-шаблоном. Перед применением я сверяю версии, доступные команды, права, схему хранения и фактическую архитектуру.

Введение

  • Когда главная страница магазина отдаёт 200, я ещё не считаю WordPress и WooCommerce здоровыми. Покупатель может не открыть каталог, карточка — не получить цену, корзина — потерять сессию, checkout — зависнуть до создания заказа, а фоновые задачи — копить просрочку. Поэтому я начинаю не с количества метрик, а с пути пользователя и причинной цепочки: внешний DNS и TLS → HTTP и веб-сервер → PHP-FPM → WordPress/WooCommerce; база и Redis — зависимости приложения, WP-Cron и Action Scheduler — отдельная ветка фоновых заданий.
  • Для каждого слоя я держу один и тот же цикл: решение → сигналы → проверка → rollback. Это дисциплинирует изменения. Синтетическая проверка отвечает, способен ли наш контролируемый клиент пройти безопасный маршрут сейчас. Реальная бизнес-метрика отвечает, что происходило с настоящими сессиями, оплатами и заказами. Первое нельзя выдавать за второе, а второе нельзя собирать так, чтобы раскрывать персональные данные или создавать заказ.
  • Дальше я подробно показываю порядок настройки, ключи метрик и примеры выражений. Их нельзя импортировать вслепую как готовый production YAML/XML: сначала я подтверждаю версии компонентов, допустимую частоту опроса, точки доступа и нормальную нагрузку конкретного магазина.
Я разделяю внешние проверки DNS, TLS и HTTP, прикладной слой WordPress/WooCommerce и локальные сигналы FPM, базы, Redis и очереди.
В моей архитектуре внешний probe доказывает пользовательский результат, а локальные метрики объясняют причину.
Я выстраиваю четыре уровня сигналов и подавляю зависимые симптомы, сохраняя независимую тревогу о сроке TLS.
Я собираю связанные показатели одним master item, разбираю dependent items и оставляю оператору корневое событие.
  • 1. Начинаю с границы сервиса и карты отказов

    • Решение. Я описываю магазин как набор наблюдаемых контрактов. Внешний контракт — домен разрешается, цепочка сертификата валидна, редиректы ведут на канонический HTTPS, страницы отвечают вовремя и содержат устойчивый маркер. Прикладной контракт — REST index доступен согласно политике сайта, каталог отдаёт продукты, корзина сохраняет состояние одной синтетической сессии, checkout отображается без отправки формы. Внутренний контракт — у FPM есть свободная ёмкость, база отвечает на лёгкий read-only запрос, Redis не вытесняет ключи неожиданно, планировщики не накапливают просроченную работу.
    • Сигналы я делю на четыре уровня. Уровень L0 — свежесть самого сбора: `nodata()`, unsupported item, ошибка preprocessing. L1 — транспорт: DNS, TCP, TLS, HTTP status, redirect chain. L2 — приложение: content marker, REST/Store API, PHP-FPM, DB, Redis. L3 — предметный результат: реальный поток checkout и заказов, возраст и состояние очереди, ошибки платёжных интеграций из уже существующей observability. Эта иерархия нужна не для красоты: если L1 упал, десять событий L2 обычно лишь каскад.
    • Проверка. Перед созданием триггеров я рисую причинный граф и для каждого события записываю независимый read-only тест. Rollback. Если новый probe меняет сессию, вызывает заметную нагрузку, возвращает персональные данные или нестабилен между версиями, я отключаю item, сохраняю обезличенный ответ для разбора и возвращаюсь к более узкому контракту.

    Source ids

    К разделу: 3 Trigger dependencies

  • 2. Пользовательский путь: до checkout, но без заказа

    • Решение. В web scenario или Browser item я прохожу главную, каталог, заранее выбранную опубликованную карточку, корзину и страницу checkout. Для простого HTTP-сценария каждая ступень — GET с проверкой ожидаемого status, времени и стабильного маркера. Для корзины нужен отдельный контролируемый сеанс: Store API использует cookie-based customer session, а изменяющие корзину endpoint требуют nonce/token механизма. Такой сценарий я запускаю только для выделенного дешёвого тестового товара, на отдельной синтетической cookie jar и с явным удалением товара из корзины в конце. Он не нажимает Place order, не вызывает `POST /checkout`, не резервирует склад и не обращается к боевому платёжному шлюзу.
    • Безопасный минимум можно проверить без записи: `curl --fail-with-body --silent --show-error --location --max-redirs 5 --connect-timeout 3 --max-time 10 --proto '=https' --tlsv1.2 'https://SHOP.EXAMPLE/' -o /dev/null`; затем те же GET для `/shop/`, разрешённой карточки и `/checkout/`. Placeholder `SHOP.EXAMPLE` обязателен к замене. Для контроля origin после миграции использую `curl --resolve 'SHOP.EXAMPLE:443:203.0.113.10' 'https://SHOP.EXAMPLE/'`: URL сохраняет правильный Host и SNI, а тестовый IP заменяется на фактический. Опция `-k` запрещена, потому что она маскирует TLS-проблему.
    • Сигналы: результат DNS с двух независимых резолверов; срок и имя в сертификате; число и адреса редиректов; HTTP status; TTFB и полное время; размер ответа; обязательный маркер страницы; отсутствие известных шаблонов maintenance/error. На карточке я проверяю не конкретную цену, которая меняется, а устойчивый элемент товара. На checkout — форму/блок и отсутствие серверной ошибки, но не создаю заказ.
    • Проверка. Один и тот же маршрут запускаю из внешнего Zabbix proxy и при необходимости из внутренней точки. Сравниваю внешний результат с origin через `--resolve`, чтобы отделить DNS/CDN/WAF от приложения. Частоту выбираю с учётом кэша и стоимости динамических страниц; checkout не опрашиваю каждую секунду. Rollback — отключить сценарий и удалить только его синтетическую сессию. Если магазин не допускает изменение корзины, оставляю GET-путь и использую одобренный staging/canary для stateful шага.
    • Реальные бизнес-метрики веду отдельно: количество начатых checkout, созданных заказов, распределение итоговых статусов, ошибки оплаты и время переходов между статусами — только из уже согласованного аналитического или серверного контура, агрегированно и без customer/order payload. Ноль реальных заказов не равен аварии без календаря продаж и бизнес-контекста; успешная синтетика не доказывает, что реальная оплата проходит.

    Source ids

    К разделу: WooCommerce Store API | WooCommerce developer docs

  • 3. WordPress: Site Health, REST API и WP-Cron

    • Решение. Для WordPress я беру три независимых признака. Первый — публичный REST discovery `/wp-json/`, если он разрешён политикой сайта. Второй — узкие Site Health REST tests, например loopback/HTTPS, через отдельную аутентифицированную учётную запись с capability `view_site_health_checks`. Третий — расписание cron локальным WP-CLI без принудительного запуска. Публичный REST может быть намеренно закрыт или изменён security-плагином; в таком случае 401/403 — ожидаемый контракт, а не универсальная авария.
    • Безопасная команда расписания: `sudo -u WP_OWNER -- wp --path=/srv/www/SHOP cron event list --fields=hook,next_run_gmt,next_run_relative,recurrence --format=json`. Здесь `WP_OWNER` и путь — placeholders, а правило sudo должно разрешать фиксированный wrapper без произвольных аргументов. Site Health вызываю HTTP agent по конкретным GET endpoints `/wp-json/wp-site-health/v1/tests/loopback-requests` и `/https-status`; Application Password хранится в secret/vault macro и не печатается. `cron event list` читает расписание; я не подменяю его `wp cron event run --all`, потому что последнее выполняет задачи и может создать нагрузку или изменить данные.
    • WP-Cron не является постоянно работающим daemon: WordPress проверяет очередь при загрузках страниц. Функция `spawn_cron()` инициирует неблокирующий HTTP request к `wp-cron.php`, применяет lock и не должна запускаться чаще ограничения lock. Поэтому я наблюдаю не только наличие событий, но и самое старое просроченное событие, возраст успешного выполнения известного безопасного hook (если приложение уже пишет такой сигнал), ошибки loopback/spawn и фактическую схему: page-load spawning либо системный scheduler при `DISABLE_WP_CRON`.
    • Проверка. Я сопоставляю `next_run_gmt`, системное время, ошибки Site Health loopback и журнал планировщика. Отсутствие трафика объясняет задержку штатного WP-Cron; при системном cron проверяю owner, рабочий каталог, PHP binary и расписание, но не запускаю все hooks для теста. Rollback изменений планировщика: вернуть прежний механизм и значение `DISABLE_WP_CRON`, восстановить прежнюю запись scheduler и убедиться, что одновременно не работают два владельца запуска.

    Source ids

    К разделу: Cron – Plugin Handbook | Developer.WordPress.org; spawn_cron() – Function | Developer.WordPress.org; wp cron event list – WP-CLI Command | Developer.WordPress.org; Authentication – REST API Handbook | Developer.WordPress.org; Wp Site Health Tests – REST API Handbook | Developer.WordPress.org; 4 Secret user macros

  • 4. WooCommerce API и очередь заказов

    • Решение. Публичный Store API применяю для read-only проверки каталога, например `GET /wp-json/wc/store/v1/products?per_page=1`; он предназначен для customer-facing product/cart/checkout и не требует API keys для публичного чтения. Изменяющие endpoints корзины работают в контексте клиентской сессии и требуют корректных tokens. Административный WooCommerce REST API отделяю полностью: consumer key/secret получает минимальные read-права, передаётся только по HTTPS и не попадает в URL, argv, item history или debug log.
    • Для authenticated проверки я предпочитаю HTTP agent с Zabbix secret/vault macros в полях credentials либо локальный wrapper, читающий root-owned credential file/secret store. Команда с `curl -u USER:SECRET` в расписании неприемлема: секрет виден в argv. Для разовой ручной проверки вне Zabbix безопаснее `curl --config /run/credentials/woocommerce-monitor.curl ...`, где файл доступен только сервисному пользователю; реальное имя и права определяются инфраструктурой.
    • Очередь WooCommerce обычно обслуживает Action Scheduler, но я не предполагаю одну таблицу и один набор колонок. Версия, data store и префикс БД различаются; прямой SQL по `wp_actionscheduler_actions` хрупок. Сначала проверяю доступные команды `wp action-scheduler --help` и использую официальный WP-CLI интерфейс там, где он установлен. Считаю pending, failed и overdue, причём overdue — это pending action с запланированным временем в прошлом по принятой политике, а не отдельный универсальный status. Дополнительно полезны возраст старейшей pending-задачи, свежесть последнего complete и группировка по hook/group с allow-list, чтобы не экспортировать аргументы действий.
    • Сигналы очереди требуют контекста. Один failed action — доказательство ошибки действия, но не обязательно недоступность checkout; растущий backlog и возраст старейшей due action важнее голого количества. Я связываю их с WP-Cron/runner, PHP-FPM, БД и журналом конкретного hook. Trigger не должен включать payload заказа или customer data.
    • Проверка — повторный read-only list/count через WP-CLI и сверка с экраном Scheduled Actions для уполномоченного администратора. Я не запускаю массово pending actions и не удаляю failed actions ради зелёного графика. Rollback collector — выключить wrapper/item и вернуть прежние права; очередь не модифицируется. Исполнение или очистка — отдельная change-процедура с владельцем WooCommerce.

    Source ids

    К разделу: WooCommerce Store API | WooCommerce developer docs; WooCommerce REST API | WooCommerce developer docs; WP CLI | Action Scheduler - Job Queue for WordPress; 4 Secret user macros

  • 5. PHP-FPM: status и ping с минимальной экспозицией

    • Решение. В каждом нужном pool включаю `pm.status_path` и при необходимости `ping.path`, но публикую их только через защищённый HTTP location web-сервера, доступный на loopback, либо через иной явно ограниченный HTTP proxy. Сам Unix socket PHP-FPM и `pm.status_listen` говорят по FastCGI, а не по HTTP: `curl` к ним напрямую не обращается. Никогда не выставляю full status наружу: он способен показать URI и параметры текущих запросов. Если основной pool забит, отдельный `pm.status_listen` может дать независимый FastCGI status listener; применимость сверяю с установленной версией PHP.
    • Master item забирает JSON status одним локальным запросом. Dependent items извлекают `accepted conn`, `listen queue`, `max listen queue`, `idle processes`, `active processes`, `total processes`, `max active processes`, `max children reached` и `slow requests`. Счётчики `max children reached` и `slow requests` накопительные: для интенсивности применяю change per second или delta с обработкой рестарта pool, а не тревожусь на вечное значение больше нуля.
    • Предварительное условие проверки — сначала настроить в nginx или Apache локальный HTTP listener, привязанный только к `127.0.0.1:<FPM_STATUS_HTTP_PORT>`, и location `/fpm-status`, который передаёт запрос по FastCGI в фактический `listen` нужного FPM pool. `<FPM_STATUS_HTTP_PORT>`, путь, FastCGI socket/host:port и параметры `SCRIPT_FILENAME`/`SCRIPT_NAME` — обязательные placeholders: их определяю по реальной конфигурации, проверяю allow-list и не считаю порт заранее существующим. После validation web-сервера и PHP-FPM проверка выглядит так: `curl --fail --silent --show-error --max-time 5 'http://127.0.0.1:8081/fpm-status?json'`, где `8081` — только пример значения `<FPM_STATUS_HTTP_PORT>`. Сначала подтверждаю HTTP status, JSON schema и отсутствие доступа не с loopback; `curl` не направляю в FastCGI socket. Ping доказывает ответ FPM, но не работоспособность WordPress. Rollback: удалить локальный HTTP include/location и вернуть прежнюю конфигурацию pool после config test и контролируемого reload; если validation не проходит, конфигурацию не применяю.

    Source ids

    К разделу: PHP: Status Page - Manual; PHP: Configuration - Manual

  • 6. MySQL/MariaDB: лёгкий read-only контроль

    • Решение. Отдельная monitoring account получает только необходимые права и доступ с локального host/socket. Connectivity проверяю коротким `SELECT 1`; состояние — узким набором status variables: Threads_connected, Threads_running, Connections, Aborted_connects, Max_used_connections и, если настроено, счётчиками slow queries. Пароль не передаю как `-pSECRET`: клиент читает защищённый `--defaults-extra-file` или credential store.
    • Копируемый безопасный пример: `mysql --defaults-extra-file=/run/credentials/db-monitor.cnf --connect-timeout=3 --batch --skip-column-names -e 'SELECT 1'`. Это лёгкий read-only запрос; путь примерный, файл должен иметь минимальные права. Для replication, только если она реально есть, наблюдаю receiver/applier, last error и lag-показатель с оговоркой о его семантике. В MySQL Performance Schema replication tables удобнее для программного чтения и multithreaded workers; MariaDB имеет отличия, поэтому запрос выбираю по продукту и версии.
    • Сигналы интерпретирую вместе: высокая доля Threads_running относительно проверенной ёмкости, рост aborted connections, исчерпание connection budget, рост slow-query counter и replication errors. Для connection budget master `db.status` должен вернуть числовые `Threads_connected` и `max_connections`. Из них создаю dependent item `db.connection_utilization` типа Numeric (float), единицы `%`: preprocessing проверяет оба поля, отклоняет отсутствующие или нечисловые значения, при `max_connections<=0` делает item unsupported с явной ошибкой, а иначе возвращает `100*Threads_connected/max_connections`. Альтернатива — calculated item по реальным item paths, например `100*last(//db.threads_connected)/last(//db.max_connections)`, но отдельное правило должно не допустить расчёт при неположительном знаменателе. Ошибку сбора или знаменателя не заменяю нулём: её контролирует отдельный nodata/unsupported trigger. `{$DB.CONN.PCT}` задаю в тех же процентных единицах, например `80` означает 80%, а `{$DB.WINDOW}` — временной placeholder вроде `5m`, выбранный по baseline. Полный PROCESSLIST и тексты slow log не отправляю в Zabbix: там могут быть SQL literals и персональные данные. Проверка — тот же read-only запрос локально, error log и ограниченная Performance Schema выборка. Rollback — отозвать monitoring grant и удалить credential file после отключения items; никаких FLUSH, ANALYZE или тяжёлых full-table probes мониторинг не выполняет.

    Source ids

    К разделу: MySQL :: MySQL 8.4 Reference Manual :: 7.1.10 Server Status Variables; MySQL :: MySQL 8.4 Reference Manual :: 29.12.11 Performance Schema Replication Tables; 15 Dependent item; 14 Calculated item

  • 7. Redis: доступность, память и качество object cache

    • Решение. Redis опрашивает локальный agent/wrapper по Unix socket или защищённому TCP. `PING` подтверждает способность обработать команду, `INFO` отдаёт группы статистики. Не публикую Redis в Интернет. При TCP учитываю ACL с отдельным read-only пользователем, AUTH, TLS и сетевое ограничение; даже secret macro не компенсирует открытый порт.
    • Собираю `used_memory`, `maxmemory`, `evicted_keys`, `keyspace_hits`, `keyspace_misses`, `blocked_clients`, `connected_clients`, `rejected_connections`, uptime и роль. Hit ratio рассчитываю как hits/(hits+misses) только при ненулевом знаменателе и оцениваю по окну/delta: накопительный lifetime ratio скрывает свежую деградацию. Evictions также превращаю в скорость и связываю с `maxmemory`/policy. Если `maxmemory=0`, процент заполнения к нему не вычисляю.
    • Безопасная форма для ACL без секрета в argv: `REDISCLI_AUTH` тоже может утечь через окружение процесса, поэтому для постоянного сбора я предпочитаю локальный защищённый config/agent plugin или Unix socket с файловыми правами. Иллюстративно без аутентификационных данных: `redis-cli -s /run/redis/redis.sock --no-auth-warning PING` и `redis-cli -s /run/redis/redis.sock --no-auth-warning INFO memory`. Проверка — PING, узкие INFO sections и WordPress object-cache diagnostics, если они уже доступны. Rollback — отключить collector и удалить только созданного monitoring ACL user/правило после проверки отсутствия потребителей; данные Redis не очищать.

    Source ids

    К разделу: INFO | Docs; PING | Docs; ACL | Docs; 4 Secret user macros

  • 8. Как я собираю это в Zabbix

    • Решение. На каждую подсистему создаю один master item с компактным JSON и dependent items с JSONPath. Историю сырого master обычно не храню либо держу очень коротко; числовые dependent items получают разумную history, а trends — только там, где долгий агрегат полезен. Dependent items наследуют момент и частоту master item. JSONPath сначала тестирую на обезличенном образце ответа и задаю явную обработку ошибок, чтобы изменение схемы стало отдельным событием, а не нулём.
    • LLD использую только для изменяемого множества: FPM pools, сайты multisite или Action Scheduler groups из allow-list. Пять фиксированных ступеней customer journey не нуждаются в discovery. Макросы задают URL, proxy, intervals и пороги; чувствительные значения — Secret text или Vault. Я помню, что секретный macro скрывает отображение, но Zabbix всё равно подставляет значение, поэтому не допускаю его попадания в item value, error text или script output.
    • Теги `service=storefront|wordpress|php-fpm|db|redis|scheduler`, `scope=external|origin|local`, `signal=availability|latency|capacity|backlog|freshness` делают маршрутизацию и корреляцию явными. Value maps применяю к ограниченным состояниям (`up/down/unknown`, role), но не маскирую ими сырые ошибки. Частоту и timeout развожу: внешний homepage чаще, динамический checkout реже, локальные status — умеренно; timeout меньше интервала и меньше периода подавления. Универсальные числа ниже — стартовая иллюстрация, не SLA.

    Матрица элементов

    KeyTypeIntervalPreprocessingUnitsNote

    store.journey.step[home]

    Web/Browser dependent

    {$JOURNEY.INTERVAL} (например 1m)

    JSONPath $.steps.home.status/latency/content

    bool, ms

    GET, no write

    store.journey.step[checkout]

    Dependent

    master (например 5m)

    JSONPath $.steps.checkout.*

    bool, ms

    не отправлять order

    wp.site_health

    Zabbix agent wrapper master

    {$WP.HEALTH.INTERVAL}

    JSON validation

    JSON

    history off/short

    wp.cron.oldest_overdue

    Dependent

    WP master

    JSONPath + timestamp delta

    s

    read-only list

    wc.store.products

    HTTP agent

    {$WC.API.INTERVAL}

    HTTP status + JSONPath

    bool

    public GET

    wc.as.pending

    Dependent

    {$AS.INTERVAL}

    JSONPath $.pending

    actions

    schema/version checked

    wc.as.oldest_due_age

    Dependent

    AS master

    JSONPath $.oldest_due_age

    s

    preferred over count alone

    php.fpm.get[{#POOL}]

    Agent master prototype

    {$FPM.INTERVAL}

    JSON validation

    JSON

    local endpoint

    php.fpm.listen_queue[{#POOL}]

    Dependent prototype

    FPM master

    JSONPath $['listen queue']

    requests

    LLD only for real pools

    db.status

    Agent/DB monitor master

    {$DB.INTERVAL}

    JSON validation

    JSON

    least privilege

    db.threads_running

    Dependent

    DB master

    JSONPath $.Threads_running

    threads

    baseline threshold

    db.connection_utilization

    Dependent (or Calculated)

    DB master

    100*Threads_connected/max_connections; reject missing/non-numeric; unsupported if max_connections<=0

    %

    Numeric (float); {$DB.CONN.PCT} is percent; errors are not zero

    redis.info

    Agent/plugin master

    {$REDIS.INTERVAL}

    text-to-JSON wrapper

    JSON

    local/protected

    redis.evictions.rate

    Dependent

    Redis master

    JSONPath $.evicted_keys; change per second

    evictions/s

    handle restart

    redis.hit_ratio.window

    Calculated

    {$REDIS.INTERVAL}

    delta hits/(delta hits+delta misses)

    %

    guard zero denominator

    Source ids

    К разделу: 15 Dependent item; 4 JSONPath functionality; Low-level discovery; 4 Secret user macros; History and trends; 14 Calculated item

  • 9. Матрица событий и подавление каскадов

    • Я назначаю severity по влиянию и срочности конкретного магазина. Ниже `Warning/High/Disaster` — не универсальная шкала, а проектная заготовка. Каждое событие содержит operational data: какую независимую проверку выполнить, где искать владельца и какой сигнал должен восстановиться.

    Матрица триггеров

    EventExpression exampleSeverityDepends onVerification

    Нет свежих данных master item

    nodata(/TEMPLATE/key,{$COLLECTOR.NODATA})=1

    Warning

    agent/proxy unavailable

    проверить last error, wrapper и schema

    Публичный HTTPS недоступен

    max(/TEMPLATE/store.journey.step[home],#3)=0

    High

    DNS failure; proxy/network failure

    внешний curl и origin через --resolve

    Checkout не открывается

    max(/TEMPLATE/store.journey.step[checkout],#2)=0

    High

    homepage/HTTP root failure

    GET checkout без submit, затем PHP/DB

    FPM listen queue устойчиво растёт

    min(/TEMPLATE/php.fpm.listen_queue[pool],{$FPM.WINDOW})>{$FPM.QUEUE.MAX}

    High

    FPM down; collector unavailable

    локальный status и web latency

    Action Scheduler просрочен

    min(/TEMPLATE/wc.as.oldest_due_age,{$AS.WINDOW})>{$AS.OVERDUE.MAX}

    Warning/High

    WP-Cron runner failure; DB down

    read-only WP-CLI list и hook logs

    DB connection budget близок к пределу

    min(/TEMPLATE/db.connection_utilization,{$DB.WINDOW})>{$DB.CONN.PCT}

    High

    DB collector unavailable; db.connection_utilization unsupported

    проверить Threads_connected, max_connections>0, вычисленный процент и единицы macro

    Redis evictions появились

    min(/TEMPLATE/redis.evictions.rate,{$REDIS.WINDOW})>{$REDIS.EVICT.RATE}

    Warning

    Redis unavailable

    INFO memory/stats, maxmemory policy

    TLS скоро истекает

    last(/TEMPLATE/tls.days_left)<{$TLS.DAYS.WARN}

    Warning

    нет зависимости от FPM/DB

    внешний сертификат с правильным SNI

    Source ids

    К разделу: 2 Trigger expression; 3 Trigger dependencies; 14 Calculated item; 15 Dependent item

  • 10. Диагностика: иду снаружи внутрь

    • Если магазин недоступен, я не начинаю с рестарта PHP. Порядок такой: (1) свежесть Zabbix proxy/agent и время; (2) DNS у независимых резолверов; (3) TCP/TLS, SNI и redirect chain; (4) HTTP status, latency и content; (5) тот же origin через `--resolve`; (6) web server/upstream; (7) FPM ping/status и очередь; (8) лёгкий DB query и connections/threads; (9) Redis; (10) WordPress Site Health/REST; (11) WP-Cron и Action Scheduler; (12) уже существующие агрегированные order/payment сигналы.
    • Типовые развилки: внешний probe падает, а origin здоров — смотрю DNS/CDN/WAF; origin даёт 502 и FPM ping не отвечает — проверяю pool/socket; FPM отвечает, но latency и Threads_running растут — исследую БД без тяжёлого запроса; страницы быстрые, но очередь стареет — проверяю runner, cron ownership и конкретные failed hooks. Так событие ведёт к проверке, а не к автоматическому опасному действию.
    • Rollback диагностики прост: все probes по умолчанию read-only, интервалы можно увеличить, collector отключить. Я не лечу мониторингом: автоматический restart, очистка Redis, запуск всех cron events или retry всех заказных действий требуют отдельной одобренной процедуры.

    Source ids

    К разделу: PHP: Status Page - Manual; MySQL :: MySQL 8.4 Reference Manual :: 7.1.10 Server Status Variables; INFO | Docs; Wp Site Health Tests – REST API Handbook | Developer.WordPress.org; wp cron event list – WP-CLI Command | Developer.WordPress.org; WP CLI | Action Scheduler - Job Queue for WordPress; 3 Trigger dependencies

  • 11. Поэтапная миграция старого WordPress/PHP/MySQL

    • Решение начинается с inventory: версии ОС, web server, PHP и extensions, WordPress/WooCommerce/plugins/theme, table engine/charset/collation, DB size, uploads, object/page cache, session/cart storage, cron, Action Scheduler runner, SMTP/payment/webhooks, certificates, vhost redirects, filesystem ownership и внешние интеграции. Затем составляю compatibility matrix и отдельно отмечаю всё, что не подтверждено производителем.
    • До окна работ делаю backup файлов и БД и обязательно restore rehearsal на изолированном адресе. Проверяю checksum/число файлов, импорт БД, URL/config, PHP startup, wp-admin, REST, каталог, корзину и checkout без заказа. Новый сервер получает TLS/vhost, но тестируется через `--resolve`. Кэши и sessions планирую явно: object cache нельзя просто считать переносимым источником истины; ключевой namespace/salt и политика очистки должны исключить столкновение старого и нового origin.
    • Первичный files/db sync выполняю заранее. На финальном окне включаю согласованный maintenance или read-only режим на уровне приложения, который действительно блокирует записи, а не только рисует заглушку. Останавливаю старого владельца cron/workers/Action Scheduler, делаю final delta файлов и консистентный DB dump/replication cutover по выбранной технологии, восстанавливаю на новом сервере, проверяю owner/permissions и только затем запускаю единственного владельца cron и workers на новом.
    • Перед DNS switch gate включает: успешный restore, совместимость, TLS/vhost, локальный journey, DB/Redis, cron ownership, очередь без неожиданного роста, логи без новых критичных ошибок и готовый rollback. Низкий TTL помогает только если был снижен заблаговременно и резолверы его соблюдают; он не гарантирует мгновенное переключение. После go меняю DNS и фиксирую точное время/значения.

    Source ids

    К разделу: Cron – Plugin Handbook | Developer.WordPress.org; WP CLI | Action Scheduler - Job Queue for WordPress; PHP: Configuration - Manual; MySQL :: MySQL 8.4 Reference Manual :: 7.1.10 Server Status Variables; INFO | Docs

  • 12. Контроль после DNS и защита от split-brain

    • Сигналы после переключения беру из нескольких перспектив. Проверяю authoritative answer и независимые recursive resolvers, старый и новый origin через `--resolve` с тем же HTTPS hostname/SNI, публичные HTTP/TLS/redirect/content, весь безопасный user journey, FPM, DB, Redis, logs и очереди. Публичный DNS может вести разных клиентов на разные origin, поэтому на обоих узлах отслеживаю access и, главное, возможность записи.
    • Заказы или другие записи для проверки создаются только через заранее одобренный canary с тестовым платёжным режимом и процедурой отмены либо не создаются вовсе. По умолчанию я использую существующую observability реальных операций, не читаю персональные payload и не оформляю тестовую покупку. Если старый и новый сервер одновременно принимают writes, объявляю split-brain: останавливаю rollout, определяю authoritative writer и не пытаюсь склеить базы импровизированными SQL-командами.
    • Go/no-go оцениваю не по одному зелёному HTTP 200. Go — резолвинг и TLS ожидаемы, origin/journey стабилен в согласованном окне, writer единственный, очереди исполняются, ошибки не растут. No-go — потеря записей, два writer, несовместимость checkout/payment, неконсистентные sessions/cache, необъяснимый backlog или невозможность доказать состояние.

    Source ids

    К разделу: WooCommerce Store API | WooCommerce developer docs; PHP: Status Page - Manual; MySQL :: MySQL 8.4 Reference Manual :: 7.1.10 Server Status Variables; INFO | Docs; wp cron event list – WP-CLI Command | Developer.WordPress.org; WP CLI | Action Scheduler - Job Queue for WordPress

  • 13. Rollback, который я готовлю до переключения

    • Rollback — не фраза «вернуть DNS». Я заранее фиксирую точку невозврата и способ сохранить записи после cutover. Если новых подтверждённых writes ещё нет, можно остановить writer/workers на новом, вернуть writer ownership старому и обратить DNS. Если writes уже появились, простой откат DNS способен потерять заказы: сначала нужна согласованная reverse delta/reconciliation процедура или решение остаться на новом узле. Это отдельный go/no-go владельцев данных.
    • При откате учитываю реальный TTL и кэши резолверов: часть клиентов продолжит ходить на новый IP. Оба origin должны корректно обслуживать TLS, а только один — принимать writes. Sessions/cart и Redis нельзя бездумно копировать или `FLUSHALL`: я либо использую заранее спроектированное общее/переносимое хранилище, либо принимаю документированную потерю синтетических сессий и защищаю реальные данные выбранной схемой.
    • Я сохраняю evidence: timestamps DNS, ответы резолверов, обезличенные probe results, версии, deploy/config diff, DB positions/checksums, queue counts и логи вокруг окна. Старый сервер не уничтожаю, не переиспользую и не очищаю, пока не завершены период наблюдения, reconciliation, backup verification и формальная приёмка. После rollback повторяю DNS/TLS/journey, проверяю единственного writer, cron ownership, workers, DB/cache и очередь.

    Source ids

    К разделу: Cron – Plugin Handbook | Developer.WordPress.org; WP CLI | Action Scheduler - Job Queue for WordPress; MySQL :: MySQL 8.4 Reference Manual :: 7.1.10 Server Status Variables; INFO | Docs

  • Вывод

    • Хороший мониторинг WooCommerce для меня — не коллекция графиков, а короткая доказуемая цепочка. Внешний путь показывает влияние на покупателя; FPM, база и Redis объясняют ресурсную причину; Site Health, REST, WP-Cron и Action Scheduler показывают прикладную работу; зависимости триггеров удерживают каскад под контролем. Любое изменение проходит решение → сигналы → проверку → rollback.
    • Если вам не удаётся самостоятельно настроить или стабилизировать мониторинг WordPress и WooCommerce в Zabbix либо вы готовите перенос магазина, обращайтесь ко мне. Я помогу разобраться с причиной сбоев, а вместе с командой IT Fresh мы настроим контроль сайта, PHP-FPM, базы данных, Redis и фоновых очередей под вашу инфраструктуру. Напишите мне в [Telegram @ITfresh_Boss](https://t.me/ITfresh_Boss), позвоните [+7 903 729-62-41](tel:+79037296241) или оставьте заявку на [ITfresh.ru](https://itfresh.ru/).

    Source ids

    К разделу: Wp Site Health Tests – REST API Handbook | Developer.WordPress.org; WooCommerce Store API | WooCommerce developer docs; PHP: Status Page - Manual; MySQL :: MySQL 8.4 Reference Manual :: 7.1.10 Server Status Variables; INFO | Docs; 3 Trigger dependencies

Я переношу магазин через проверяемый gate, удерживаю одного владельца записи и сохраняю обратимый маршрут до завершения приёмки.
Я готовлю rollback до DNS switch и не уничтожаю старый сервер, пока не доказана консистентность записей, очередей и кэшей.

Источники и границы применимости

  1. Cron – Plugin Handbook | Developer.WordPress.orgWP-Cron обрабатывает запланированные задачи WordPress; WP-Cron проверяет очередь при загрузках страниц и не работает постоянно как системный cron; При отсутствии загрузок страниц выполнение может задерживаться
  2. spawn_cron() – Function | Developer.WordPress.orgspawn_cron() посылает HTTP request для запуска cron без блокирования загрузки страницы; Функция использует cron lock и проверяет готовые jobs; Фактическое spawning зависит от констант и состояния lock
  3. wp cron event list – WP-CLI Command | Developer.WordPress.orgКоманда перечисляет scheduled cron events; Поддерживаются поля hook, next_run_gmt, recurrence и JSON output; Команда list пригодна для read-only inventory расписания
  4. Authentication – REST API Handbook | Developer.WordPress.orgWordPress REST API поддерживает cookie authentication с nonce; Application Passwords предназначены для API-доступа по HTTPS; Запрос требует capability соответствующего пользователя
  5. Wp Site Health Tests – REST API Handbook | Developer.WordPress.orgWordPress предоставляет REST endpoints для отдельных Site Health tests; Ответ включает test, status, badge, description и actions; Доступны, среди прочего, loopback-requests и https-status tests; endpoint требует соответствующей capability
  6. WooCommerce Store API | WooCommerce developer docsStore API предоставляет customer-facing endpoints для products, cart и checkout; Публичное чтение Store API не требует API keys; Customer sessions cookie-based; Изменяющие endpoints требуют nonce-token и способны изменять состояние корзины; Namespace — /wp-json/wc/store/v1
  7. WooCommerce REST API | WooCommerce developer docsWooCommerce REST API предназначен для административного доступа к данным магазина; Credentials следует передавать только по защищённому каналу и с минимальными правами; REST API отличается по назначению от публичного Store API
  8. WP CLI | Action Scheduler - Job Queue for WordPressAction Scheduler предоставляет WP-CLI команды для управления и просмотра очереди; CLI доступность и параметры зависят от установленной версии; Для мониторинга можно предпочесть официальный CLI прямому чтению внутренних таблиц
  9. PHP: Status Page - ManualPHP-FPM status page показывает pool, process и queue metrics; Поддерживаются JSON/OpenMetrics и другие форматы; Страница может раскрывать сведения о запросах и должна быть ограничена внутренними/доверенными адресами; Независимый status listener помогает получать статус при занятости основного pool
  10. PHP: Configuration - Manualpm.status_path и ping.path задаются в pool configuration; pm.max_children ограничивает число child processes; listen и listen.allowed_clients определяют endpoint и допустимых FastCGI clients
  11. MySQL :: MySQL 8.4 Reference Manual :: 7.1.10 Server Status VariablesMySQL exposes Threads_connected, Threads_running, Connections, Aborted_connects, Max_used_connections и Slow_queries; Многие status variables являются накопительными и требуют интерпретации как delta/rate; Набор и семантика сверяются с версией сервера
  12. MySQL :: MySQL 8.4 Reference Manual :: 29.12.11 Performance Schema Replication TablesPerformance Schema предоставляет таблицы состояния receiver, applier, coordinator и workers; Табличная форма лучше подходит для программного чтения, чем SHOW REPLICA STATUS; Multithreaded replication errors доступны per-worker
  13. INFO | DocsINFO возвращает секции server, clients, memory, stats, replication и keyspace; Поля включают used_memory, maxmemory, evicted_keys, keyspace_hits, keyspace_misses и blocked_clients; Ответ и доступные поля могут зависеть от версии
  14. PING | DocsPING проверяет способность сервера обслужить команду; PING не доказывает корректность WordPress object cache или пользовательского пути
  15. ACL | DocsRedis ACL ограничивает команды, keys/channels и аутентификацию пользователей; Monitoring user следует ограничивать необходимыми командами; ACL является частью защиты, но не заменяет TLS и сетевое ограничение
  16. 15 Dependent itemОдин master item может собирать набор метрик; Dependent items заполняются из master value через preprocessing; Dependent items не имеют отдельного update interval
  17. 4 JSONPath functionalityJSONPath используется в preprocessing для извлечения значений из JSON; Поддерживаются dot и bracket notation и функции; Выражения следует тестировать на фактической схеме ответа
  18. Low-level discoveryLLD создаёт items/triggers/graphs из discovery rows и prototypes; LLD macros могут извлекаться из JSONPath; Discovery оправдано для изменяемых множеств объектов
  19. 3 Trigger dependenciesTrigger dependency подавляет уведомления/действия зависимого symptom event при проблеме master trigger; Dependencies помогают уменьшать каскад событий; Причинный граф не должен создавать циклы
  20. 4 Secret user macrosZabbix поддерживает Secret text и Vault secret macros; Скрытие macro не предотвращает раскрытие через item/script output; Secret macros нельзя использовать в trigger expressions
  21. 2 Trigger expressionHistory functions reference an item key in /host/key form; The evaluation period is supplied to a history function such as min(); An unsupported referenced item can make trigger evaluation unknown
  22. 14 Calculated itemCalculated items derive stored values from existing item values; Calculated item formulas share syntax with trigger expressions and reference actual item keys; Numeric float results require Numeric (float) to avoid truncation

Евгений Семёнов · IT Fresh

Если самостоятельно не сможете — обращайтесь ко мне

Если вам не удаётся самостоятельно настроить или стабилизировать мониторинг WordPress и WooCommerce в Zabbix либо вы готовите перенос магазина, обращайтесь ко мне. Я помогу разобраться с причиной сбоев, а вместе с командой IT Fresh мы настроим контроль сайта, PHP-FPM, базы данных, Redis и фоновых очередей под вашу инфраструктуру. Напишите мне в Telegram @ITfresh_Boss, позвоните +7 903 729-62-41 или оставьте заявку на ITfresh.ru.

@ITfresh_Boss+7 903 729-62-41https://itfresh.ru/