Приложение ломается при работе через пул соединений
Пул соединений переиспользует соединения между клиентами, и в агрессивных режимах клиент не получает то же соединение дважды. Всё, что живёт в соединении — подготовленные запросы, временные таблицы, настройки сеанса, — перестаёт работать.
Вероятные причины
По порядку: сверху то, что встречается чаще.
-
Режим пула не сохраняет состояние соединения
В режиме на транзакцию соединение возвращается в пул после каждой транзакции. Состояние сеанса теряется.
-
Пул исчерпан и клиенты ждут
Число соединений к базе ограничено. При исчерпании клиенты ждут, и приложение видит таймауты.
-
Приложение обращается напрямую к базе, минуя пул
Часть соединений идёт мимо пула, и число соединений к базе оказывается больше расчётного.
Диагностика
Команды идут в том порядке, в котором их стоит выполнять: каждая следующая проверяет то, что осталось после предыдущей.
Состояние пулов: клиенты, серверы, ожидающие.
psql -h 127.0.0.1 -p 6432 -U pgbouncer -c 'SHOW POOLS' 2>/dev/nullСообщения пула о соединениях и отказах.
journalctl -u pgbouncer -n 30 --no-pagerКто подключается к базе напрямую, а кто через пул.
sudo ss -tnp | grep -E ":5432|:6432" | headРешение
Решение своё для каждой причины. Сначала определите, какая из них ваша, — иначе правки наложатся друг на друга.
- Почему происходит
- В режиме на транзакцию соединение возвращается в пул после каждой транзакции. Состояние сеанса теряется.
- Как проверить
-
Посмотрите режим пула и ошибки приложения.
sudo grep -iE "^pool_mode" /etc/pgbouncer/pgbouncer.ini 2>/dev/null journalctl -u myapp.service -n 20 --no-pager | grep -iE "prepared|temp table"
- Как исправить
- Либо перейдите на режим на сеанс, либо отключите подготовленные запросы в приложении. Оба решения рабочие, выбор зависит от нагрузки.
- Почему происходит
- Число соединений к базе ограничено. При исчерпании клиенты ждут, и приложение видит таймауты.
- Как проверить
-
Посмотрите состояние пула.
psql -h 127.0.0.1 -p 6432 -U pgbouncer -c 'SHOW POOLS' 2>/dev/null | head sudo grep -iE '^(max_client_conn|default_pool_size)' /etc/pgbouncer/pgbouncer.ini 2>/dev/null
- Как исправить
- Согласуйте размер пула с числом соединений базы и нагрузкой приложения. Пул меньше нужного превращается в узкое место.
- Почему происходит
- Часть соединений идёт мимо пула, и число соединений к базе оказывается больше расчётного.
- Как проверить
-
Посмотрите, куда подключается приложение.
sudo ss -tnp | grep -E ":5432|:6432" | head systemctl show myapp.service -p Environment | tr " " "\n" | grep -i host
- Как исправить
- Направьте все соединения через пул. Смешение прямых соединений и пула сводит на нет смысл ограничения.
Пример вывода
Подготовленный запрос не найден после возврата соединения в пул. Пример показательный: он собран на тестовой машине специально для этой страницы, а не взят из чужого журнала.
myapp[11800]: ERROR: prepared statement "stmt_1" does not exist (SQLSTATE 26000)
pgbouncer[11810]: C-0x55: app/app@10.0.0.9:51422 closing because: client unexpected eof (age=0s)
$ grep ^pool_mode /etc/pgbouncer/pgbouncer.ini
pool_mode = transaction
Связанные ошибки
- PostgreSQL: too many clients already База отказывает в подключениях: исчерпан max_connections. Как считать значение и зачем пул соединений.
- MySQL: Too many connections База отказывает в новых подключениях: исчерпан max_connections или предел дескрипторов службы.
- Connection refused в журнале службы Соединение отклонено: служба не может подключиться к базе, кешу или другому сервису. Порядок запуска, адрес, брандмауэр.
- База временных рядов не запускается после обновления Обновление сменило пользователя или расположение данных: служба не может открыть свой каталог.
- База не запускается после переноса каталога данных Перенос данных на другой раздел не работает: профиль защиты и настройки службы указывают на прежний путь.
- Запись в Redis отказывает: узел работает как копия Служба работает, чтение идёт, запись отклоняется: узел находится в роли копии и не принимает изменения.
- Приложение не стартует: блокировка миграций базы Служба зависает или падает на применении миграций: осталась блокировка после прерванного запуска.
- Apache: Invalid command — не включён модуль Apache не запускается: директива требует модуль, который не подключён. Как найти нужный модуль и включить.
Где встречается чаще всего
Источники
- Документация PgBouncer: режимы пула
-
Воспроизведено на тестовой машине, systemd 255 (Ubuntu 24.04)
Воспроизведено подготовленным запросом при режиме пула на транзакцию.