Скачать CV
Назад к бизнес-кейсам

Деплой

SIGTERM посреди записи каталога

compose restart php убивал FCGI в полёте. nginx отдавал 502. Полузаписанный ключ Memcached оставался.

Деплой это docker compose up -d --build php. Старый контейнер получает SIGTERM. У PHP-FPM несколько секунд, потом SIGKILL. Воркер, который писал slab листинга, остановился. nginx отдал 502. Memcached оставил обрезанное значение. Следующий GET отдавал битый HTML, пока lock на пересборку не отработал снова.

opcache_reset() в хуке делал следующую минуту хуже. Каждый выживший воркер заново компилировал LaraBoom. CPU подскакивал. Листинг, который только что получил 502, ждал компиляцию.

Проблема была в рестарте контейнера вместо drain. Посетители получали 502, потом битый slab. Нужен SIGUSR2 внутри живого контейнера, grace period длиннее самого медленного запроса и без общего opcache_reset().

SIGTERM это не drain. SIGUSR2 это drain. FCGI в полёте должен доехать.
SIGTERM это не drain. SIGUSR2 это drain. FCGI в полёте должен доехать.

Reload внутри контейнера

Образ сначала копирует код. Потом kill -USR2 на pid php-fpm. Старые воркеры заканчивают запрос. Новые стартуют с новыми файлами и preload. nginx держит unix-сокет. 502 от мёртвого FCGI на этом пути нет. Записи в Memcached доходят. Lock пересборки в Redis не остаётся взятым наполовину.

У нового воркера новый OPcache. Общий reset это stampede специально.
У нового воркера новый OPcache. Общий reset это stampede специально.
  • stop_grace_period у сервиса php длиннее самого медленного запроса каталога, который мерили.
  • queue и schedule получают новый образ отдельно. Воркер Horizon заканчивает текущий job и умирает.
  • SET slab в Memcached это одно значение. Частичной записи нет, если процесс жив до возврата SET.

Деплой по-прежнему занимает минуту из-за сборки образа. Публичная страница в эту минуту не отдаёт 502. Это и было требование.

Какой опыт из этого

compose restart это не rolling reload. SIGTERM потом SIGKILL режет FCGI пополам. SIGUSR2 это drain, который у PHP-FPM уже есть.

opcache_reset() на живом пуле это stampede компиляции. Новые воркеры получают новый кэш. Старые должны дописать и умереть.

Обрезанное значение Memcached хуже 502. SET либо доезжает, либо его не начинают.

Назад к бизнес-кейсам