Поделиться через


Обработка временных сбоев с повторными попытками gRPC

Автор: Джеймс Ньютон-Кинг (James Newton-King)

Повторные попытки gRPC — это возможность, которая позволяет клиентам gRPC автоматически повторно выполнять вызовы со сбоем. В этой статье описывается настройка политики повтора для создания устойчивых к сбоям приложений gRPC в .NET.

Для повторных попыток gRPC требуется Grpc.Net.Client версии 2.36.0 или более поздней.

Обработка временных сбоев

Вызовы gRPC могут быть прерваны временными сбоями. К временным сбоям относятся:

  • кратковременная потеря сетевых подключений;
  • временная недоступность службы;
  • истечение времени ожидания из-за загрузки сервера.

При прерывании вызова gRPC в клиенте создается исключение RpcException со сведениями об ошибке. Клиентское приложение должно перехватить исключение и выбрать способ устранения ошибки.

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

Дублирование логики повторных попыток в приложении является более расширенным вариантом, который подвержен ошибкам. К счастью, в клиенте .NET gRPC предусмотрена встроенная поддержка автоматических повторных попыток.

Настройка политики повтора gRPC

Политика повтора настраивается один раз при создании канала 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 } }
});

Предыдущий код:

  • Создает объект MethodConfig. Политики повтора можно настроить для каждого метода, а методы сопоставляются с помощью свойства Names. Этот метод настраивается с помощью MethodName.Default, поэтому он применяется ко всем методам gRPC, вызываемым этим каналом.
  • Настраивает политику повтора. Эта политика предписывает клиентам автоматически повторять вызовы gRPC, которые завершаются сбоем с кодом состояния Unavailable.
  • Настраивает для созданного канала использование политики повтора путем задания GrpcChannelOptions.ServiceConfig.

Клиенты gRPC, созданные с помощью канала, будут автоматически выполнять повторные попытки вызовов со сбоями:

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

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

Ситуации, в которых допускаются повторные попытки

Повторные попытки вызовов выполняются в следующих случаях:

  • Код состояния сбоя соответствует значению в RetryableStatusCodes.
  • Предыдущее число попыток меньше MaxAttempts.
  • Вызов не был зафиксирован.
  • Крайний срок не был превышен.

Вызов gRPC фиксируется в двух сценариях:

  • Клиент получает заголовки ответов. Заголовки ответов отправляются сервером при вызове ServerCallContext.WriteResponseHeadersAsync или при записи первого сообщения в поток ответа сервера.
  • Размер исходящего сообщения клиента (или сообщений в случае потоковой передачи) превысил максимальный размер буфера клиента. MaxRetryBufferSize и MaxRetryBufferPerCallSizeнастраиваются в канале.

Зафиксированные вызовы не будут повторяться независимо от кода состояния или предыдущего числа попыток.

Вызовы потоковой передачи

Вызовы потоковой передачи можно использовать с повторными попытками gRPC, но при их совместном использовании необходимо учитывать следующие важные моменты.

  • Потоковая передача сервера, двунаправленная потоковая передача: RPC потоковой передачи, возвращающие несколько сообщений с сервера, не будут выполнять повторные попытки после получения первого сообщения. В приложениях должна присутствовать дополнительная логика для выполнения повторных вызовов потоковой передачи сервера и двунаправленной потоковой передачи вручную.
  • Потоковая передача клиента, двунаправленная потоковая передача: RPC потоковой передачи, отправляющие несколько сообщений на сервер, не будут выполнять повторные попытки, если размер исходящих сообщений превышает максимальный размер буфера клиента. Максимальный размер буфера можно увеличить в настройках конфигурации.

Дополнительные сведения см. в разделе Ситуации, в которых допускаются повторные попытки.

Задержка между повторными попытками

Задержка между повторными попытками настраивается с помощью параметров InitialBackoff, MaxBackoff и BackoffMultiplier. Дополнительные сведения о каждом параметре доступны в разделе Параметры повторных попыток gRPC.

Фактическая задержка между повторными попытками задается произвольно. Случайное значение задержки между 0 и текущим значением задержки определяет, когда будет выполнена следующая повторная попытка. Учтите, что даже при настроенной экспоненциальной задержке, которая увеличивает текущее значение задержки между попытками, значение фактической задержки между попытками не всегда будет больше. Значение задержки задается произвольно, чтобы не допустить объединения повторных попыток из нескольких вызовов в кластер и потенциальной перегрузки сервера.

Обнаружение повторных попыток с помощью метаданных

Повторные попытки gRPC можно обнаружить с помощью наличия метаданных grpc-previous-rpc-attempts . Метаданные grpc-previous-rpc-attempts :

  • Автоматически добавляется для повторных вызовов и отправляется на сервер.
  • Значение представляет число предыдущих попыток повторных попыток.
  • Значение всегда является целым числом.

Рассмотрим следующий сценарий повтора:

  1. Клиент выполняет вызов gRPC к серверу.
  2. Сервер завершается ошибкой и возвращает возвращаемый ответ кода состояния.
  3. Клиент повторяет вызов gRPC. Так как была одна предыдущая попытка, grpc-previous-rpc-attempts метаданные имеют значение 1. Метаданные отправляются на сервер с повторным повтором.
  4. Сервер завершается успешно и возвращает ОК.
  5. Клиент сообщает об успешном выполнении. grpc-previous-rpc-attempts находится в метаданных ответа и имеет значение 1.

Метаданные grpc-previous-rpc-attempts отсутствуют в первоначальном вызове gRPC, предназначены 1 для первого повтора, 2 для второго повтора и т. д.

Параметры повторных попыток gRPC

В следующей таблице описаны параметры настройки политики повтора gRPC:

Параметр Описание
MaxAttempts Максимальное количество попыток вызова, включая исходную попытку. Это значение ограничено значением параметра GrpcChannelOptions.MaxRetryAttempts, которое по умолчанию равно 5. Значение является обязательным и должно быть больше 1.
InitialBackoff Начальная задержка между повторными попытками. Случайное значение задержки между 0 и текущим значением задержки определяет, когда будет выполнена следующая повторная попытка. После каждой попытки текущее значение задержки умножается на BackoffMultiplier. Значение является обязательным и должно быть больше 0.
MaxBackoff Максимальное значение задержки задает верхний предел для увеличения экспоненциальной задержки. Значение является обязательным и должно быть больше 0.
BackoffMultiplier Задержка будет умножена на это значение после каждой повторной попытки и будет увеличиваться экспоненциально, если множитель больше 1. Значение является обязательным и должно быть больше 0.
RetryableStatusCodes Коллекция кодов состояния. Вызов gRPC, который завершается сбоем с соответствующим состоянием, будет автоматически повторяться. Дополнительные сведения о кодах состояния и их использовании в gRPC см. здесь. Требуется по меньшей мере один повторяемый код состояния.

Хеджирование

Хеджирование — это альтернативная стратегия повторного выполнения. Хеджирование позволяет настойчиво отправлять несколько копий одного вызова gRPC, не дожидаясь ответа. Хеджированные вызовы gRPC можно выполнять на сервере несколько раз, при этом используется первый успешный результат. Важно, чтобы хеджирование было включено только для методов, которые можно выполнять несколько раз без негативного воздействия.

В сравнении с повторными попытками хеджированию присущи свои достоинства и недостатки:

  • Преимуществом хеджирования является более быстрое возвращение успешного результата. Оно предусматривает одновременное выполнение нескольких вызовов gRPC и будет завершено, когда будет доступен первый успешный результат.
  • Недостаток хеджирования заключается в том, что оно может быть нерациональным. Можно выполнить несколько вызовов, и все они будут успешными. Используется только первый результат, а остальные отбрасываются.

Настройка политики хеджирования gRPC

Политика хеджирования настраивается так же, как и политика повтора. Обратите внимание, что политику хеджирования нельзя объединить с политикой повтора.

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

Параметры хеджирования gRPC

В следующей таблице описаны параметры настройки политики хеджирования gRPC:

Параметр Описание
MaxAttempts Политика хеджирования будет отправлять не больше этого числа вызовов. MaxAttempts представляет общее количество всех попыток, включая исходную. Это значение ограничено значением параметра GrpcChannelOptions.MaxRetryAttempts, которое по умолчанию равно 5. Значение является обязательным и должно быть равно 2 или больше.
HedgingDelay При указании этого значения первый вызов будет отправлен незамедлительно, последующие хеджированные вызовы будут отложены. Если для задержки задано значение 0 или null, все хеджированные вызовы отправляются незамедлительно. Параметр HedgingDelay является необязательным и по умолчанию равен нулю. Значение должно быть больше нуля или равно нулю.
NonFatalStatusCodes Коллекция кодов состояния, которая указывает, что другие хеджированные вызовы могут быть успешно выполнены. Если сервер возвращает некритический код состояния, хеджированные вызовы будут по-прежнему отправляться. В противном случае невыполненные запросы будут отменены, и в приложение будет возвращена ошибка. Дополнительные сведения о кодах состояния и их использовании в gRPC см. здесь.

Дополнительные ресурсы