Есть ли тайм-аут для неактивных соединений 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.