Recentemente eu fiz um teste de carga de uma aplicação python que se conecta ao Redis.

Durante os testes observei que o número de conexões no lado do Redis sempre aumentava com o tempo, além de ser propriamente um número que julguei alto para o que a aplicação faz.

A figura a baixo ilustra três baterias de testes: uma primeira rodada sem otimização, das 11:30 às 12:30; uma segunda rodada, das 12:30 até 13:00 sem nenhuma intervenção; e a terceira, pouco depois das 13:00 até mais ou menos 14hrs, com a otimização.

REDIS otimizado

O grande problema ao ter um número de conexões abertas alta é que este número é limitado.

O número de conexões possíveis é limitado tanto na origem (cliente) quanto no destino (servidor). O problema de ter um número alto é que caso seja necessário conectar outro serviço no mesmo REDIS podemos ter negação de abertura de conexão porque o servidor já abriu todas as portas possíveis. Já do lado cliente, ter o número de conexões abertas alto também limita novos acessos tanto de saída, quanto de entrada (caso vocês esteja desenvolvendo um serviço).

Resolvi este problema para minha aplicação usando o próprio cliente do Redis que estava usando: REDIS-py .

Quando você instância um cliente do REDIS são ofertadas algumas opções de controle de conexão. Destaco dois parâmetros:

  • socket_keepalive
  • max_connections

Eu inicialmente comecei usando o primeiro, socket_keepalive. Ficando da seguinte forma:

from redis import Redis

Redis.from_url(REDIS_HOST, socket_keepalive=True)

Como uso também o Sentinel:

from redis import Redis
from redis.sentinel import Sentinel

sentinel = Sentinel(SENTINEL_HOSTS_, password=password)
master = sentinel.master_for(service, redis_class=Redis, socket_keepalive=True)
slave = sentinel.slave_for(service, redis_class=Redis, socket_keepalive=True)

O parâmetro socket_keepalive faz com que as conexões TCP sejam reutilizadas uma vez aberta. Sem a necessidade de abertura de novas conexões entre o cliente e o REDIS.

Ao usar este parâmetro eu esperava uma melhora no tempo de resposta, uma vez que o cliente não precisaria estabelecer uma nova conexão com Redis. Mas já obtive uma melhora no número de conexões abertas, conforme imagem acima.

Minha expectativa para usar o parâmetro max_connections era alta, mas foi frustrante.

Acreditiva que ao limitar o número máximo de conexões simultâneas teria como resultado algumas poucas dezenas de conexões abertas. Mas passei a ter erros na minha aplicação por que rapidamente preenchia o pool de conexões, inclusive perdendo performance, que para este aplicação é inaceitável.

Testei com 10 conexões, 25, 50, 100, 250, 500. Até que comecei a notar que o número de conexões abertas estava sendo dominado pelo socket_keepalive. Em outras palavras, se eu usasse um número baixo dava erro, se eu usasse um número alto, por mais que eu forcasse minha aplicação o número de conexões abertas não crescia, provavelmente que outros fatores da minha aplicação passaram a ser gargalo.

O tunning de conexões com o Redis foi satisfeito apenas com socket_keepalive.