Чи є тайм-аут для простоїв з'єднань PostgreSQL?


94
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 хвилин.


як ви підключаєтесь до БД? socketTimeout може бути тим, що ви шукаєте.
— Doon

У нас є ця застаріла веб-програма Pylons, і ми використовували SQLAlchemy, але, мабуть, не використовували її належним чином. Я не пам’ятаю. Ми намагаємось усунути витік. socketTimeoutЗ документа, схоже, це повністю закриває з'єднання з БД. Я намагаюся закрити кожну неробочу діяльність, і лічильник запускається, як тільки встановлено з'єднання.
— user1012451


@ user1012451 Коли ви говорите "закрити кожен простій" - ви маєте на увазі припинити <IDLE> in transactionсеанси, залишивши сеанс запущеним, але в <IDLE>стані? Іншими словами, розірвати транзакцію, але не сеанс? (Проголосовало проти: незрозуміле питання)
— Крейг Рінгер,

@CraigRinger через деякий час ми досягаємо максимального підключення до клієнта. Щоб вирішити це, ми повинні перезапустити веб-програму, яка змушує також перезапустити postgresql. Це знищить усі зв’язки. Коли ми бачимо їх idleназавжди, ми запитуємо, чи можемо ми встановити час очікування для кожного з’єднання / сеансу (я, чесно кажучи, не знаю правильної термінології, вибачте). Якщо транзакція займає 5 хвилин для звичайної веб-програми, щось має бути не так ....
— user1012451

Відповіді:


118

Здається, у вашому додатку витік з’єднання, оскільки він не може закрити об’єднані з’єднання . У вас виникають проблеми не лише із <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?
— Henley Chiu

@HenleyChiu Я не розумію, чому ні, хоча я спеціально не перевіряв.
— Крейг Рінгер,

1
Запуск цього, здається, вбив мого процесу відправника WAL
— Джозефа Персі

@CraigRinger навіть підключення psql вважається бездіяльним з'єднанням. І чому спочатку потрібно розірвати зв’язок простою. У мене є тривалий код, який встановлює зв'язок з pg, виконує деяку операцію dml, а потім чекає повідомлення через чергу, а потім виконує ще деяку операцію dml. навіть тоді зв'язок з поштовими відправленнями є idle. чому я повинен закривати його.
— Вірен

72

У PostgreSQL 9.6 є нова опція, idle_in_transaction_session_timeoutяка повинна виконати те, що ви описуєте. Ви можете встановити його за допомогою SETкоманди, наприклад:

SET SESSION idle_in_transaction_session_timeout = '5min';

1
Дуже просто запитувати щось настільки просте, але я взагалі абсолютно новий у базах даних - чи не могли б ви навести дуже базовий приклад того, як користуватися цією функцією?
— sg

Щось подібне у попередніх версіях PostgreSQL ??
— sdsc81

Ні, для попередніх версій потрібно щось подібне до інших відповідей.
— шості

Чи потрібно встановлювати цей параметр при кожному перезапуску бази даних? Або після того, як ви це зробили, ви можете забути про це? Дякую
— fresko

5
SET SESSIONпризначений лише для поточного сеансу (він повернеться за замовчуванням після відкриття нового з’єднання). Ви також можете встановити параметри конфігурації на рівні бази даних, використовуючи, наприклад ALTER DATABASE SET idle_in_transaction_session_timeout = '5min', або використовуючи конфігураційні файли (див. Postgresql.org/docs/current/static/config-setting.html ).
— шості

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, яке я розробив.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.