Existe um tempo limite para conexões inativas do 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             

Eu vejo muitos deles. Estamos tentando consertar nosso vazamento de conexão. Enquanto isso, queremos definir um tempo limite para essas conexões ociosas, talvez no máximo 5 minutos.

user1012451
fonte
como você está se conectando ao DB? socketTimeout pode ser o que você está procurando.
Doon
Temos este aplicativo da web Pylons legado e usamos o SQLAlchemy, mas aparentemente não o usamos corretamente. Não me lembro. Estamos tentando consertar o vazamento. socketTimeoutdo doc parece que isso fecha totalmente a conexão com o banco de dados. Estou tentando fechar cada inativo, e o contador inicia assim que a conexão é estabelecida.
user1012451
@ user1012451 Quando você diz "feche cada ocioso" - você quer dizer encerrar <IDLE> in transactionsessões, deixando a sessão em execução, mas no <IDLE>estado? Em outras palavras, encerrar a transação, mas não a sessão? (Votação negativa: pergunta pouco clara)
Craig Ringer
@CraigRinger depois de um tempo, alcançamos a conexão máxima do cliente. Para resolver isso, devemos reiniciar o webapp, o que força a reinicialização do postgresql também. Isso acaba com todas as conexões. Quando vemos isso idlepara sempre, estamos perguntando se poderíamos definir um tempo limite em cada conexão / sessão (honestamente, não sei a terminologia correta, desculpe). Se uma transação leva 5 minutos para um aplicativo da web normal, algo deve estar errado ....
user1012451

Respostas:

118

Parece que há um vazamento de conexão em seu aplicativo porque ele não fecha as conexões em pool . Você não está tendo problemas apenas com as <idle> in transactionsessões, mas com muitas conexões no geral.

Eliminar conexões não é a resposta certa para isso, mas é uma solução temporária OK-ish.

Em vez de reiniciar o PostgreSQL para inicializar todas as outras conexões de um banco de dados PostgreSQL, consulte: Como desanexar todos os outros usuários de um banco de dados postgres? e como descartar um banco de dados PostgreSQL se houver conexões ativas para ele? . Este último mostra uma consulta melhor.

Para definir o tempo limite, como @Doon sugeriu, consulte Como fechar conexões ociosas no PostgreSQL automaticamente? , que o aconselha a usar o PgBouncer como proxy para PostgreSQL e gerenciar conexões inativas. Essa é uma idéia muito boa se você tiver um aplicativo com erros que vaza conexões de qualquer maneira; Eu recomendo fortemente configurar o PgBouncer.

Um keepalive TCP não fará o trabalho aqui, porque o aplicativo ainda está conectado e ativo, mas não deveria estar.

No PostgreSQL 9.2 e superior, você pode usar a nova state_changecoluna timestamp e o statecampo de pg_stat_activitypara implementar um reaper de conexão inativo. Faça um cron job executar algo assim:

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;

Em versões anteriores, você precisa implementar esquemas complicados que controlam quando a conexão fica inativa. Nao ligue; basta usar o pgbouncer.

Craig Ringer
fonte
4
Bom, mas vai matar outros back-ends do PgAdmin. Use a condição adicional application_name = ''
Andrew Selivanov,
1
Posso executar o pg_terminate_backend se estiver usando o pgbouncer?
Henley Chiu
@HenleyChiu Não vejo por que não, embora não tenha verificado especificamente.
Craig Ringer
1
Executá-lo parece ter matado meu processo de remetente do WAL
Joseph Persie
@CraigRinger mesmo uma conexão psql é considerada uma conexão inativa. E por que é preciso fechar a conexão ociosa em primeiro lugar. Eu tenho um código de longa execução que estabelece conexão com o pg, realiza algumas operações dml e, em seguida, aguarda a mensagem na fila e, em seguida, realiza mais alguma operação dml. Agora, durante esse período, isto é, enquanto está esperando na fila (por mensagem), conforme mencionado acima mesmo assim, a conexão com postagens é idle. por que devo fechá-lo.
Viren,
72

No PostgreSQL 9.6, há uma nova opção idle_in_transaction_session_timeoutque deve cumprir o que você descreve. Você pode defini-lo usando o SETcomando, por exemplo:

SET SESSION idle_in_transaction_session_timeout = '5min';
Shosti
fonte
1
É uma pena ter que perguntar algo tão simples, mas sou novato em bancos de dados em geral - Você poderia dar um exemplo básico de como usar essa função?
sg
Algo assim nas versões anteriores do PostgreSQL ??
sdsc81
Não, algo semelhante às outras respostas é necessário para as versões anteriores.
shosti
Você precisa definir este parâmetro a cada reinicialização do banco de dados? Ou depois que você fez uma vez, você pode esquecer? Obrigado
fresko
5
SET SESSIONé apenas para a sessão atual (ela voltará ao padrão assim que você abrir uma nova conexão). Você também pode definir parâmetros de configuração em um nível de banco de dados usando ALTER DATABASE SET idle_in_transaction_session_timeout = '5min', por exemplo , ou usando arquivos de configuração (consulte postgresql.org/docs/current/static/config-setting.html ).
shosti
22

No PostgreSQL 9.1, as conexões inativas com a consulta a seguir. Isso me ajudou a evitar a situação que justificava o reinício do banco de dados. Isso acontece principalmente com conexões JDBC abertas e não fechadas corretamente.

SELECT
   pg_terminate_backend(procpid)
FROM
   pg_stat_activity
WHERE
   current_query = '<IDLE>'
AND
   now() - query_start > '00:10:00';
sramay
fonte
1
pg_terminate_backend está disponível desde 8,4
Andrew Banks em
8

se você estiver usando postgresql 9.6+, então em seu postgresql.conf você pode definir

idle_in_transaction_session_timeout = 30000 (mseg)

Bertrand David
fonte
0

Uma possível solução alternativa que permite habilitar o tempo limite da sessão do banco de dados sem uma tarefa externa agendada é usar a extensão pg_timeout que desenvolvi.

pifor
fonte