PostgreSQL: почему после добавления серверов заканчиваются соединения

Приложение перенесли с одного экземпляра на четыре. Памяти у базы достаточно, CPU загружен умеренно, но пользователи получают «too many connections». Причина часто проста: каждый новый процесс создал собственный пул. Лимит, который казался небольшим внутри одного сервиса, умножился на количество экземпляров, фоновых задач и процессов внутри контейнера.
Нарисуйте карту клиентов базы
Считайте не машины и не контейнеры, а независимые пулы. На одном сервере могут работать несколько веб-процессов, обработчики очереди, планировщик и служебные скрипты. У каждого свои подключения. Во время обновления старые и новые экземпляры иногда существуют одновременно, что временно удваивает часть потребления.
Дополните карту служебными клиентами: миграциями, мониторингом, резервным копированием, аналитикой и доступом администратора. Не занимайте весь разрешённый предел приложением. Конкретные резервируемые слоты и параметры зависят от версии PostgreSQL и настройки сервера; перед изменением проверьте документацию именно своей версии.
| Потребитель | Количество пулов | Предел каждого | Верхняя оценка |
|---|---|---|---|
| Веб-приложение | 4 | 15 | 60 |
| Фоновые обработчики | 3 | 8 | 24 |
| Служебные задачи | 2 | 3 | 6 |
| Миграция во время выпуска | 1 | 2 | 2 |
| Итого без запаса | — | — | 92 |
Это верхние пределы, а не фактическая одновременная занятость. Но если каждый процесс умеет открыть столько соединений, конфигурация должна учитывать такое состояние. Ошибочно ориентироваться только на спокойный снимок панели в полночь.
Проверьте, чем заняты уже открытые соединения
На своей базе с разрешённым доступом изучите pg_stat_activity: приложение, пользователя, состояние, возраст запроса и транзакции. Особое внимание — долгим транзакциям и состоянию idle in transaction. Такое соединение не просто простаивает: незавершённая транзакция может удерживать блокировки и мешать обслуживанию таблиц.
Не завершайте все подключения подряд. Сначала выясните владельца и влияние. Принудительное завершение приводит к откату текущей транзакции, а приложение может немедленно открыть новое соединение. Для безопасной диагностики сохраните обезличенные признаки, не выгружая текст запросов с персональными параметрами в открытый тикет.
Три разных исправления
- Слишком много независимых пулов
- Согласуйте общий бюджет и уменьшите пределы каждого процесса. Проверьте кратковременное перекрытие экземпляров при развёртывании.
- Соединения удерживаются слишком долго
- Исправьте границы транзакций, медленные запросы и возврат соединения в пул при исключениях. Сетевой вызов внешнего API внутри транзакции заслуживает отдельного разбора.
- Много коротких клиентов
- Рассмотрите отдельный пулер, выбрав режим под приложение. В транзакционном режиме нельзя без проверки полагаться на произвольное состояние сессии между транзакциями.
Просто увеличить max_connections бывает допустимо после расчёта ресурсов, но это не универсальное лечение. Соединения имеют стоимость, а медленный запрос не ускорится от появления сотни новых конкурентов. Если упираетесь в диск или блокировку, рост параллелизма способен ухудшить ситуацию.
Как испытать конфигурацию до следующего пика
Смоделируйте обычный поток, длительный запрос и постепенное добавление экземпляров на стенде. Наблюдайте не только число соединений, но и ожидание получения соединения из пула, длительность запросов и долю ошибок. Затем повторите тест во время обновления с перекрытием версий. Нужен ограниченный план нагрузки, а не бесконечный стресс рабочего сервера.
Калькулятор ниже суммирует конфигурационные пределы. В строке указываются название, число независимых пулов и предел одного пула. Он показывает запас относительно введённого доступного бюджета. Из него уже должны быть вычтены защищённые административные слоты; инструмент сам не читает настройки базы.
Результатом работы должна стать карта клиентов и согласованные пределы с владельцем каждого пула. Когда появляется новый сервис, его включают в эту карту до запуска. Тогда масштабирование перестаёт незаметно расходовать общий ресурс.
Общий бюджет пулов PostgreSQL
Введите бюджет после вычета административного резерва. Верхняя оценка не является прогнозом фактической нагрузки. Расчёт выполняется на вашем устройстве, введённые данные никуда не отправляются.
Материалы для проверки
Если нужна реализация
Состав работ зависит от текущего проекта и подтверждённой причины. Можно обсудить диагностику или разработку подходящего решения.
