Подтвердить что ты не робот

Django ORM отправляет бездействующие соединения в DB Postgres

В последнее время мое приложение Django часто терпит крах из-за ошибок подключения к базе данных:

OperationalError: FATAL:  sorry, too many clients already

Когда я перехожу в базу данных приложения, я вижу, что на самом деле существует почти 100 открытых соединений, все с одним и тем же запросом (выполняемым ORM Django) и все в состоянии idle.

Я вручную делал SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle';, но я недоумеваю, почему это происходит. Может ли кто-нибудь пролить свет на то, что здесь происходит?

Настройки базы данных Django не отклоняются от значений по умолчанию (я не определил CONN_MAX_AGE или что-то в этом роде).

Что может быть причиной этого? Я не делаю никаких продвинутых запросов Django. Это что-то, что можно решить с помощью настройки Django или, возможно, некоторой конфигурации PostgreSQL? Любые советы приветствуются.

4b9b3361

Ответ 1

видимо, вы не отключите. Использование db.close_connection() после завершения запроса поможет. Также, если я получу это правильно, CONN_MAX_AGE может помочь некоторое короткое значение. И рассмотрите возможность использования некоторого пула сеансов, например pgbouncer для соединений django. Таким образом, если у вас слишком много подключений, он будет ждать (или повторно использовать предыдущий, в зависимости от конфигурации), а не прерывать выполнение с ошибкой...

update: объяснение, почему я предлагаю его

из документов

каждый поток поддерживает свое собственное соединение, ваша база данных должна поддерживать по крайней мере, столько одновременных соединений, сколько у вас есть рабочие потоки.

Итак, если у вас больше потоков, то postgres max_connections, вы получите упомянутую ошибку. Каждый поток может повторно использовать соединение, если CONN_MAX_AGE не прошел. Ваш параметр равен 0, поэтому соединение должно быть закрыто после завершения запроса, но вы видите 100 незанятых соединений. Поэтому они не закрываются. Большое количество соединений означает, что они также не используются повторно (логика: если бы у вас было бы 100 параллельных запросов, они бы не все простаивали, и если у вас их так много, они не используются повторно - открытие нового). Поэтому я думаю, что django не закрывает их как промитированные - поэтому CONN_MAX_AGE, установленный в 0, не работает в вашем коде. Поэтому я предлагаю использовать db.close_connection() для принудительного отключения и установки CONN_MAX_AGE на некоторое небольшое значение, которое может изменить поведение.

Ответ 2

Лучше всего догадаться без каких-либо подробностей, но если это тот же запрос, и все они без дела, похоже, что вы делаете какое-то асинхронное программирование, и вы зашли в тупик, и в частности ваш тупик проявляется сам в соединениях db становится насыщенным.

Ответ 3

Если вы еще не определили CONN_MAX_AGE, и вы не используете сторонний пул, то это должно быть проблемой где-то в вашем коде или в библиотеке, которую вы используете. По умолчанию Django открывает и закрывает соединение db для каждого запроса. И тот факт, что вы видите простаивающие соединения в pg_stat_activity, не означает, что есть тупик - вместо этого это означает, что что-то открыло эти соединения и не закрыло его.

Сначала я должен убедиться, что эти соединения действительно происходят из Django, например. перезапустить приложение и посмотреть, как он влияет на pg_stat_activity. Если вы подтвердите это, проверьте, не смешивается ли там какой-либо асинхронный или многопроцессорный код, который оставляет висящие потоки/процессы.