История, с которой легко столкнуться любому, кто держит PostgreSQL в проде: система работала стабильно, AAS держался около 1.0 на инстансе с 2 vCPU, а потом внезапно взлетел до 25. Ниже — не хроника «как мы страдали», а разбор того, что стоит делать, если вы увидели похожую картину. Без магии и обещаний, что «одна метрика всё расскажет».
Что вообще означает скачок AAS
AAS (Average Active Sessions) — среднее число сессий, которые в данный момент либо выполняют запрос, либо ждут ресурса. На двухъядерном инстансе значение около 1.0 — норма: одна активная сессия примерно на одно ядро. Рост до 25 означает, что в среднем два с половиной десятка сессий одновременно чего-то ждут или работают. Это не обязательно «база умирает», но это точно сигнал, что где-то образовалась очередь.
Первое, что стоит сделать, — не гадать, а разложить AAS по состояниям ожидания. В PostgreSQL это делается через pg_stat_activity: смотрите на wait_event_type и wait_event. Если большинство сессий в состоянии Lock или LWLock, причина — блокировки. Если в IO — упираетесь в диск. Если в CPU — запросы реально жгут процессор. Это первый развилочный пункт, и от него зависит всё дальнейшее.
Шаг 1: зафиксировать картину, а не тушить пожар вслепую
Типичная ошибка в такие моменты — сразу перезапускать базу или убивать все сессии подряд. Это снимает симптом, но стирает следы. Прежде чем что-то трогать, снимите срез:
- Выгрузка pg_stat_activity с группировкой по state, wait_event_type и query (хотя бы первые 100 символов запроса).
- Текущие блокировки: pg_locks в связке с pg_stat_activity, чтобы увидеть, кто кого ждёт.
- Метрики ОС: загрузка CPU, очередь на диск, объём свободной памяти.
- Логи PostgreSQL за последние часы — особенно ошибки и медленные запросы, если включён log_min_duration_statement.
Эти данные нужны не для отчёта, а чтобы понять, был ли это всплеск нагрузки, деградация конкретного запроса или внешний фактор вроде пропавшего индекса после миграции.
Шаг 2: найти источник очереди
Дальше смотрите на топ запросов по времени. Если есть pg_stat_statements, берите запросы с наибольшим средним временем и количеством вызовов. Часто картина такая: один запрос стал выполняться в разы дольше, потому что вырос объём данных или изменился план. Другая частая причина — массовые блокировки из-за транзакции, которая держит lock и не завершается.
Практический критерий: если в pg_locks видно, что десятки сессий ждут один и тот же объект, ищите «голову» очереди — сессию, которая держит блокировку. Дальше решайте, можно ли её аккуратно завершить через pg_terminate_backend или нужно ждать. Завершение сессии — это не «починка», а способ разблокировать остальных, и применять его стоит осознанно.
Шаг 3: проверить, что изменилось
Когда острая фаза снята, задайте себе вопрос: что поменялось за последние сутки? Типичные триггеры деградации:
- Выкатили миграцию, которая добавила тяжёлый запрос или убрала индекс.
- Вырос трафик от нового клиента или фоновой задачи.
- Изменился план запроса из-за устаревшей статистики — помогает ANALYZE.
- На диске закончилось место или выросла latency хранилища.
Сверьте время начала деградации с логами деплоя и изменениями в конфигурации. В большинстве инцидентов ответ находится именно здесь, а не в «загадочном поведении PostgreSQL».
Типичные ошибки при разборе
Первая — смотреть только на CPU и делать вывод, что «база тормозит». AAS растёт и при ожидании блокировок, когда процессор почти свободен. Вторая — игнорировать исторические метрики: без базовой линии вроде «AAS около 1.0» вы не поймёте, что 25 — это аномалия, а не норма для вашего профиля нагрузки. Третья — лечить следствие: добавлять индексы или менять конфиг без понимания, какой запрос создал очередь.
Ещё одна распространённая ошибка — не иметь pg_stat_statements и логов медленных запросов. В момент инцидента включать их поздно: вы уже не увидите, что происходило час назад. Настройте сбор заранее, даже если кажется, что «у нас маленькая база и всё быстро». Именно на маленьких инстансах запас по ресурсам невелик, и любая очередь видна резко.
Что сделать заранее, чтобы следующий разбор был быстрее
Держите минимальный набор наблюдаемости: график AAS с разбивкой по состояниям ожидания, сбор pg_stat_statements, логи медленных запросов и алерт на рост AAS выше вашей базовой линии. Определите порог, при котором вы вмешиваетесь: например, AAS держится выше 5 дольше пяти минут. Это субъективно, но лучше, чем реагировать только когда всё уже легло.
И последнее: разбор инцидента полезен не отчётом, а конкретными изменениями. По итогам стоит зафиксировать, какие метрики смотреть первыми, кто принимает решение о завершении сессий и какие изменения в схеме или коде нужно внести, чтобы та же очередь не повторилась. Без этого через месяц история повторится с тем же AAS и теми же вопросами.