Behandlung vorübergehender Fehler mit gRPC-Wiederholungen

Von James Newton-King

Bei gRPC-Wiederholungen handelt es sich um ein Feature, mit dem gRPC-Clients Aufrufe, die zu einem Fehler geführt haben, automatisch wiederholen können. In diesem Artikel wird erläutert, wie Sie eine Wiederholungsrichtlinie konfigurieren, um robuste, fehlertolerante gRPC-Apps in .NET zu erstellen.

Für gRPC-Wiederholungen ist Version 2.36.0 oder höher von Grpc.Net.Client erforderlich.

Behandeln vorübergehender Fehler

gRPC-Aufrufe können durch vorübergehende Fehler unterbrochen werden. Vorübergehende Fehler sind z. B.:

  • Vorübergehender Verlust der Netzwerkverbindung.
  • Vorübergehende Nichtverfügbarkeit eines Diensts.
  • Timeouts aufgrund der Serverauslastung.

Wenn ein gRPC-Aufruf unterbrochen wird, löst der Client eine RpcException mit Details zum Fehler aus. Die Client-App muss die Ausnahme abfangen und bestimmen, wie der Fehler behandelt werden soll.

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

Das Duplizieren der Wiederholungslogik in einer App wäre umständlich und fehleranfällig. Glücklicherweise verfügt der .NET-gRPC-Client über eine integrierte Unterstützung für automatische Wiederholungen.

Konfigurieren einer gRPC-Wiederholungsrichtlinie

Bei Erstellung eines gRPC-Kanals wird eine Wiederholungsrichtlinie konfiguriert:

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

Der vorangehende Code:

  • Erstellt eine MethodConfig. Wiederholungsrichtlinien können methodenweise konfiguriert werden, und die Methoden werden über die Names Eigenschaft zugeordnet. Diese Methode ist mit MethodName.Default konfiguriert, sodass Sie auf alle von diesem Kanal aufgerufenen gRPC-Methoden angewendet wird.
  • Konfiguriert eine Wiederholungsrichtlinie. Diese Richtlinie weist Clients an, gRPC-Aufrufe, die zu einem Fehler mit dem Statuscode Unavailable führen, automatisch zu wiederholen.
  • Konfiguriert den erstellten Kanal für die Verwendung der Wiederholungsrichtlinie, indem GrpcChannelOptions.ServiceConfig festgelegt wird.

Mit dem Kanal erstellte gRPC-Clients führen bei Aufruffehlern automatisch Wiederholungsversuche durch:

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

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

Unter welchen Umständen Wiederholungsversuche gültig sind

Aufrufe werden wiederholt, wenn:

  • Der Fehlerstatuscode einem Wert in RetryableStatusCodes entspricht.
  • Die vorherige Anzahl von Versuchen kleiner als MaxAttempts ist.
  • Der Aufruf nicht committet wurde.
  • Die Frist nicht überschritten wurde.

Ein gRPC-Aufruf wird in zwei Szenarien committet:

  • Der Client empfängt Antwortheader. Antwortheader werden vom Server gesendet, wenn ServerCallContext.WriteResponseHeadersAsync aufgerufen wird, oder wenn die erste Nachricht in den Serverantwortstream geschrieben wird.
  • Die ausgehende Nachricht des Clients (oder Nachrichten bei Streaming) hat die maximale Puffergröße des Clients überschritten. MaxRetryBufferSize und MaxRetryBufferPerCallSize werden für den Kanal konfiguriert.

Committete Aufrufe werden nicht wiederholt, unabhängig vom Statuscode oder der vorherigen Anzahl von Versuchen.

Streamingaufrufe

Streamingaufrufe können mit gRPC-Wiederholungsversuchen verwendet werden, aber es gibt wichtige Überlegungen, wenn sie gemeinsam verwendet werden:

  • Serverstreaming, bidirektionales Streaming: Streaming-RPCs, die mehrere Nachrichten vom Server zurückgeben, werden nicht wiederholt, nachdem die erste Nachricht empfangen wurde. Apps müssen zusätzliche Logik hinzufügen, um Server- und bidirektionale Streamingaufrufe manuell neu einzurichten.
  • Clientstreaming, bidirektionales Streaming: Streaming-RPCs, die mehrere Nachrichten an den Server senden, werden nicht wiederholt, wenn die ausgehenden Nachrichten die maximale Puffergröße des Clients überschritten haben. Die maximale Puffergröße kann mittels Konfiguration erhöht werden.

Weitere Informationen finden Sie unter Unter welchen Umständen Wiederholungsversuche gültig sind.

Backoffverzögerung für Wiederholungen

Die Backoffverzögerung zwischen Wiederholungsversuchen wird mit InitialBackoff, MaxBackoff und BackoffMultiplier konfiguriert. Weitere Informationen zu den einzelnen Optionen finden Sie im Abschnitt Optionen für gRPC-Wiederholungen.

Die tatsächliche Verzögerung zwischen Wiederholungsversuchen ist zufällig. Eine zufällige Verzögerung zwischen 0 und dem aktuellen Backoff bestimmt, wann der nächste Wiederholungsversuch unternommen wird. Beachten Sie, dass selbst bei einer Konfiguration von exponentiellen Backoffs, durch die der aktuelle Backoff zwischen Versuchen erhöht wird, die tatsächliche Verzögerung zwischen den Versuchen nicht immer größer ist. Die Verzögerung ist zufällig, um zu verhindern, dass Wiederholungen mehrerer Aufrufe zusammentreffen und der Server möglicherweise überlastet wird.

Erkennen von Wiederholungen mit Metadaten

gRPC-Wiederholungen können durch das Vorhandensein von Metadaten für grpc-previous-rpc-attempts erkannt werden. Für Metadaten für grpc-previous-rpc-attempts gilt Folgendes:

  • Werden automatisch zu wiederholten Anrufen hinzugefügt und zum Server gesendet.
  • Der Wert stellt die Anzahl der vorherigen Wiederholungsversuche dar.
  • Der Wert ist stets eine ganze Zahl.

Betrachten Sie folgendes Wiederholungsszenario:

  1. Der Client richtet einen gRPC-Aufruf an den Server.
  2. Der Server meldet einen Fehler und gibt eine wiederholbare Statuscodeantwort zurück.
  3. Der Client wiederholt den gRPC-Aufruf. Da es bereits einen Versuch gab, haben die Metadaten für grpc-previous-rpc-attempts den Wert 1. Metadaten werden mit der Wiederholung zum Server gesendet.
  4. Der Server meldet Erfolg und gibt OK zurück.
  5. Der Client meldet Erfolg. grpc-previous-rpc-attempts ist in den Metadaten der Antwort enthalten und hat den Wert 1.

Die Metadaten von grpc-previous-rpc-attempts sind beim ersten gRPC-Aufruf nicht vorhanden, für den ersten Wiederholungsversuch 1, für den zweiten Wiederholungsversuch 2 usw.

Optionen für gRPC-Wiederholungen

In der folgenden Tabelle werden die Optionen für die Konfiguration von gRPC-Wiederholungsrichtlinien beschrieben:

Option Beschreibung
MaxAttempts Die maximale Anzahl von Aufrufversuchen, einschließlich des ursprünglichen Versuchs. Dieser Wert wird durch GrpcChannelOptions.MaxRetryAttempts mit dem Standardwert 5 begrenzt. Ein Wert ist erforderlich und muss größer als 1 sein.
InitialBackoff Die anfängliche Backoffverzögerung zwischen Wiederholungsversuchen. Eine zufällige Verzögerung zwischen 0 und dem aktuellen Backoff bestimmt, wann der nächste Wiederholungsversuch unternommen wird. Nach jedem Versuch wird der aktuelle Backoff mit BackoffMultiplier multipliziert. Ein Wert ist erforderlich und muss größer als 0 sein.
MaxBackoff Der maximale Backoff stellt eine Obergrenze für die exponentielle Backoffzunahme dar. Ein Wert ist erforderlich und muss größer als 0 sein.
BackoffMultiplier Der Backoff wird nach jedem Wiederholungsversuch mit diesem Wert multipliziert und erhöht sich exponentiell, wenn der Multiplikator größer als 1 ist. Ein Wert ist erforderlich und muss größer als 0 sein.
RetryableStatusCodes Eine Sammlung von Statuscodes. Ein gRPC-Aufruf, bei dem ein Fehler mit dem entsprechenden Status auftritt, wird automatisch wiederholt. Weitere Informationen zu Statuscodes finden Sie unter Statuscodes und deren Verwendung in gRPC. Mindestens ein Statuscode ist erforderlich, bei dem eine Wiederholung möglich ist.

Hedging

Das Hedging stellt eine alternative Wiederholungsstrategie dar. Das Hedging ermöglicht das aggressive Senden mehrerer Kopien eines einzelnen gRPC-Aufrufs, ohne auf eine Antwort zu warten. gRPC-Hedgingaufrufe können mehrmals auf dem Server ausgeführt werden, und das erste erfolgreiche Ergebnis wird verwendet. Es ist wichtig, dass das Hedging nur für Methoden aktiviert wird, die ohne negative Auswirkungen mehrmals ausgeführt werden können.

Das Hedging hat gegenüber Wiederholungen Vor- und Nachteile:

  • Ein Vorteil des Hedgings ist, dass ein erfolgreiches Ergebnis schneller zurückgegeben werden kann. Sie ermöglicht mehrere gleichzeitige gRPC-Aufrufe und wird beendet, wenn das erste erfolgreiche Ergebnis verfügbar ist.
  • Ein Nachteil des Hedgings ist, dass es unnötig Ressourcen verbraucht. Es können mehrere Aufrufe durchgeführt werden, die alle erfolgreich sind. Es wird nur das erste Ergebnis verwendet, und der Rest wird verworfen.

Konfigurieren einer gRPC-Hedgingrichtlinie

Eine Hedgingrichtlinie wird wie eine Wiederholungsrichtlinie konfiguriert. Beachten Sie, dass eine Hedgingrichtlinie nicht mit einer Wiederholungsrichtlinie kombiniert werden kann.

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

Optionen für das gRPC-Hedging

In der folgenden Tabelle werden die Optionen für die Konfiguration von gRPC-Hedgingrichtlinien beschrieben:

Option Beschreibung
MaxAttempts Die Höchstzahl von Aufrufen, die von der Hedgingrichtlinie gesendet werden. MaxAttempts stellt die Gesamtzahl aller Versuche dar, einschließlich des ursprünglichen Versuchs. Dieser Wert wird durch GrpcChannelOptions.MaxRetryAttempts mit dem Standardwert 5 begrenzt. Ein Wert ist erforderlich und muss mindestens 2 betragen.
HedgingDelay Der erste Aufruf wird sofort gesendet, und die nachfolgenden Hedgingaufrufe werden um diesen Wert verzögert. Wenn die Verzögerung auf 0 oder null festgelegt ist, werden alle Hedgingaufrufe sofort gesendet. HedgingDelay ist optional und ist standardmäßig auf 0 (null) festgelegt. Ein Wert muss 0 (null) oder größer sein.
NonFatalStatusCodes Eine Sammlung von Statuscodes, für die gilt, dass andere Hedgingaufrufe möglicherweise trotzdem erfolgreich ausgeführt werden. Wenn vom Server ein Statuscode für einen nicht schwerwiegenden Fehler zurückgegeben wird, werden die Hedgingaufrufe fortgesetzt. Andernfalls werden ausstehende Anforderungen abgebrochen, und der Fehler wird an die App zurückgegeben. Weitere Informationen zu Statuscodes finden Sie unter Statuscodes und deren Verwendung in gRPC.

Zusätzliche Ressourcen