Есть ли тайм-аут для неактивных соединений PostgreSQL?

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 минут.

7 ответов

Решение

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

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

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

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

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

В PostgreSQL 9.2 и выше вы можете использовать новый state_change столбец отметки времени и status поле 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.

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

SET SESSION idle_in_transaction_session_timeout = '5min';

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

SELECT
   pg_terminate_backend(procpid)
FROM
   pg_stat_activity
WHERE
   current_query = '<IDLE>'
AND
   now() - query_start > '00:10:00';

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

idle_in_transaction_session_timeout = 30000 (мс)

Существует тайм-аут для разорванных соединений (т. е. из-за сетевых ошибок), который зависит от функции поддержания активности TCP ОС. По умолчанию в Linux разорванные TCP-соединения закрываются примерно через 2 часа (см. sysctl net.ipv4.tcp_keepalive_time).

Также есть тайм-аут на заброшенные транзакции, idle_in_transaction_session_timeoutи на замках, lock_timeout. Рекомендуется установить их в postgresql.conf.

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

Другим вариантом является установка этого значения «tcp_keepalives_idle». Подробнее см. в документации https://www.postgresql.org/docs/10/runtime-config-connection.html .

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

Другие вопросы по тегам