# теория · шаг 1 из 4
stub_status и три метрики, которые нужны
Коротко
stub_status включается одной директивой и даёт семь чисел. Два из них
отвечают на вопросы, которые иначе стоят часов: расхождение accepts и
handled означает, что соединения отбрасывались, а отношение requests к
accepts показывает, работает ли keepalive. Считать надо и соединения к
бэкендам: один проксируемый запрос занимает два слота worker_connections, и
при нехватке клиент получает 500. Качество ответов снимается не отсюда, а из
лога: доля 5xx, 95-й процентиль $upstream_response_time и число 499.
Метрики уже собираешь - листай до второго разбора: там про то, сколько соединений съедает один проксируемый запрос.
worker_connections 3. Статика отдаётся нормально, а тот же сайт через
proxy_pass отвечает 500. Опечатки в конфиге нет, бэкенд жив. Что
происходит?
worker_connections 2: свой ответ=000, через прокси=000
worker_connections 3: свой ответ=200, через прокси=500
worker_connections 4: свой ответ=200, через прокси=200
На что это похоже
worker_connections привычно читают как «сколько клиентов поместится». На
самом деле это число слотов на всё сразу: слушающий сокет занимает слот,
клиент занимает слот, и соединение к бэкенду занимает ещё один - как будто в
приёмной считают не посетителей, а стулья, и один стул всегда занят вешалкой, а
переговорщик с поставщиком садится на второй.
Отсюда правило, которое экономит вечер: делить настроенное число пополам,
если сайт проксирующий. И отсюда же понятно, почему nginx с
worker_connections 2 вообще не стартует.
Механизм: что считает stub_status
Правило
location = /nginx_status {
stub_status;
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
access_log off;
}
Active connections: 291
server accepts handled requests
16630948 16630948 31070465
Reading: 6 Writing: 179 Waiting: 106
| Число | Что означает |
|---|---|
Active connections |
обслуживается прямо сейчас, включая keepalive |
accepts |
принято соединений с момента старта |
handled |
обработано; меньше accepts - соединения отбрасывались |
requests |
всего запросов; больше соединений из-за keepalive |
Reading |
читаем запрос клиента |
Writing |
пишем ответ |
Waiting |
keepalive-соединения без активности |
Закрывать обязательно: секретов тут нет, но профиль нагрузки виден, а сама
страница удобна как цель для опроса чужими руками. access_log off - чтобы
опросы раз в секунду не забивали лог.
Разбор: работает ли keepalive
Вопрос «а keepalive-то у нас включён?» решается двумя замерами. Двадцать запросов одним соединением и двадцать - каждый своим:
| прогон | прирост accepts |
прирост requests |
|---|---|---|
| 20 запросов в одном соединении | 2 | 21 |
| 20 запросов, каждый со своим | 21 | 21 |
Отношение requests / accepts в первом случае около десяти, во втором - около
единицы. Единица означает, что каждый запрос платит за установку соединения, а
на HTTPS ещё и за рукопожатие; на графике это видно как ровная линия, которая
не должна быть ровной.
Замерить это на живом сервере - минута, а вывод серьёзный: если отношение
близко к единице, ищи, кто обрывает keepalive - клиент, промежуточный прокси
или твой же keepalive_timeout 0.
Разбор: сколько соединений съедает один запрос
Тот же стенд, что в крючке, только теперь с логом:
worker_connections |
свой ответ | через прокси | строк «not enough» |
|---|---|---|---|
| 2 | nginx не стартует | - | 2 |
| 3 | 200 | 500 | 1 |
| 4 | 200 | 200 | 0 |
Читается так. Слушающий сокет забирает слот ещё до первого клиента - поэтому при двойке nginx честно отказывается стартовать:
nginx: [emerg] 1 worker_connections are not enough for 1 listening sockets
При тройке хватает на сокет и клиента, но не на соединение к бэкенду - и
клиент получает 500, а не 502 и не 503. Это важное различие: 500 в
такой ситуации означает не ошибку приложения, а нехватку ресурсов у самого
nginx. В логе рядом лежит объяснение, и уровень у него alert, а не
warn:
[alert] 10#10: *10 4 worker_connections are not enough while connecting to upstream,
client: 127.0.0.1, server: , request: "GET /apislow/x HTTP/1.1"
Хвост строки называет и место: слот кончился при подключении к бэкенду, а не при приёме клиента.
Что ломается без этого
Наплыв, которого не видно в кодах ответа. Стенд с worker_connections 4 и
тридцатью параллельными запросами: accepts 38, handled 31. Семь соединений
были приняты ядром и отброшены nginx - клиент увидел обрыв, а в access_log
для них нет ни строки, потому что запроса не случилось. Единственные следы -
расхождение двух чисел в stub_status и [alert] в error_log. Если снимать
только «долю 5xx по логу», такой инцидент не виден вовсе.
Телеметрия, которую никто не проверял. Метрика, собираемая не с той машины или не в том формате, выглядит как здоровый график. Проверяется нарочной поломкой:
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/этого-точно-нет
В графике должен появиться 404. Не появился - разбираться сейчас, а не в три часа ночи. Так же проверяются и алерты: подними порог на минуту и убедись, что письмо дошло. Ненастроенный алерт хуже отсутствующего - он создаёт ложное чувство безопасности.
Зачем это в работе
Три показателя, которых stub_status не даёт и которые снимаются из лога:
доля 5xx ловит поломки, 95-й процентиль $upstream_response_time ловит
деградацию до того, как она станет поломкой, число 499 ловит терпение
пользователей - оно кончается раньше любых твоих таймаутов.
log_format metrics '$time_iso8601 $status $request_time $upstream_response_time '
'$upstream_cache_status $upstream_addr';
Разбирать этот формат можно чем угодно - от awk до экспортера в Prometheus.
Важно не чем, а что рядом с ним лежит опрос stub_status: коды ответа и
счётчики соединений отвечают на разные вопросы, и инцидент, который не видно в
одном, обычно виден в другом. В открытой версии активных проверок здоровья
бэкендов нет, их роль играют пассивные max_fails и fail_timeout из
восьмого раздела.
Теперь сам
В мониторинге ровная линия: requests растёт примерно так же, как accepts,
их отношение около единицы. Жалоб нет, ошибок нет. Стоит ли что-то делать?
Ответ: стоит. Отношение около единицы означает, что keepalive не работает и
каждый запрос платит за установку TCP-соединения, а на HTTPS - ещё и за
рукопожатие. Это не поломка, а постоянный налог на скорость и на процессор.
Смотреть надо keepalive_timeout у себя, заголовок Connection от клиентов и
промежуточные прокси; если сайт проксирующий, заодно проверить keepalive в
блоке upstream - к бэкендам соединения тоже могут открываться на каждый
запрос.
Главное
stub_status - одна директива и семь чисел. Расхождение accepts и handled
означает отброшенные соединения (замер: 38 против 31 при нехватке слотов), и в
access_log их не видно вовсе - только [alert] worker_connections are not
enough. Отношение requests к accepts показывает, работает ли keepalive:
двадцать запросов одним соединением дали прирост accepts на 2, двадцатью
соединениями - на 21. В worker_connections входит и слушающий сокет, и
соединение к бэкенду: при значении 3 статика отдаётся, а проксируемый запрос
даёт 500. Закрывать статус обязательно (allow/deny плюс access_log
off), качество ответов снимать из лога (5xx, процентиль
$upstream_response_time, 499), а телеметрию проверять нарочной поломкой.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий