Stackexchange.redis: Tolerância a falhas transitórias e discussão de suporte de nova tentativa implícita

Criado em 28 abr. 2016  ·  5Comentários  ·  Fonte: StackExchange/StackExchange.Redis

O problema

Somos usuários intensivos do Cache Redis do Azure; e a plataforma às vezes (por exemplo, uma vez por mês) reinicializa o sistema operacional do host subjacente para atualizações da plataforma, fazendo com que nossa instância de cache redis primária seja desativada. A instância secundária do Azure é executada, mas apenas após um momento de várias falhas de comando.

Quando esses eventos acontecem, os soquetes são desconectados, os comandos falham e os tempos limite ocorrem momentaneamente e o SE.Redis tem o direito de lançar essa exceção.

Aqui está um exemplo das exceções que podemos ver durante esse período:

[RedisConnectionException: SocketFailure em SMEMBERS]
...
Mensagem: [IOException: Incapaz de ler dados da conexão de transporte: Uma conexão existente foi fechada à força pelo host remoto.]
System.Net.Security._SslStream.EndRead (IAsyncResult asyncResult): 174
StackExchange.Redis.PhysicalConnection.EndReading (resultado IAsyncResult): 17
Mensagem: [SocketException: Uma conexão existente foi fechada à força pelo host remoto]
System.Net.Sockets.NetworkStream.EndRead (IAsyncResult asyncResult): 99

E:

Mensagem: [RedisConnectionException: Nenhuma conexão disponível para atender a esta operação: EXEC]
StackExchange.Redis.ConnectionMultiplexer.ThrowFailed [T] (TaskCompletionSource 1 source, Exception unthrownException):0 System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw():12 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task):41 System.Runtime.CompilerServices.TaskAwaiter 1.GetResult (): 11
... código do aplicativo ...

E:

Mensagem: [TimeoutException: Timeout executando EXEC, inst: 1, mgr: Inactive, err: never, queue: 102, qu: 0, qs: 102, qc: 0, wr: 0, wq: 0, in: 0, ar : 0, IOCP: (Ocupado = 0, Livre = 1000, Min = 4, Máx = 1000), TRABALHADOR: (Ocupado = 3, Livre = 32764, Min = 4, Max = 32767), Nome do cliente: RD0003FFAD174E]
StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl T : 34
StackExchange.Redis.RedisTransaction.Execute (sinalizadores CommandFlags): 14

Proposta de solução

Azure, Amazon e outros serviços em nuvem seguem a linha de que as coisas precisam para lidar com falhas temporárias. Os drivers do SQL Azure lidam com isso com suporte de repetição interno no lado do código do aplicativo, mas o driver recomendado (SE.Redis) não tem suporte de repetição de comando para proteger o código do aplicativo dessas falhas temporárias.

Não é um problema fácil de resolver: nem todos os comandos devem necessariamente ser repetidos, pois não são idempotentes (por exemplo, operações INCR) que podem ou não ter sido bem-sucedidas.

Estou me perguntando o que você pensa sobre a melhor forma de abordar uma solução para esse problema.

Suporte de nível de driver por SE.Redis que poderia ter uma opção de "tentativa de comando" que tenta novamente cegamente todos os comandos (ou opcionalmente apenas "comandos idempotentes" como SET ou GET) em qualquer forma de conexão / falha de tempo limite para até X tentativas seria um muito boa solução inicial.

Idealmente, talvez houvesse um comando de nível Redis "Este servidor está fechando" que poderia alertar o driver para pausar o envio de quaisquer comandos por alguns momentos enquanto o secundário subjacente assume o controle seria melhor, mas essa também é uma solução mais coordenada envolvendo a equipe Redis.

Pensamentos?

connection enhancement Azure timeout

Comentários muito úteis

colisão para esta questão.
Procurando orientação sobre como tentar novamente as operações SET ou GET no caso de haver um problema de rede temporário que causa uma SocketException.

Estamos migrando do ServiceStack para o cliente StackExchange e no código que estamos substituindo, que usava o ServiceStack, detectamos exceções e tentamos novamente as operações após um curto thread.sleep. Na maioria das ocasiões, a nova tentativa funcionaria.

Se houver um problema de rede que cause uma System.Net.SocketException, como "Uma conexão estabelecida foi abortada pelo software em sua máquina host" ou "Uma conexão existente foi forçosamente fechada pelo host remoto" StackExchange.Redis tentará novamente automaticamente até que o tempo syncTimeout tenha decorrido?

Se não, há alguma etapa sugerida que deve acontecer entre a falha inicial e uma nova tentativa em nosso código? Tal como:

  • recriar o multiplexador? (Acho que não)
  • esperando um curto período de tempo?
  • chamando Close () e Configure ()?

Apenas para esclarecimento, estou falando sobre problemas de rede ao tentar StringSet ou StringGet. Não ao tentar conectar-se inicialmente ao servidor Redis.

Todos 5 comentários

Há um mecanismo de nova tentativa no SE.Redis, podemos usar as opções abaixo na string de conexão:

abortConnect=false
connectRetry=3000
connectTimeout=600000
syncTimeout=600000

Abaixo está o exemplo de string de conexão:

"contoso.redis.cache.windows.net,abortConnect=false,connectRetry=3000,connectTimeout=600000,syncTimeout=600000,ssl=true,password=weweweweweZNw1L4bIo0DgPxD9ytdwewe="

Usando: StackExchange.Redis e ServiceStack.Redis

Para documentação sobre o parâmetro "connectRetry", encontrei o seguinte:
// RetryTimeout = 3000, (padrão 3000ms) // Para melhorar a resiliência das conexões do cliente, o RedisClient repetirá de forma transparente as operações do Redis com falha devido às exceções de Socket e I / O em um backoff exponencial começando de 10ms até o RetryTimeout de 3000ms. Esses padrões podem ser ajustados com: RedisConfig.DefaultRetryTimeout = 3000; RedisConfig.BackOffMultiplier = 10;

=> Já tenho o mesmo problema algumas vezes. Mas isso era com o valor padrão de "3000ms".

_Isso não resolverá o problema exposto (não é um mecanismo de falha transiante) mas pode ajudar um pouco? ._
Eu estava me perguntando sobre o impacto de alterar esse valor padrão para um maior (5 segundos, por exemplo). Não quero diminuir o desempenho se isso estiver acontecendo em uma taxa maior do que o esperado.

connectRetry especifica o número de tentativas de conexão durante a conexão inicial e não é sobre o tempo, abortConnect especifica se as novas tentativas devem acontecer, connectTimeout e sycTimeout são para tempo limite de operação de conexão e sincronização, respectivamente.

Além disso, você está usando o Cache Redis do Azure e o cliente recomendado para o mesmo é StackExchange.Redis, mas a seção de documentação que você colou acima parece ser de ServiceStack.Redis , confirme qual cliente Redis você está usando.

A discussão original era sobre novas tentativas de operações, não conexões. É meu entendimento que connectRetry , connectTimeout e abortConnect relacionados a tentar novamente a conexão real, não a operação. Tentar novamente as operações get / set seria extremamente útil e, no momento, estou procurando soluções antes de criar uma do zero.

Não consigo encontrar nada sobre syncTimeout .

colisão para esta questão.
Procurando orientação sobre como tentar novamente as operações SET ou GET no caso de haver um problema de rede temporário que causa uma SocketException.

Estamos migrando do ServiceStack para o cliente StackExchange e no código que estamos substituindo, que usava o ServiceStack, detectamos exceções e tentamos novamente as operações após um curto thread.sleep. Na maioria das ocasiões, a nova tentativa funcionaria.

Se houver um problema de rede que cause uma System.Net.SocketException, como "Uma conexão estabelecida foi abortada pelo software em sua máquina host" ou "Uma conexão existente foi forçosamente fechada pelo host remoto" StackExchange.Redis tentará novamente automaticamente até que o tempo syncTimeout tenha decorrido?

Se não, há alguma etapa sugerida que deve acontecer entre a falha inicial e uma nova tentativa em nosso código? Tal como:

  • recriar o multiplexador? (Acho que não)
  • esperando um curto período de tempo?
  • chamando Close () e Configure ()?

Apenas para esclarecimento, estou falando sobre problemas de rede ao tentar StringSet ou StringGet. Não ao tentar conectar-se inicialmente ao servidor Redis.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

BrennanConroy picture BrennanConroy  ·  6Comentários

tombatron picture tombatron  ·  4Comentários

dardar4 picture dardar4  ·  4Comentários

anytime-hxy picture anytime-hxy  ·  4Comentários

sudheergn picture sudheergn  ·  5Comentários