Em uma instância de cluster Redis com N shards de dados, a falha de um único shard aciona um failover entre primário e réplica. Durante o failover — que geralmente dura de alguns segundos a dezenas de segundos — todas as requisições roteadas para esse shard falham. Se o tráfego estiver distribuído uniformemente entre os shards, a taxa teórica de falha será 1/N.
Na prática, a taxa real de falha costuma superar esse valor teórico. As seções a seguir explicam as três causas e como resolver cada uma delas. Os exemplos utilizam uma instância de cluster com dois shards de dados operando em modo proxy.
No modo de conexão direta, apenas comandos multi-key fazem a taxa real de falha exceder 1/N.
Por que a taxa real de falha excede 1/N
As três causas dividem-se em duas camadas:
Camada de protocolo: comandos multi-key que abrangem o shard com falha.
Camada de cliente: clientes assíncronos de conexão única e esgotamento do pool de conexões.
Comandos multi-key atingem o shard com falha
Quando um comando referencia chaves distribuídas por vários shards, a falha de um único shard pode causar a falha de todo o comando, não apenas da parte direcionada ao shard indisponível.
Modo proxy: o proxy divide comandos multi-key em subcomandos e roteia cada um para o shard correspondente pela tabela de roteamento.
Modo de conexão direta: o cliente envia cada subcomando diretamente ao shard correspondente.
Se qualquer subcomando tiver como alvo um shard com falha, toda a requisição falhará, conforme ilustrado abaixo.
Solução: minimize o número de chaves por comando para reduzir o raio de impacto de uma falha de shard.
Clientes de conexão única propagam uma falha para requisições subsequentes
Alguns clientes, como o Lettuce, multiplexam requisições assincronamente em uma única conexão. O Redis Serialization Protocol (RESP) exige que as respostas retornem na mesma ordem de envio das requisições. Se uma requisição intermediária falhar — por exemplo, GET key2 falhar porque o shard de destino está indisponível — o cliente não receberá a resposta de nenhuma requisição enviada posteriormente, mesmo que essas requisições tenham sido bem-sucedidas.
Solução: migre para um cliente com suporte a pool de conexões, como o Jedis.
O esgotamento do pool de conexões bloqueia ou causa falha em novas requisições
Clientes com pool de conexões possuem um número máximo configurável de conexões. Quando todas as conexões estão ocupadas e não há conexões ociosas disponíveis, novas requisições falham ou são bloqueadas, dependendo da configuração blockWhenExhausted.
Considere um cliente Jedis com maxTotal definido como 3 e timeout definido como 2000 ms. Se três requisições GET key2 forem iniciadas em 2 segundos e o shard de destino estiver lento ou sem resposta, as três conexões permanecerão abertas até atingirem o tempo limite. O pool fica esgotado durante os 2 segundos completos. Qualquer nova requisição nesse intervalo falhará imediatamente ou ficará bloqueada até a liberação de uma conexão.
Solução: defina um tamanho adequado para o pool de recursos do JedisPool e reduza o valor de timeout para 200–300 ms, em vez dos 2.000 ms padrão. Um tempo limite mais curto reduz a duração que uma conexão com falha ocupa no pool, permitindo que requisições íntegras prossigam mais rapidamente.