O pgBouncer funciona muito bem, mas ocasionalmente fica indisponível

9

Estou executando o pgBouncer na frente de um banco de dados ocupado do postgres 9. Na maioria das vezes, funciona bem. Mas a cada poucas horas recebo um email de erro do meu aplicativo, com uma exceção do psycopg2:

OperationalError ('não foi possível conectar ao servidor: não é possível atribuir o endereço solicitado. O servidor está executando no host "neo-hulk" e aceitando conexões TCP / IP na porta 6432?')

Este é um aplicativo python com um monte de trabalhadores de aipo executando tarefas. Quando esses erros chegam, eu verifico o pgbouncer db e o tamanho da piscina está dentro dos limites. Após algumas experiências, defina o tamanho máximo do pool para 400 e o tamanho do pool para 200. o modo pool é "session" (as solicitações são na maioria confirmadas automaticamente, quase nenhuma transação).

O que faz o pgBouncer 'desaparecer' assim? é apenas por curtos períodos de tempo (e no total estamos falando de uma pequena quantidade de solicitações em comparação com o grande volume de solicitações que está sendo entregue), mas as solicitações que falham são importantes.

Obrigado!

Harel
fonte
Sistema operacional e versão? Versão do kernel se Linux? Versões exatas do PostgreSQL e PgBouncer? Você executou o PgBouncer no nível do log de depuração e viu se ele relata algo útil?
Craig Ringer
Debian 6. Linux versão 2.6.32-5-amd64 (Debian 2.6.32-48squeeze1) pgbouncer versão 1.5.4 Postgres 9.1. O log não conecta / desconecta, como eu pensei que era um pouco demais, mas não há erros quando esses erros de aplicativo são lançados. O erro vem de pensar psycopg2 não há nenhum servidor db para conversar, embora este problema não existia pré pgbouncer
Harel
11
Hum, o PgBouncer atual e o kernel são antigos, mas bem estáveis. Eu acho que você precisa habilitar o log mais detalhado no PgBouncer -vvve ver se é possível combinar a saída anômala do log com os erros no tempo.
Craig Ringer
Eu fiz um "conjunto detalhado = 1; recarregar;" no shell pgbouncer e não conseguiu encontrar nada fora do comum no log. como é um sistema de produção, não foi possível parar o serviço para executar como um não daemon com -vvv. Espero que eu tenha o mesmo resultado. observe que o erro sugere que não foi possível conectar ao pgbouncer, ou seja, não foi possível encontrá-lo ouvindo nessa porta. Existem milhares de conexões feitas o tempo todo e é estranho que um pequeno número delas falhe assim.
Harel
Complicado; que soa como uma condição de corrida potencial, mas em que / onde ...
Craig Ringer

Respostas:

15

A parte " Não é possível atribuir o endereço solicitado " na mensagem de erro vem da pilha TCP do kernel. Quando encontrado de forma intermitente, isso normalmente significa que o espaço dos soquetes disponíveis está esgotado devido a muitos soquetes no estado de espera ( TIME_WAITou menos provavelmente FIN_WAIT_1ou FIN_WAIT_2)

O intervalo de portas de soquete pode ser gerado por cat /proc/sys/net/ipv4/ip_local_port_range. O valor padrão em um kernel Linux padrão é geralmente 32768 61000.

Você pode verificar o resultado netstat -ton|grep WAITno (s) cliente (s) e no host do pgBouncer quando o sistema estiver ocupado. O -osinalizador mostrará os contadores de tempo limite relacionados aos estados de espera.

Se o número total de soquetes TCP estiver próximo 61000-32768=28232, é provável que a exaustão desse intervalo seja seu problema. Como um soquete fechado gasta 60 segundos no TIME_WAITestado em condições normais, se um host do cliente se conectar mais de 28232 vezes em um minuto, novas conexões falharão com o erro mencionado até que as portas sejam liberadas.

Como primeira solução alternativa, o intervalo de portas TCP pode ser estendido:

 # echo "1025 65535" >/proc/sys/net/ipv4/ip_local_port_range

Se não for satisfatório, verifique as sinalizações tcp_tw_recyclee tcp_tw_reuse, também ajustáveis ​​através de /proc/sys/net/ipv4e sysctl.

Eles são definidos como (de man tcp):

       tcp_tw_recycle (Booleano; padrão: desativado; desde o Linux 2.4)
              Habilite a reciclagem rápida de soquetes TIME_WAIT. Ativando isso
              opção não é recomendada, pois isso causa problemas ao trabalhar
              com NAT (Network Address Translation).

       tcp_tw_reuse (Booleano; padrão: desativado; desde Linux 2.4.19 / 2.6)
              Permitir reutilizar soquetes TIME_WAIT para novas conexões quando estiver
              seguro do ponto de vista do protocolo. Não deve ser alterado sem
              aconselhamento / solicitação de especialistas técnicos.

Pessoalmente, tive sucesso tcp_tw_recycleao enfrentar esse problema com um aplicativo cliente MySQL, mas não tome isso como uma recomendação, pois minha compreensão do TCP é superficial, na melhor das hipóteses.

Daniel Vérité
fonte
11
Essa resposta mostra qualquer bug do entendimento superficial do TCP. Obrigado por isso. Aumentei o intervalo de portas e deixei que funcionasse por um tempo para ver se isso tinha algum efeito. (Eu preciso reiniciar depois que eu defini-lo?)
Harel
Eu acho que o aumento da porta fez isso. Até agora não recebi nenhum erro. Uma contagem aproximada das linhas netstat mostra perto de 20K no cliente, portanto, a partir daí, o limite padrão de 28K não é longo. Obrigado por isso!
Harel
11
Boa! Você quer colocar a configuração em /etc/sysctl.confcomo net.ipv4.ip_local_port_range = 1025 65535ter que persistem entre as reinicializações.
Daniel Vérité
Obrigado. Recebi erros desde então, mas não esse, o que ainda é bom. Deixá-lo funcionar por alguns dias e fará com que o perm mude. Estou feliz isso até agora parece funcionar porque as outras mudanças me assustar :)
Harel