Instâncias do Tair (Redis OSS-compatible) podem apresentar falhas transitórias devido a instabilidade de rede, interrupções de serviço ou sobrecarga do servidor. Configure mecanismos automáticos de nova tentativa na biblioteca do cliente para lidar com essas falhas.
Causas de falhas temporárias
|
Causa |
Efeito |
|
Failover entre nó primário e réplica |
O Tair monitora a integridade dos nós e aciona um failover quando o nó primário falha. O cliente pode sofrer breves interrupções de conexão em segundos e entrar em estado de somente leitura por até 30 segundos. Esse estado evita perda de dados e gravações duplicadas. Para mais informações, consulte Alta disponibilidade. |
|
Consultas lentas |
Operações com complexidade de tempo O(N) bloqueiam outras requisições e causam falhas temporárias em operações simultâneas do cliente. |
|
Problemas de rede |
Instabilidade na rede e retransmissão de dados entre cliente e servidor provocam falhas intermitentes nas requisições. |
Melhores práticas para novas tentativas
Repita apenas operações idempotentes
Um timeout pode ocorrer em qualquer etapa da execução do comando:
O comando não chegou ao servidor.
O comando chegou ao servidor, mas a execução excedeu o tempo limite.
O comando foi executado no servidor, mas a resposta excedeu o tempo limite.
Como uma operação repetida pode ser executada mais de uma vez, repita apenas operações idempotentes.
Idempotente -- SET a b: A execução deste comando várias vezes sempre produz o mesmo resultado.
Não idempotente -- LPUSH mylist a: A execução deste comando várias vezes adiciona elementos a duplicados à mylist.
Configure contagem e intervalo adequados para novas tentativas
Defina a quantidade de tentativas e o intervalo com base na carga de trabalho:
Poucas tentativas ou intervalo muito longo: A aplicação pode não concluir operações durante falhas transitórias curtas.
Muitas tentativas ou intervalo muito curto: A aplicação consome recursos excessivos e pode sobrecarregar o servidor.
|
Estratégia |
Descrição |
|
Nova tentativa imediata |
Tenta novamente sem atraso. Adequada apenas para falhas com resolução esperada em milissegundos. |
|
Nova tentativa com intervalo fixo |
Aguarda uma duração fixa entre as tentativas. Pode causar picos de requisição quando muitos clientes tentam simultaneamente. |
|
Backoff exponencial |
Dobra o tempo de espera após cada tentativa. Distribui as tentativas ao longo do tempo e reduz a carga no servidor. |
|
Backoff aleatório |
Adiciona variação aleatória ao intervalo de backoff. Evita que múltiplos clientes façam novas tentativas no mesmo instante após um evento de falha compartilhado. |
Evite aninhamento de novas tentativas
O aninhamento de novas tentativas — quando uma operação de repetição aciona outro loop de tentativa — pode causar repetições excessivas ou ilimitadas. Implemente a lógica de nova tentativa em uma única camada da pilha da aplicação.
Registre falhas de nova tentativa em log
Gere logs de nova tentativa no nível WARN. Registre apenas quando a tentativa final falhar, e não em cada tentativa, para evitar ruído nos logs.
Jedis
Use Jedis 4.0.0 ou superior. Os exemplos a seguir usam Jedis 5.0.0.
Adicione a dependência ao arquivo pom.xml:
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>5.0.0</version>
</dependency>
Instância padrão ou cluster em modo proxy (JedisPool)
Para instâncias padrão ou instâncias de cluster em modo proxy, use PooledConnectionProvider com UnifiedJedis.
O exemplo abaixo tenta executar o comando SET até 5 vezes em 10 segundos usando backoff exponencial. Se todas as tentativas falharem, o sistema lança uma exceção.
PooledConnectionProvider provider = new PooledConnectionProvider(HostAndPort.from("127.0.0.1:6379"));
int maxAttempts = 5; // Maximum number of retries
Duration maxTotalRetriesDuration = Duration.ofSeconds(10); // Maximum total retry duration
UnifiedJedis jedis = new UnifiedJedis(provider, maxAttempts, maxTotalRetriesDuration);
try {
System.out.println("set key: " + jedis.set("key", "value"));
} catch (Exception e) {
// The operation failed after maxAttempts retries or after maxTotalRetriesDuration elapsed.
e.printStackTrace();
}
|
Parâmetro |
Valor no exemplo |
Descrição |
|
|
5 |
Número máximo de tentativas. |
|
|
10 segundos |
Duração total máxima para todas as tentativas. As repetições param quando essa duração é excedida, mesmo que |
Instância de cluster em modo de conexão direta (JedisCluster)
Para instâncias de cluster em modo de conexão direta, use JedisCluster. O parâmetro maxAttempts define o número máximo de tentativas e tem 5 como valor padrão. O sistema lança uma exceção se todas as tentativas falharem.
HostAndPort hostAndPort = HostAndPort.from("127.0.0.1:30001");
int connectionTimeout = 5000;
int soTimeout = 2000;
int maxAttempts = 5;
ConnectionPoolConfig config = new ConnectionPoolConfig();
JedisCluster jedisCluster = new JedisCluster(hostAndPort, connectionTimeout, soTimeout, maxAttempts, config);
try {
System.out.println("set key: " + jedisCluster.set("key", "value"));
} catch (Exception e) {
// The operation failed after maxAttempts retries.
e.printStackTrace();
}
|
Parâmetro |
Valor no exemplo |
Padrão |
Descrição |
|
|
5000 |
-- |
Timeout de conexão em milissegundos. |
|
|
2000 |
-- |
Timeout de socket em milissegundos. |
|
|
5 |
5 |
Quantidade máxima de tentativas em caso de falha. |
Redisson
O Redisson oferece dois parâmetros para controlar o comportamento de novas tentativas:
|
Parâmetro |
Padrão |
Descrição |
|
|
3 |
Quantidade de tentativas. |
|
|
1500 ms |
Intervalo entre tentativas, em milissegundos. |
Config config = new Config();
config.useSingleServer()
.setTimeout(1000)
.setRetryAttempts(3)
.setRetryInterval(1500) // ms
.setAddress("redis://127.0.0.1:6379");
RedissonClient connect = Redisson.create(config);
StackExchange.Redis
O StackExchange.Redis suporta apenas novas tentativas de conexão, não de comandos individuais. Use o parâmetro connectRetry para definir o número de tentativas de reconexão.
var conn = ConnectionMultiplexer.Connect("redis0:6380,redis1:6380,connectRetry=3");
|
Parâmetro |
Valor no exemplo |
Descrição |
|
|
3 |
Número de tentativas para a conexão inicial. |
Para lógica de nova tentativa no nível de comando, use uma biblioteca de resiliência como Polly para envolver comandos individuais com políticas de repetição.
Lettuce
O Lettuce não fornece parâmetros para repetir comandos individuais após um timeout. Em vez disso, oferece dois modos de confiabilidade de execução:
|
Modo |
Comportamento |
|
No máximo uma vez |
Cada comando é executado no máximo uma vez. Se o cliente desconectar e reconectar, comandos pendentes podem ser perdidos. |
|
Pelo menos uma vez (padrão) |
Cada comando é executado pelo menos uma vez. O cliente repete comandos para garantir a execução bem-sucedida. Se ocorrer um failover entre nó primário e réplica enquanto o cliente tenta novamente, os comandos de repetição podem se acumular. Após a conclusão do failover, a utilização da CPU da instância pode aumentar abruptamente. |
A configuração autoReconnect determina o modo de execução:
clientOptions.isAutoReconnect() ? Reliability.AT_LEAST_ONCE : Reliability.AT_MOST_ONCE;
Para mais informações, consulte Client-Options e Command execution reliability.