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

# конспект · шаг 4 из 4

Конспект: наблюдаемость и выкладки

выжимка - её можно унести в заметки

Что смотреть постоянно и как выкладывать изменения так, чтобы откат был дешёвым.

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 если handled меньше - соединения отбрасывались
requests всего запросов; больше соединений из-за keepalive
Reading / Writing / Waiting читаем запрос / отдаём ответ / держим keepalive

Замер keepalive: 20 запросов одним соединением дали прирост accepts на 2 и requests на 21; 20 запросов своими соединениями - 21 и 21. Отношение около единицы означает, что keepalive не работает.

Слоты соединений считаются на всё

Замер на проксирующем сайте:

worker_connections свой ответ через прокси
2 nginx не стартует -
3 200 500
4 200 200

Слушающий сокет занимает слот, клиент - ещё один, соединение к бэкенду - третий. При нехватке клиент получает 500, а в логе [alert] worker_connections are not enough.

Три метрики, которых достаточно

  1. доля 5xx - из access_log по $status;
  2. время ответа - $request_time и $upstream_response_time (перцентили, а не среднее);
  3. отброшенные соединения - разница accepts и handled.

Безопасные выкладки

# в http: группы app_stable и app_canary объявлены через upstream
split_clients "$remote_addr$http_user_agent" $backend {
    5%      app_canary;     # канарейка: 5% пользователей на новую версию
    *       app_stable;
}

# в server
location /api/ {
    mirror /mirror;         # копия трафика на тестовый бэкенд
    proxy_pass http://$backend;
}

location = /mirror { internal; proxy_pass http://app_canary$request_uri; }

В proxy_pass с переменной - имя группы, а не app-new:8000: имя хоста nginx разрешал бы во время запроса, и без resolver копия молча не доезжает.

Замеры: один и тот же ключ всегда даёт ту же группу; 400 разных ключей - 4,5% канарейки при заявленных 5%; ключ $request_id отправил одного и того же клиента в канарейку 7 раз из 200. Зеркало получает и тело POST. Первый ответ медленную копию не ждёт (0,0016 с против 10 секунд копии), но запрос заканчивается вместе с ней: следующий запрос по тому же keepalive-соединению ждал 5 секунд пятисекундного зеркала. С телом зеркало заставляет nginx дочитать его до отправки бэкенду (3,0 с против 0,001 без зеркала).

Ловушки джокера

  • stub_status открытым наружу - бесплатная разведка о твоей нагрузке.
  • Ключ карты, который меняется от запроса к запросу ($request_id, $date_gmt, время) - пользователь прыгает между версиями внутри сессии.
  • Среднее время ответа прячет хвост: 99-й перцентиль и среднее живут в разных вселенных.
  • Канарейка без метки группы в логе бессмысленна: ошибки новой версии не отличить от ошибок старой.
  • Медленное зеркало не тормозит первый ответ, но задерживает следующий запрос по тому же соединению и держит слоты соединений - под нагрузкой это оборачивается отброшенными соединениями.
  • Забытый internal у зеркала: замер - с ним снаружи 404, без него 204.

Комментарии

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

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

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