Миграция ждала блок...
 
Уведомления
Очистить всё

Миграция ждала блокировку и на 4 минуты повесила все запросы к таблице

5 Сообщения
4 Пользователи
9 Реакции
210 Просмотры
Лариса 2002
Сообщения: 9
Автор темы
Разобрался с блоками тимлид
Присоединился: 3 месяца назад
[#122]

Hanami 2, PostgreSQL 17. Вчера днём выкатили безобидную миграцию: добавить в invoices колонку без default, просто NULL. Обычно это мгновенно. А тут миграция висела четыре минуты, и всё это время любые запросы к invoices, даже простые SELECT, стояли в очереди. API отдавал таймауты, пока кто-то не нашёл и не убил долгий отчёт аналитиков. Я правильно понимаю, что виноват отчёт? И как защититься, если отчёты не всегда гоняют по реплике?


4 ответа
kostya.sokurov
Сообщения: 73
Держит прод бэкенд-разработчик, senior
Присоединился: 4 года назад

Правильно понимаете. ALTER TABLE берёт ACCESS EXCLUSIVE и ждал, пока закончится долгая транзакция с отчётом. А все новые запросы, даже SELECT, встают в очередь уже за ним: блокировки выдаются по порядку. В итоге одна долгая выборка плюс одна быстрая миграция кладут таблицу. Защита: короткий lock_timeout для миграций, пусть лучше упадёт и повторится, чем повесит всех:

SET lock_timeout = '3s';
ALTER TABLE invoices ADD COLUMN paid_via text;

И перед выкаткой посмотреть, что сейчас долго открыто:

SELECT pid, now() - xact_start AS duration, state, left(query, 60)
FROM pg_stat_activity
WHERE xact_start IS NOT NULL
ORDER BY duration DESC
LIMIT 5;

Про уровни блокировок подробно здесь: https://www.postgresql.org/docs/current/explicit-locking.html


Ответ
GoshaFedorov
Сообщения: 3
Пишет в irb тимлид
Присоединился: 3 месяца назад

Мы ещё ставим statement_timeout и idle_in_transaction_session_timeout на роль, под которой ходят отчёты. Десять минут на запрос, кому нужно дольше, идёт на реплику. Аналитики поворчали неделю и привыкли


Ответ
Лариса 2002
Сообщения: 9
Автор темы
Разобрался с блоками тимлид
Присоединился: 3 месяца назад

В итоге так: в обёртке миграций теперь SET lock_timeout = '5s' и три попытки с паузой в 30 секунд. Для роли отчётов statement_timeout 15 минут. Сегодня катили ещё одну колонку: первая попытка упала по таймауту, вторая прошла. Никто ничего не заметил.


Ответ
1 ответ
GalinaKorneva
Присоединился: 4 года назад

Читает чужие PR бэкенд-разработчица
Сообщения: 30

Автор: Лариса 2002
Никто ничего не заметил.

Лучший итог для миграции. Я бы ещё повесила алерт на транзакции дольше получаса


Ответ