1. 1
  2. 2
  3. 3
  4. 4
  5. 5

# теория · шаг 2 из 5

Первые пять минут инцидента

Коротко

Инцидент - плохое время для творчества: работает заранее написанный порядок. Жив ли процесс → что применено (nginx -T) → свежие строки error_log → воспроизведение локальным curl → проверка бэкенда напрямую. Смягчать можно человеческой страницей, протухшим кешем, выводом узла из группы и поднятым таймаутом - это обезболивание, а не лечение. Режим обслуживания включается файлом-флагом без перезагрузки конфига, а Retry-After на странице заглушки требует always - иначе заголовка на 503 не будет.

Свой порядок уже есть - листай до первого разбора: там замеренная заглушка и ловушка с always.

Заглушка на время работ готова: файл-флаг, return 503, своя страница и Retry-After, чтобы поисковики и клиенты вернулись позже. Проверяешь - страница на месте, а заголовка нет.

↳  выводcurl -D- на включённой заглушке
HTTP/1.1 503 Service Temporarily Unavailable
Retry-After: 600
↳  выводтот же ответ, заголовок без always
заголовков «X-Without-Always» в ответе: 0

Один заголовок доехал, второй - нет, хотя стоят рядом в одном блоке.

На что это похоже

Первые пять минут инцидента - это не расследование, а сортировка в приёмном покое. Задача не «понять, что случилось», а быстро отделить тяжёлое от лёгкого и понять, чьё это: nginx, приложения или сети.

Отсюда и правило про творчество: у сортировки есть протокол, и он выполняется в одном порядке всегда - именно потому, что в три часа ночи голова работает хуже, чем список.

Механизм: порядок первых пяти минут

жив ли процесс и слушает ли порт что реально применено: nginx -T свежие строки error_log воспроизвести локальным curl проверить бэкенд напрямую
Порядок важнее скорости: каждый шаг отсекает половину гипотез

Правило

$  команда
systemctl is-active nginx && ss -ltnp | grep nginx
nginx -T | grep -A5 "server_name shop.local"
tail -n 100 /var/log/nginx/error.log | grep -v "\[notice\]"
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' -H 'Host: shop.local' http://127.0.0.1/api/cart
curl -sS -o /dev/null -w '%{http_code} %{time_total}\n' http://app:8000/api/cart

Второй шаг стоит отдельного слова: -T печатает собранный конфиг со всеми include. Половина инцидентов «я же поправил» заканчивается здесь - правка легла в файл, который не подключён, или её перекрыл другой блок. Третий шаг тоже: ошибки, начавшиеся ровно в момент жалобы, - твои; всё, что сыплется неделями, - фон.

Разбор: режим обслуживания файлом-флагом

Заглушку для плановых работ готовят заранее, и включаться она должна без правки конфига:

/etc/nginx/conf.d/shop.local.confhttp server
location / {
    if (-f /etc/nginx/maintenance.on) {
        return 503;
    }
    proxy_pass http://app:8000;
}

error_page 503 /maintenance.html;
location = /maintenance.html {
    root /var/www/errors;
    internal;
    add_header Retry-After 600 always;
}

Замер по шагам:

действие ответ
до включения 200
touch maintenance.on, без reload 503, тело своей страницы
заголовок Retry-After с always на месте
соседний заголовок без always отсутствует
rm maintenance.on снова 200

Два вывода. Первый: if (-f ...) проверяется на каждом запросе, поэтому режим включается и выключается созданием файла - без reload, без правки конфига, руками дежурного. Это тот редкий if, который безопасен: внутри только return (тринадцатый раздел).

Второй - ловушка из крючка. add_header по умолчанию работает только на успешных кодах, а заглушка - это 503. Без always заголовка на ней не будет, и клиенты с поисковиками не узнают, когда возвращаться.

Разбор: быстрые смягчения и их цена

Пока чинится причина, стоит перестать делать больно пользователям. Все четыре приёма применяются через reload и откатываются так же:

приём что даёт чем платишь
error_page 502 503 504 /50x.html человеческая страница вместо стандартной ничем, делай сразу
proxy_cache_use_stale error timeout http_502 отдаём протухшее, пока бэкенд не в себе часть пользователей видит старые данные
down у сервера в upstream вывести больной узел оставшиеся берут его нагрузку
поднять proxy_read_timeout дожидаться медленных ответов соединения живут дольше, слотов меньше

Последняя строка - причина, по которой это именно обезболивание: поднятый таймаут удерживает слоты worker_connections, и при затянувшемся инциденте ты получишь второй, уже свой.

Что ломается без этого

Кручение параметров «на всякий случай». worker_processes, worker_connections, размеры буферов посреди инцидента менять нельзя: эффект неочевиден, а отличить его от случайных колебаний в этот момент невозможно. Если после правки стало лучше - ты не знаешь почему, и это худший из исходов.

Выключенные логи. Соблазн «разгрузить диск» возникает ровно тогда, когда зрение нужнее всего. Диск чистится ротацией и find -delete по старым файлам, а не выключением access_log.

Правка, которая никуда не приехала. Классический сценарий: конфиг поправлен, reload выполнен, ничего не изменилось. Причины две - файл не подключён (nginx -T покажет) или reload не применился (порт занят, файл сертификата исчез), а код возврата при этом нулевой, как в первом уроке раздела. Смотреть надо error_log, а не результат команды.

Зачем это в работе

После инцидента записывают три вещи, пока не забылось. Что сломалось - не «упал сайт», а «502 на /api/, потому что бэкенд перезапускался дольше своей готовности». Как узнали - жалоба пользователя или мониторинг, и если жалоба, то почему не мониторинг. Что заметит раньше в следующий раз.

Для nginx ответ на третий вопрос почти всегда один и тот же: доля 5xx ловит поломки, 95-й процентиль $upstream_response_time ловит деградацию, число 499 ловит терпение пользователей. Плюс расхождение accepts и handled из stub_status - оно ловит то, чего в кодах ответа не видно вовсе.

Теперь сам

Ночью дежурный включил режим обслуживания файлом-флагом, утром удалил файл - и часть пользователей продолжает видеть страницу «идут работы». curl с сервера отдаёт 200. Что произошло?

Ответ: страницу заглушки закешировали - либо промежуточный кеш и браузер (503 кешируется, если у ответа есть Cache-Control или Expires, а Retry-After некоторые прокси трактуют как разрешение подождать), либо собственный proxy_cache, если заглушка попала в него. Проверять: curl -I с сервера и от пострадавшего, заголовки Cache-Control и Age в ответе, статус $upstream_cache_status в логе. Лечится добавлением add_header Cache-Control "no-store" always; на страницу заглушки - на будущее, и сбросом кеша сейчас. Мораль общая: временная страница обязана быть некешируемой, иначе она переживёт работы.

Главное

Порядок вместо творчества: жив ли процесс → что применено (nginx -T) → свежие строки error_log → воспроизведение локальным curl → проверка бэкенда напрямую тем же путём. Режим обслуживания включается файлом-флагом с if (-f ...) и return 503 - без перезагрузки конфига, потому что условие проверяется на каждом запросе; Retry-After на такой странице требует always, иначе заголовка на 503 не будет (замер: соседний заголовок без always в ответе отсутствует). Смягчения - своя страница ошибки, протухший кеш, down у узла и поднятый таймаут - дают время, но последний съедает слоты соединений. Не крути буферы и воркеров на горячую и не выключай логи. После инцидента - три вопроса: что сломалось, как узнали, что заметит раньше.

Комментарии

Пока нет комментариев. Будь первым!

Оставить комментарий

Комментарий появится после проверки. Email не публикуется. Войти, чтобы не вводить имя каждый раз.