Condividi tramite


Gestione degli errori temporanei con tentativi gRPC

Nota

Questa non è la versione più recente di questo articolo. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Avviso

Questa versione di ASP.NET Core non è più supportata. Per altre informazioni, vedere Criteri di supporto di .NET e .NET Core. Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Importante

Queste informazioni si riferiscono a un prodotto non definitive che può essere modificato in modo sostanziale prima che venga rilasciato commercialmente. Microsoft non riconosce alcuna garanzia, espressa o implicita, in merito alle informazioni qui fornite.

Per la versione corrente, vedere la versione .NET 8 di questo articolo.

Di James Newton-King

gRPC tentativi è una funzionalità che consente ai client gRPC di ripetere automaticamente le chiamate non riuscite. Questo articolo illustra come configurare un criterio di ripetizione dei tentativi per rendere le app gRPC resilienti a tolleranza di errore in .NET.

I tentativi gRPC richiedono Grpc.Net.Client versione 2.36.0 o successiva.

Gestione degli errori temporanei

Le chiamate gRPC possono essere interrotte da errori temporanei. Gli errori temporanei includono:

  • Perdita momentanea della connettività di rete.
  • Indisponibilità temporanea di un servizio.
  • Timeout dovuti al carico del server.

Quando una chiamata gRPC viene interrotta, il client genera un oggetto RpcException con i dettagli sull'errore. L'app client deve intercettare l'eccezione e scegliere come gestire l'errore.

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.
}

La duplicazione della logica di ripetizione dei tentativi in un'app è dettagliata e soggetta a errori. Fortunatamente, il client gRPC .NET ha un supporto predefinito per i tentativi automatici.

Configurare un criterio di ripetizione dei tentativi gRPC

Un criterio di ripetizione dei tentativi viene configurato una volta quando viene creato un canale gRPC:

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 } }
});

Il codice precedente:

  • Crea un oggetto MethodConfig. I criteri di ripetizione dei tentativi possono essere configurati per metodo e i metodi corrispondono usando la Names proprietà . Questo metodo è configurato con MethodName.Default, quindi viene applicato a tutti i metodi gRPC chiamati da questo canale.
  • Configura un criterio di ripetizione dei tentativi. Questo criterio indica ai client di ripetere automaticamente le chiamate gRPC che hanno esito negativo con il codice Unavailabledi stato .
  • Configura il canale creato per l'uso dei criteri di ripetizione dei tentativi impostando GrpcChannelOptions.ServiceConfig.

I client gRPC creati con il canale ritentano automaticamente le chiamate non riuscite:

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

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

Quando i tentativi sono validi

Le chiamate vengono ritentate quando:

  • Il codice di stato con errori corrisponde a un valore in RetryableStatusCodes.
  • Il numero precedente di tentativi è minore di MaxAttempts.
  • La chiamata non è stata eseguita correttamente.
  • La scadenza non è stata superata.

Una chiamata gRPC viene sottoposta a commit in due scenari:

  • Il client riceve le intestazioni di risposta. Le intestazioni di risposta vengono inviate dal server quando ServerCallContext.WriteResponseHeadersAsync viene chiamato o quando il primo messaggio viene scritto nel flusso di risposta del server.
  • Il messaggio in uscita del client (o i messaggi se lo streaming) ha superato le dimensioni massime del buffer del client. MaxRetryBufferSize e MaxRetryBufferPerCallSize sono configurati nel canale.

Le chiamate di cui è stato eseguito il commit non eseguiranno nuovi tentativi, indipendentemente dal codice di stato o dal numero precedente di tentativi.

Chiamate in streaming

Le chiamate di streaming possono essere usate con i tentativi gRPC, ma esistono considerazioni importanti quando vengono usate insieme:

  • Streaming del server, streaming bidirezionale: i controller di dominio di streaming che restituiscono più messaggi dal server non riprovano dopo la ricezione del primo messaggio. Le app devono aggiungere logica aggiuntiva per ristabilire manualmente le chiamate di streaming bidirezionali e del server.
  • Streaming client bidirezionale : i controller di controllo di streaming che inviano più messaggi al server non riprovano se i messaggi in uscita hanno superato le dimensioni massime del buffer del client. Le dimensioni massime del buffer possono essere aumentate con la configurazione.

Per altre informazioni, vedere Quando i tentativi sono validi.

Ritardo di ripetizione dei tentativi di backoff

Il ritardo di backoff tra i tentativi di ripetizione è configurato con InitialBackoff, MaxBackoffe BackoffMultiplier. Altre informazioni su ogni opzione sono disponibili nella sezione opzioni di ripetizione dei tentativi gRPC.

Il ritardo effettivo tra i tentativi è casuale. Un ritardo casuale compreso tra 0 e il backoff corrente determina quando viene effettuato il tentativo successivo. Si consideri che anche con il backoff esponenziale configurato, aumentando il backoff corrente tra i tentativi, il ritardo effettivo tra i tentativi non è sempre maggiore. Il ritardo è casuale per evitare tentativi da più chiamate da clustering insieme e potenzialmente sovraccarico del server.

Rilevare i tentativi con i metadati

I tentativi gRPC possono essere rilevati dalla presenza di grpc-previous-rpc-attempts metadati. Metadati grpc-previous-rpc-attempts :

  • Viene aggiunto automaticamente alle chiamate ripetute e inviate al server.
  • Value rappresenta il numero di tentativi precedenti.
  • Il valore è sempre un numero intero.

Si consideri lo scenario di ripetizione dei tentativi seguente:

  1. Il client effettua una chiamata gRPC al server.
  2. Il server ha esito negativo e restituisce una risposta di codice di stato ritentabile.
  3. Il client ritenta la chiamata gRPC. Poiché è stato eseguito un tentativo precedente, grpc-previous-rpc-attempts i metadati hanno un valore pari 1a . I metadati vengono inviati al server con il nuovo tentativo.
  4. Il server ha esito positivo e restituisce OK.
  5. Il client segnala l'esito positivo. grpc-previous-rpc-attemptsè nei metadati della risposta e ha il valore .1

I grpc-previous-rpc-attempts metadati non sono presenti nella chiamata gRPC iniziale, è 1 per il primo tentativo, 2 per il secondo tentativo e così via.

Opzioni di ripetizione dei tentativi gRPC

Nella tabella seguente vengono descritte le opzioni per la configurazione dei criteri di ripetizione dei tentativi gRPC:

Opzione Descrizione
MaxAttempts Numero massimo di tentativi di chiamata, incluso il tentativo originale. Questo valore è limitato per impostazione GrpcChannelOptions.MaxRetryAttempts predefinita a 5. Un valore è obbligatorio e deve essere maggiore di 1.
InitialBackoff Ritardo di backoff iniziale tra i tentativi. Un ritardo casuale compreso tra 0 e il backoff corrente determina quando viene effettuato il tentativo successivo. Dopo ogni tentativo, il backoff corrente viene moltiplicato per BackoffMultiplier. Un valore è obbligatorio e deve essere maggiore di zero.
MaxBackoff Il backoff massimo pone un limite superiore alla crescita esponenziale del backoff. Un valore è obbligatorio e deve essere maggiore di zero.
BackoffMultiplier Il backoff verrà moltiplicato per questo valore dopo ogni tentativo di ripetizione e aumenterà in modo esponenziale quando il moltiplicatore è maggiore di 1. Un valore è obbligatorio e deve essere maggiore di zero.
RetryableStatusCodes Raccolta di codici di stato. Una chiamata gRPC che non riesce con uno stato corrispondente verrà ritentata automaticamente. Per altre informazioni sui codici di stato, vedere Codici di stato e il relativo uso in gRPC. È necessario almeno un codice di stato riprovabile.

Hedging

L'hedging è una strategia alternativa di ripetizione dei tentativi. L'hedging consente di inviare in modo aggressivo più copie di una singola chiamata gRPC senza attendere una risposta. Le chiamate gRPC hedged possono essere eseguite più volte nel server e viene usato il primo risultato riuscito. È importante che l'hedging sia abilitato solo per i metodi sicuri per l'esecuzione più volte senza effetti negativi.

L'hedging presenta vantaggi e svantaggi rispetto ai tentativi:

  • Un vantaggio dell'hedging è che potrebbe restituire un risultato riuscito più velocemente. Consente più chiamate gRPC simultanee e verrà completato quando è disponibile il primo risultato riuscito.
  • Uno svantaggio dell'hedging è che può essere sprecato. È possibile effettuare più chiamate e tutte le chiamate hanno esito positivo. Viene utilizzato solo il primo risultato e vengono rest eliminati.

Configurare un criterio di hedging gRPC

Un criterio di hedging è configurato come un criterio di ripetizione dei tentativi. Si noti che un criterio di hedging non può essere combinato con un criterio di ripetizione dei tentativi.

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 } }
});

Opzioni di hedging gRPC

La tabella seguente descrive le opzioni per la configurazione dei criteri di hedging gRPC:

Opzione Descrizione
MaxAttempts Il criterio di hedging invierà fino a questo numero di chiamate. MaxAttempts rappresenta il numero totale di tutti i tentativi, incluso il tentativo originale. Questo valore è limitato per impostazione GrpcChannelOptions.MaxRetryAttempts predefinita a 5. Un valore è obbligatorio e deve essere 2 o superiore.
HedgingDelay La prima chiamata viene inviata immediatamente, le successive chiamate di hedging vengono ritardate da questo valore. Quando il ritardo è impostato su zero o null, tutte le chiamate siepi vengono inviate immediatamente. HedgingDelay è facoltativo e il valore predefinito è zero. Un valore deve essere zero o maggiore.
NonFatalStatusCodes Una raccolta di codici di stato che indicano altre chiamate di copertura può comunque avere esito positivo. Se un codice di stato non irreversibile viene restituito dal server, le chiamate con copertura continueranno. In caso contrario, le richieste in sospeso verranno annullate e l'errore restituito all'app. Per altre informazioni sui codici di stato, vedere Codici di stato e il relativo uso in gRPC.

Risorse aggiuntive