Есть ли тайм-аут для простаивающих соединений PostgreSQL?

98
1 S postgres  5038   876  0  80   0 - 11962 sk_wai 09:57 ?        00:00:00 postgres: postgres my_app ::1(45035) idle                                                                                 
1 S postgres  9796   876  0  80   0 - 11964 sk_wai 11:01 ?        00:00:00 postgres: postgres my_app ::1(43084) idle             

Я их много вижу. Мы пытаемся исправить утечку нашего соединения. Но тем временем мы хотим установить тайм-аут для этих незанятых соединений, возможно, максимум до 5 минут.

user1012451
источник
как вы подключаетесь к БД? socketTimeout может быть тем, что вы ищете.
Doon
У нас есть это устаревшее веб-приложение Pylons, и мы использовали SQLAlchemy, но, очевидно, использовали его неправильно. Не помню. Мы пытаемся устранить утечку. socketTimeoutиз документа похоже, что это полностью закрывает соединение с БД. Я пытаюсь закрыть каждый холостой ход, и счетчик запускается, как только устанавливается соединение.
user1012451 05
@ user1012451 Когда вы говорите «закрывать каждый неактивный» - вы имеете в виду завершить <IDLE> in transactionсеанс, оставив сеанс запущенным, но в <IDLE>состоянии? Другими словами, завершить транзакцию, но не сеанс? (Проголосовано против: неясный вопрос)
Craig Ringer
@CraigRinger через некоторое время мы достигаем максимального клиентского соединения. Чтобы решить эту проблему, мы должны перезапустить веб-приложение, что также заставит перезапустить postgresql. Это уничтожит все связи. Когда мы видим это idleнавсегда, мы спрашиваем, можем ли мы установить тайм-аут для каждого соединения / сеанса (я, честно говоря, не знаю правильной терминологии, извините). Если транзакция занимает 5 минут для обычного веб-приложения, что-то должно быть не так ...
user1012451

Ответы:

120

Похоже, у вас есть утечка соединения в вашем приложении, потому что оно не может закрыть объединенные соединения . У вас проблемы не только с<idle> in transaction сессиями, а со слишком большим количеством подключений в целом.

Удаление подключений не является правильным решением для этого, но это нормальный временный обходной путь.

Вместо того, чтобы перезапускать PostgreSQL для загрузки всех других подключений из базы данных PostgreSQL, см .: Как мне отсоединить всех других пользователей от базы данных postgres? и как удалить базу данных PostgreSQL, если к ней есть активные подключения?. Последний показывает лучший запрос.

Для установки тайм-аутов, как предложил @Doon, см. Как автоматически закрывать простаивающие соединения в PostgreSQL? , который советует вам использовать PgBouncer для прокси для PostgreSQL и управления незанятыми соединениями. Это очень хорошая идея, если у вас есть приложение с ошибками, которое все равно пропускает соединения; Я очень сильно рекомендую настроить PgBouncer.

TCP KeepAlive не будет делать эту работу здесь, потому что приложение все еще подключен и живой, он просто не должно быть.

В PostgreSQL 9.2 и более поздних версиях вы можете использовать новый state_changeстолбец временной метки и stateполе, pg_stat_activityчтобы реализовать сборщик бездействующих соединений. Запустите задание cron примерно так:

SELECT pg_terminate_backend(pid)
    FROM pg_stat_activity
    WHERE datname = 'regress'
      AND pid <> pg_backend_pid()
      AND state = 'idle'
      AND state_change < current_timestamp - INTERVAL '5' MINUTE;

В более старых версиях вам нужно реализовать сложные схемы, которые отслеживают, когда соединение простаивает. Не беспокойся; просто используйте pgbouncer.

Крэйг Рингер
источник
4
Хорошо, но это убьет другие серверные части PgAdmin. Используйте дополнительное условие application_name = ''
Андрей Селиванов
1
Могу ли я запустить pg_terminate_backend, если я использую pgbouncer?
Хенли Чиу
@HenleyChiu Я не понимаю, почему нет, хотя я специально не проверял.
Craig Ringer
1
Запуск этого, похоже, убил мой процесс отправителя WAL
Джозеф Перси,
@CraigRinger, даже если соединение с psql считается неактивным. И зачем в первую очередь закрывать неактивное соединение. У меня есть длительный код, который устанавливает соединение с pg, выполняет некоторую операцию dml, а затем ждет сообщения в очереди, а затем выполняет еще несколько операций dml. Теперь в течение этого периода, то есть пока он ожидает в очереди (для сообщения), как упоминалось выше даже тогда связь с почтовыми отправлениями есть idle. почему я должен его закрыть.
Вирен
73

В PostgreSQL 9.6 есть новая опция, idle_in_transaction_session_timeoutкоторая должна выполнять то, что вы описываете. Вы можете установить его с помощью SETкоманды, например:

SET SESSION idle_in_transaction_session_timeout = '5min';
шости
источник
1
Отстойно спрашивать что-то такое простое, но я новичок в базах данных в целом. Не могли бы вы привести очень простой пример использования этой функции?
SG
Что-нибудь подобное в предыдущих версиях PostgreSQL ??
sdsc81
Нет, для предыдущих версий требуется что-то похожее на другие ответы.
shosti
Вам нужно устанавливать этот параметр при каждом перезапуске базы данных? Или после того, как вы это сделали однажды, вы можете забыть? Спасибо
fresko 08
5
SET SESSIONпредназначен только для текущего сеанса (он вернется к значениям по умолчанию, когда вы откроете новое соединение). Вы также можете установить параметры конфигурации на уровне базы данных, например ALTER DATABASE SET idle_in_transaction_session_timeout = '5min', или используя файлы конфигурации (см. Postgresql.org/docs/current/static/config-setting.html ).
shosti 08
22

В PostgreSQL 9.1 неактивные соединения со следующим запросом. Это помогло мне предотвратить ситуацию, которая потребовала перезапуска базы данных. В основном это происходит с открытыми и некорректными соединениями JDBC.

SELECT
   pg_terminate_backend(procpid)
FROM
   pg_stat_activity
WHERE
   current_query = '<IDLE>'
AND
   now() - query_start > '00:10:00';
срамай
источник
1
pg_terminate_backend присутствует с 8.4
Эндрю Бэнкс
8

если вы используете postgresql 9.6+, то в вашем postgresql.conf вы можете установить

idle_in_transaction_session_timeout = 30000 (мсек)

Бертран Давид
источник
0

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

pifor
источник