Короткий ответ
Не начинайте с «поставьте кэш-плагин». Для site.example пройдите слои по порядку: DNS (время резолва, кэш, неверный IP), TCP/TLS (handshake, сертификат, HTTP/2), TTFB (PHP-FPM/Apache генерация), SQL (locks, slow query), ассеты (вес, число запросов, без сжатия, чужие CDN). Сравнивайте curl --resolve на 10.0.20.40 и «как пользователь» через публичный DNS. Оперативные симптомы TTFB: сайт медленно отвечает. Таймауты: 504.
Зафиксируйте цифры до любых правок.
Фиксируйте цифры до правок: иначе не отличите регресс PHP от «у клиента плохая сеть».
Симптомы и как отличить
- «Долго, потом щёлк» — часто TTFB.
- «Страница пустая, потом рисуется» — ассеты/JS.
- «То быстро то нет» — очередь FPM, боты, lock SQL.
- Только с мобильного — сеть/TLS 1-RTT / DNS оператора.
Таблица решений — в конце диагностики, не в начале.
Возможные причины
- DNS: высокий TTL плюс далёкий резолвер, NXDOMAIN→поиск, CNAME-цепочка, SERVFAIL retry.
- TLS: полный handshake каждый раз без session, слабый CPU, неверный chain (клиент ретраит).
- TTFB: PHP без opcache, холодный WP,
max_childrenочередь, диск. - SQL: полный scan, missing index,
autocommitтранзакции. - Ассеты: 20 МБ героя, блокирующий JS, нет gzip/brotli, 100 запросов без HTTP/2.
- Боты: перегруз.
- 502/очередь: FPM, 502.
Диагностика
Плейсхолдеры: site.example, 10.0.20.40, /var/www/site.example.
1. DNS
dig +stats A site.example
dig +stats AAAA site.example
dig +trace site.example | tailСмотрите Query time. Сравните с dig @<NS_из_ответа>. Если A не 10.0.20.40 (при прямом origin) — сначала DNS.
curl -o /dev/null -s -w 'namelookup:%{time_namelookup}\n' https://site.example/
curl -o /dev/null -s -w 'namelookup:%{time_namelookup}\n' --resolve site.example:443:10.0.20.40 https://site.example/Второй обнуляет DNS. Разница — резолв.
2. TCP и TLS
curl -o /dev/null -s -w 'connect:%{time_connect} tls:%{time_appconnect}\n' --resolve site.example:443:10.0.20.40 https://site.example/
echo | openssl s_client -connect 10.0.20.40:443 -servername site.example -tls1_2 2>/dev/null | grep -E 'Protocol|Cipher'time_appconnect >> time_connect — CPU/крипто/прокси. Проверьте, нет ли лишнего hop NPM+nginx+apache.
HTTP/2:
curl -sI --http2 --resolve site.example:443:10.0.20.40 https://site.example/ | head3. TTFB HTML
curl -o /dev/null -s -w 'ttfb:%{time_starttransfer} total:%{time_total} size:%{size_download}\n' \
--resolve site.example:443:10.0.20.40 https://site.example/Повторите 5 раз. Статика /favicon.ico vs /. Если favicon 20 мс, HTML 2 с — генерация, не канал.
Включите $request_time $upstream_response_time в лог nginx на время инцидента.
PHP slowlog — как в статье TTFB. opcache_get_status только с localhost, не светите в интернет.
4. SQL
На время:
SHOW GLOBAL STATUS LIKE 'Slow_queries';
SHOW FULL PROCESSLIST;Slow query log long_query_time=1. Ищите запросы темы/плагина из стека FPM.
5. Диск
iostat -xz 1 3
df -h /var/www /var/lib/mysqlBackup на том же диске в рабочее время — классика.
6. Ассеты
curl -s --resolve site.example:443:10.0.20.40 https://site.example/ | grep -oE 'src="[^"]+' | headВ DevTools: Waterfall, что блокирует. Content-Encoding: gzip на text/css и JS:
curl -sI -H 'Accept-Encoding: gzip' --resolve site.example:443:10.0.20.40 https://site.example/wp-includes/css/dashicons.min.css | grep -i content-encodingПуть CSS подставьте реальный из HTML.
7. Сравнение CDN vs origin
--resolve на origin IP vs обычный URL. Если CDN медленнее origin — кэш miss/гео. Если origin медленный — CDN HTML-кэш только спрячет.
Решение
- DNS: TTL, лишние CNAME, битый AAAA — DNS старый сервер если IP не тот.
- TLS: HTTP/2, актуальные протоколы, не слабые шифры ради «старых XP». Stapling опционально.
- TTFB: opcache, object cache, меньше плагинов, очередь FPM, вынести wp-cron.
- SQL: индексы, убрать N+1, не
SELECT *. - Ассеты: сжатие nginx
gzip onдля text, лимиты картинок, не 4 МБ PNG в шапке. - Боты: лимиты до PHP.
Не включайте Xdebug и display_errors для перф-профилирования в проде.
gzip on;
gzip_types text/css application/javascript application/json image/svg+xml;nginx -t && reload.
Сценарий: разложить HAR
Скачайте HAR с проблемного клиента. Смотрите: (1) время до первого запроса после DNS, (2) TTFB документа, (3) длинные waiting, (4) блокирующий JS в <head>, (5) 4xx/5xx ассетов с ретраями. Ретраи TLS увеличивают appconnect. Сверьте URL ассетов: если они на старом CDN/IP — DNS.
С сервера:
curl -s -o /dev/null -w '%{time_namelookup} %{time_connect} %{time_appconnect} %{time_starttransfer} %{time_total}\n' \
--resolve site.example:443:10.0.20.40 https://site.example/
php -r 'echo "cli\n";' # не TTFB сайтаСнимите EXPLAIN на запрос из slow log, не гадайте индекс. Если iowait высокий во время TTFB — сначала диск/backup, не Redis.
Документируйте: «TTFB origin 1.8s, DNS 20ms, TLS 30ms, LCP 4s из 2.5MB hero». Это разделяет работы системного и фронтенда. Не смешивайте в одном тикете «сайт медленный».
HTTP/2 мультиплекс не лечит TTFB HTML. Он лечит пачку мелких ассетов на одном соединении. Измерьте оба слоя отдельно.
Как проверить, что проблема устранена
Повторите тот же набор curl до/после, запишите namelookup, connect, appconnect, starttransfer, total. LCP в полевом RUM, не только ваш офисный гигабит. Проверьте пик: p95 request_time за час.
Страница 200, не 504. FPM не на max_children без ботов.
Если не помогло
- Регион пользователя далек — нужен CDN ассетов, HTML всё ещё origin.
- Steal time гипервизора.
- MySQL на другой площадке с RTT 40 мс × десятки запросов.
- HTTP/3 только на CDN, origin HTTP/1.1 — измерьте оба.
Профилактика
- Чёрный ящик: cron curl с
--resolveи без, алерт p95. - Бюджет: TTFB HTML < оговорённого SLA.
- Нагрузочный тест на staging, не на проде в обед.
- Каталог плагинов без «на всякий случай».
- Храните эталон HAR «хорошего дня» для
site.exampleс--resolveна10.0.20.40: иначе спорите о регрессе без цифр namelookup/connect/ttfb.
FAQ
PageSpeed 100 обязателен?
Нет. Сначала бизнес-метрика (TTFB, LCP вашей аудитории). Балл — эвристика.
ab / wrk на прод?
Осторожно, это DoS себе. Только окно и лимит RPS.
Почему ping хороший, TTFB плохой?
Ping ≠ TLS+PHP+SQL.
Нужен ли Redis сразу?
После доказательства, что object cache поможет (много повторяемых опций WP). Не вместо индекса.
Apache mod_pagespeed
Снят с поддержки в привычном виде. Не тащите как стандарт 2026. Кэш и сжатие — nginx/CDN.