Eu tenho um programa golang que faz computação em dados em vários threads ao mesmo tempo, todos puxando seus dados do Postgres. O número de threads depende de um resultado anterior. Portanto, pode haver centenas de threads tentando extrair dados do Postgres ao mesmo tempo.
A biblioteca sql golang permite especificar um limite de conexão, o que evita que o postgres fique sem memória compartilhada ou conexões livres.
Se eu codificar o número máximo de conexões, ficarei sem conexões quando outra coisa estiver conectada. Por outro lado, se eu codificar um número muito baixo de conexões permitidas do programa golang, o desempenho será limitado desnecessariamente.
Qual seria a melhor maneira de permitir que o programa go use o máximo de conexões possíveis, sem ultrapassar os limites. Imagino que esse número seja variável dependendo do número de outros serviços que estão conectados ao banco de dados naquele momento.
Estou pensando em executar o PgBouncer entre o banco de dados e o programa golang, esperançosamente aceitando todas as conexões do programa golang, permitindo o maior número possível, mas bloqueando o resto até que as conexões fiquem livres. No entanto, não tenho certeza se o PgBouncer faz isso, mas testarei isso a seguir.
Existe talvez outro método de ter um pool de conexões que bloqueará conexões quando nenhuma conexão real estiver livre? Bloquear, não recusar, pois recusar uma conexão significa que terei que adicionar lógica de repetição ao meu programa golang.
Você poderia reescrever isso para ter menos consultas retornando mais linhas cada? Se você iniciar um thread por linha a ser retornado, provavelmente estará introduzindo mais sobrecarga do que removendo.
A menos que "algo mais" seja outro programa golang fazendo o mesmo que o primeiro, ou algo equivalente, então você pode fazer max_connections ser apenas um pouco maior que o tamanho máximo do pool em golang, e você não deve ter um problema. Isso exige que você tenha uma boa idéia de quais são as outras coisas.
Você verificou isso? Ter 300 conexões lutando por 16 CPUs e 4 discos rígidos não vai aumentar a produtividade. Há apenas tanto hardware, e agora você tem que lutar improdutivamente por spinlocks (por exemplo), além de fazer o trabalho real.
Ele pode fazer isso, mas por que seria melhor do que o próprio golang fazer isso? Pode fazer sentido se você puder enviar suas "outras conexões" pelo pgbouncer, mas não pode enviá-las pelo golang. Então você pode ter um pooler que vê tudo. Por outro lado, introduz outra camada de latência em cada viagem de ida e volta da rede. Além de outra camada de complexidade.