Compartilhar via


Tratamento de falhas transitórias com repetições de gRPC

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 9 deste artigo.

Aviso

Esta versão do ASP.NET Core não tem mais suporte. Para obter mais informações, consulte a Política de Suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Importante

Essas informações relacionam-se ao produto de pré-lançamento, que poderá ser substancialmente modificado antes do lançamento comercial. A Microsoft não oferece nenhuma garantia, explícita ou implícita, quanto às informações fornecidas aqui.

Para a versão atual, consulte a versão .NET 9 deste artigo.

Por James Newton-King

As repetições de gRPC são um recurso que permite que os clientes gRPC repitam automaticamente as chamadas com falha. Este artigo discute como configurar uma política de repetição para tornar aplicativos gRPC resilientes e tolerantes a falhas no .NET.

As repetições de gRPC exigem Grpc.Net.Client versão 2.36.0 ou posterior.

Tratamento de falhas transitórias

As chamadas gRPC podem ser interrompidas por falhas transitórias. As falhas transitórias incluem:

  • Perda momentânea de conectividade de rede.
  • Indisponibilidade temporária de um serviço.
  • Tempos limites atingidos devido à carga do servidor.

Quando uma chamada gRPC é interrompida, o cliente lança uma RpcException com detalhes sobre o erro. O aplicativo cliente deve capturar a exceção e escolher como lidar com o erro.

var client = new Greeter.GreeterClient(channel);
try
{
    var response = await client.SayHelloAsync(
        new HelloRequest { Name = ".NET" });

    Console.WriteLine("From server: " + response.Message);
}
catch (RpcException ex)
{
    // Write logic to inspect the error and retry
    // if the error is from a transient fault.
}

A duplicação da lógica de repetição em um aplicativo é detalhada e propensa a erros. Felizmente, o cliente gRPC do .NET tem um suporte interno para repetições automáticas.

Configurar uma política de repetição de gRPC

Uma política de repetição é configurada uma vez quando um canal gRPC é criado:

var defaultMethodConfig = new MethodConfig
{
    Names = { MethodName.Default },
    RetryPolicy = new RetryPolicy
    {
        MaxAttempts = 5,
        InitialBackoff = TimeSpan.FromSeconds(1),
        MaxBackoff = TimeSpan.FromSeconds(5),
        BackoffMultiplier = 1.5,
        RetryableStatusCodes = { StatusCode.Unavailable }
    }
};

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
    ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
});

O código anterior:

  • Cria um MethodConfig. As políticas de repetição podem ser configuradas por método e os métodos são correspondidos usando a propriedade Names. Esse método é configurado com MethodName.Default, portanto, ele é aplicado a todos os métodos gRPC chamados por esse canal.
  • Configura uma política de repetição. Essa política instrui os clientes a repetir automaticamente as chamadas gRPC que falham com o código de status Unavailable.
  • Configura o canal criado para usar a política de repetição definindo GrpcChannelOptions.ServiceConfig.

Os clientes gRPC criados com o canal repetirão automaticamente as chamadas com falha:

var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(
    new HelloRequest { Name = ".NET" });

Console.WriteLine("From server: " + response.Message);

Quando repetições são válidas

As chamadas são repetidas quando:

  • O código de status com falha corresponde a um valor em RetryableStatusCodes.
  • O número anterior de tentativas é menor que MaxAttempts.
  • A chamada não foi confirmada.
  • O prazo não foi excedido.

Uma chamada gRPC torna-se confirmada em dois cenários:

  • O cliente recebe cabeçalhos de resposta. Os cabeçalhos de resposta são enviados pelo servidor quando ServerCallContext.WriteResponseHeadersAsync é chamado ou quando a primeira mensagem é gravada no fluxo de resposta do servidor.
  • A mensagem de saída do cliente (ou mensagens por fluxo de dados) excedeu o tamanho máximo do buffer do cliente. MaxRetryBufferSize e MaxRetryBufferPerCallSize são configurados no canal.

As chamadas confirmadas não farão repetições, independentemente do código de status ou do número anterior de tentativas.

Chamadas de fluxo de dados

As chamadas de fluxo de dados podem ser usadas com repetições de gRPC, mas há considerações importantes a fazer quando elas são usadas juntas:

  • Streaming de servidor, fluxo de dados bidirecional: os RPCs de fluxo de dados que retornam várias mensagens do servidor não tentarão novamente após o recebimento da primeira mensagem. Os aplicativos devem adicionar lógica adicional para restabelecer manualmente chamadas de fluxo de dados bidirecionais e de servidor.
  • Streaming de cliente, fluxo de dados bidirecional: os RPCs de fluxo de dados que enviam várias mensagens para o servidor não tentarão novamente se as mensagens de saída excederem o tamanho máximo do buffer do cliente. O tamanho máximo do buffer pode ser aumentado com a configuração.

Para obter mais informações, confira Quando as repetições são válidas.

Repita o atraso de retirada

O atraso de retirada entre tentativas de repetição é configurado com InitialBackoff, MaxBackoffe BackoffMultiplier. Mais informações sobre cada opção estão disponíveis na seção opções de repetição de gRPC.

O atraso real entre tentativas de repetição é aleatório. Um atraso aleatório entre 0 e a retirada atual determina quando a próxima tentativa de repetição é feita. Considere que, mesmo com a retirada exponencial configurada, aumentando a retirada atual entre tentativas, o atraso real entre tentativas nem sempre é maior. O atraso é aleatório para evitar que novas tentativas de várias chamadas de formar cluster e potencialmente sobrecarregar o servidor.

Detectar repetições com metadados

As repetições de gRPC podem ser detectadas pela presença de metadados grpc-previous-rpc-attempts. Os metadados grpc-previous-rpc-attempts:

  • São adicionados automaticamente a chamadas repetidas e enviados ao servidor.
  • Value representa o número de tentativas de repetição anteriores.
  • O valor é sempre um inteiro.

Considere o seguinte cenário de repetição:

  1. O cliente faz uma chamada gRPC para o servidor.
  2. O servidor falha e retorna uma resposta de código status repetível.
  3. O cliente repete a chamada gRPC. Como houve uma tentativa anterior, os metadados grpc-previous-rpc-attempts têm um valor de 1. Os metadados são enviados ao servidor com a repetição.
  4. O servidor é bem-sucedido e retorna OK.
  5. O cliente relata êxito. grpc-previous-rpc-attempts está nos metadados de resposta e tem um valor de 1.

Os metadados grpc-previous-rpc-attempts não estão presentes na chamada gRPC inicial, sendo 1 para a primeira repetição e 2 para a segunda repetição e assim por diante.

Opções de repetição de gRPC

A tabela a seguir descreve as opções para configurar políticas de repetição de gRPC:

Opção Descrição
MaxAttempts O número máximo de tentativas de chamada, incluindo a tentativa original. Esse valor é limitado pelo GrpcChannelOptions.MaxRetryAttempts, cujo padrão é 5. Um valor é necessário e deve ser maior que 1.
InitialBackoff O atraso inicial de retirada entre tentativas de repetição. Um atraso aleatório entre 0 e a retirada atual determina quando a próxima tentativa de repetição é feita. Após cada tentativa, o backoff atual é multiplicado por BackoffMultiplier. Um valor é necessário e deve ser maior que zero.
MaxBackoff A retirada máxima coloca um limite superior no crescimento de retirada exponencial. Um valor é necessário e deve ser maior que zero.
BackoffMultiplier A retirada será multiplicada por esse valor após cada tentativa de repetição e aumentará exponencialmente quando o multiplicador for maior que 1. Um valor é necessário e deve ser maior que zero.
RetryableStatusCodes Uma coleção de códigos de status. Uma chamada gRPC que falha com um status correspondente será repetida automaticamente. Para obter mais informações sobre códigos de status, confira Códigos de status e seu uso em gRPC. Pelo menos um código de status repetível é necessário.

Hedging

Hedging é uma estratégia alternativa de repetição. O hedging permite enviar agressivamente várias cópias de uma única chamada gRPC sem esperar por uma resposta. As chamadas gRPC cobertas podem ser executadas várias vezes no servidor e o primeiro resultado bem-sucedido é usado. É importante que a cobertura só esteja habilitada para métodos seguros para execução várias vezes sem efeito adverso.

O hedging tem prós e contras quando comparado com repetições:

  • Uma vantagem do hedging é que ele pode retornar um resultado bem-sucedido mais rapidamente. Ele permite várias chamadas gRPC simultaneamente e será concluído quando o primeiro resultado bem-sucedido estiver disponível.
  • Uma desvantagem do hedging é que ele pode ser um desperdício. Várias chamadas podem ser feitas e todas ter êxito. Somente o primeiro resultado é usado e o rest é descartado.

Configurar uma política de hedging de gRPC

Uma política de cobertura é configurada como uma política de repetição. Observe que uma política de hedging não pode ser combinada com uma política de repetição.

var defaultMethodConfig = new MethodConfig
{
    Names = { MethodName.Default },
    HedgingPolicy = new HedgingPolicy
    {
        MaxAttempts = 5,
        NonFatalStatusCodes = { StatusCode.Unavailable }
    }
};

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
{
    ServiceConfig = new ServiceConfig { MethodConfigs = { defaultMethodConfig } }
});

Opções de hedging de gRPC

A tabela a seguir descreve as opções para configurar políticas de hedging de gRPC:

Opção Descrição
MaxAttempts A política de hedging enviará até esse número de chamadas. MaxAttempts representa o número total de todas as tentativas, incluindo a tentativa original. Esse valor é limitado pelo GrpcChannelOptions.MaxRetryAttempts, cujo padrão é 5. Um valor é necessário e deve igual ou maior que 2.
HedgingDelay A primeira chamada é enviada imediatamente, as chamadas de cobertura subsequentes são atrasadas por esse valor. Quando o atraso é definido como zero ou null, todas as chamadas cobertas são enviadas imediatamente. HedgingDelay é opcional e usa zero como padrão. Um valor deve igual ou maior que zero.
NonFatalStatusCodes Uma coleção de códigos de status que indicam que outras chamadas de hedge ainda podem ter êxito. Se um código de status não fatal for retornado pelo servidor, as chamadas cobertas continuarão. Caso contrário, as solicitações pendentes serão canceladas e o erro será retornado ao aplicativo. Para obter mais informações sobre códigos de status, confira Códigos de status e seu uso em gRPC.

Recursos adicionais