Nginx повторил POST на другом upstream: проверяем политику next_upstream
После краткого сетевого сбоя в журнале видны два backend для одной клиентской операции. Команда подозревает двойной клик пользователя, но повтор мог выполнить reverse proxy. Nginx умеет переходить к следующему upstream при определённых ошибках. Для чтения это часто полезно; для создания заказа требуется разбирать момент отправки и свойства операции.
Найдите политику фактического location
location /orders {
proxy_pass http://orders_backend;
proxy_next_upstream error timeout;
proxy_next_upstream_tries 2;
proxy_next_upstream_timeout 3s;
}
Пример ограничивает условия и бюджет попыток, но не задаёт универсально безопасную политику для заказов. Значения выбирают по архитектуре приложения. По умолчанию error и timeout уже относятся к условиям перехода; другие HTTP-статусы нужно задавать отдельно, если они должны участвовать.
Число попыток и общий временной бюджет отвечают на разные вопросы. Ограничение tries не гарантирует короткий ответ, если отдельная попытка ждёт слишком долго. А ограничение времени не делает повтор безопасным: оно только сужает окно, в котором прокси будет пробовать другие серверы.
Разберите судьбу изменяющего запроса
Nginx специально ограничивает повтор неидемпотентных методов после отправки upstream. Параметр non_idempotent разрешает повторять такие запросы в соответствующих условиях. Если он найден в конфигурации POST-пути, выясните, кто и зачем его включил. Удалять его без анализа доступности тоже не стоит, но понимать последствия обязательно.
Ключевой сценарий: backend записал заказ, затем соединение оборвалось до получения ответа прокси. По сетевой ошибке нельзя заключить, что запись не состоялась. Если повтор разрешён, другой backend может выполнить то же действие ещё раз. Само использование другого сервера не создаёт дедупликацию.
Свяжите попытки с одной операцией
Запишите upstream_addr и upstream_status в access log, добавьте корреляцию с идентификатором запроса приложения. Несколько значений в одной записи помогают увидеть последовательные обращения. Затем сопоставьте их с серверными журналами: одна ли бизнес-операция была создана, какой ключ использовался и какой ответ успел сформироваться.
Приложение может поддерживать ключ идемпотентности, но его присутствие в заголовке недостаточно. Сервер должен согласованно хранить результат и распознавать повтор на всех экземплярах. Если backend не имеет такой семантики, настройте для изменяющего пути более осторожную политику и предусмотрите выяснение результата после неопределённого отказа.
На стенде отдельно проверьте отказ до соединения, разрыв после приёма запроса и ошибку после записи результата. Это разные точки, хотя клиенту может прийти одинаковый 502. Не воспроизводите финансовые или иные необратимые операции на рабочем сервисе ради такой проверки.
Завершённый результат — описанный бюджет попыток, понятные условия перехода и правило обработки неопределённого исхода. Тогда сетевое восстановление доступности не превращается в случайное повторение бизнес-действий.
Развивайте диагностику сервиса за пределами одного статуса ответа. В курсе Linux и Bash для DevOps-инженеров есть HTTP, сеть и работа с журналами. Откройте программу, чтобы связывать события разных уровней в воспроизводимый разбор сбоя.
Ещё по теме
Продолжить на практике
- Linux и Bash для DevOps-инженеров ↗
Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.
