Вышел nginx 1.29.6. Релиз mainline, и в нём есть прикладная новинка: в open source-версии появилась нормальная привязка клиентских сеансов к одному backend в группе upstream. Добавили директиву sticky, а у server появились параметры route и drain.
В идеальном мире все приложения stateless, сессии лежат в Redis, а балансировщик просто гоняет запросы. В проде иначе: старый Java-стек, backend сам метит маршрут, сессия привязана к ноде, или узел нужно вывести из пула, не порвав активных пользователей. Вот здесь 1.29.6 уже интересен.
Что это за релиз
Nginx 1.29.6 относится к mainline. Стабильная линейка живёт отдельно, в mainline выкатывают новые возможности, которые потом попадут в future stable. На базе 1.29.x позже сформируют стабильную 1.30. Stable по-прежнему получает только серьёзные исправления и закрытие уязвимостей.
Срочно обновляться этой ночью не нужно. Но на стенде релиз стоит прогнать, если у вас sticky-сессии, state на ноде или мягкий вывод backend из работы.
Главное: sticky-сессии в upstream
Смысл простой. Клиент один раз попал на backend, и nginx направляет его следующие запросы туда же. Это session affinity, она же sticky session. Для блока upstream доступна директива sticky с тремя режимами: cookie, route и learn.
Раньше в open source nginx приходилось городить костыли через приложение, сторонние модули или архитектурные компромиссы. Теперь базовая session affinity есть в основном инструменте.
Вариант 1: sticky cookie
Самый прямой сценарий. Nginx сам выставляет cookie с информацией о выбранном backend. Первый запрос балансируется как обычно, дальше клиент ходит на ту же ноду.
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
Удобно для типовых веб-приложений, когда backend трогать не хочется: nginx сам привязал, сам выставил cookie, сам держит клиента на нужной ноде. Для админок, кабинетов и внутренних систем этого часто хватает.
Вариант 2: sticky route
Режим route интереснее. Nginx не придумывает свою cookie, а берёт уже существующую маршрутную информацию из запроса: например, из JSESSIONID или параметра в URI. Потом сопоставляет маршрут со значением route у серверов в upstream и отправляет запрос на нужную ноду.
map $cookie_jsessionid $route_cookie {
~.+\.(?P<route>\w+)$ $route;
}
map $request_uri $route_uri {
~jsessionid=.+\.(?P<route>\w+)$ $route;
}
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b;
sticky route $route_cookie $route_uri;
}
Хороший вариант для старых Java-приложений и систем со своей логикой маршрутизации. Nginx не ломает схему, а подстраивается под неё. Не всегда лучший подход – прийти и за пять минут объяснить легаси, что оно живёт неправильно.
Вариант 3: sticky learn
В режиме learn nginx смотрит ответы upstream и запоминает сессии, которые создало само приложение. Backend при первом ответе выставляет cookie, nginx потом помнит, на какой узел сажать этого клиента.
upstream backend {
server backend1.example.com:8080;
server backend2.example.com:8081;
sticky learn
create=$upstream_cookie_examplecookie
lookup=$cookie_examplecookie
zone=client_sessions:1m;
}
Удобно там, где приложение давно живёт своей жизнью и переделывать его ради красивой архитектуры никто не будет. Иногда лучшая автоматизация – не мешать тому, что уже работает.
Зачем route и drain
С route всё просто: метка сервера, по которой nginx понимает, к какому backend привязывать запрос. drain полезнее в эксплуатации.
upstream backend {
server backend1.example.com route=a;
server backend2.example.com route=b drain;
sticky cookie srv_id expires=1h domain=.example.com path=/;
}
Параметр drain мягко выводит сервер из пула. Новые непривязанные запросы туда не идут, а уже связанные через sticky продолжают ходить. Полезно при обслуживании, rolling update или аккуратной миграции, когда не хочется рубить активные сессии.
В кабинетах, CRM и внутренних панелях, где пользователи сидят по часу, это экономит нервы. Фраза «разлогиньтесь и зайдите заново» для бизнеса обычно звучит не как совет, а как мелкая диверсия.
Где это реально нужно
Старые приложения, где state ещё на ноде. Java-стек с JSESSIONID и маршрутами. Инфраструктура, где backend сам создаёт сессии и его лучше не трогать. Обслуживание и постепенный вывод серверов, когда жёсткий отстрел ноды слишком груб.
При этом sticky – не замена нормальной архитектуре. Это эксплуатационный инструмент, а не лечение фундаментальных проблем. Если можно сделать сервис stateless и вынести состояние в общее хранилище, обычно так и стоит. Но жизнь чаще подкидывает не идеальные системы, а реальные. Nginx 1.29.6 как раз про работу с реальностью.
Что ещё вошло в 1.29.6
Sticky – главная новость, но не единственная. В выпуске есть доработки вокруг QUIC, исправления в HTTP/2, SCGI, модуле ngx_http_mp4_module, обработке заголовка Cookie и разборе IMAP literal argument.
Релиз не сводится к одной директиве. Просто sticky, route и drain – то, что можно быстро примерить к своим конфигам, а не только прочитать в changelog.
Стоит ли обновляться
Если вы уже на mainline и ждали нормальную session affinity в open source nginx, на 1.29.6 стоит посмотреть. По классике: стенд, тесты, проверка балансировки, cookie, route и вывода узлов через drain, и только потом прод.
Если production спокойно живёт на stable и sticky прямо сейчас не нужны, срываться необязательно. Релиз хороший, но nginx любит аккуратные обновления, а не «накатим ночью и посмотрим».
Итог
Nginx 1.29.6 получился прикладным. Главное – sticky в upstream с тремя режимами, плюс route и полезный drain. Для тех, кто балансирует не сферический stateless-сервис, а живые приложения с историей, обновление рабочее, а не декоративное.