Nguon: Microsoft Learn · .NET 8.0

Xử lý lỗi tạm thời với gRPC retries (thử lại)

Nguồn: Transient fault handling with gRPC retries

Bởi James Newton-King

gRPC retries (thử lại) là tính năng cho phép gRPC client tự động thử lại các lệnh gọi thất bại. Bài viết này thảo luận cách cấu hình retry policy (chính sách thử lại) để xây dựng các ứng dụng gRPC có khả năng phục hồi và chịu lỗi trong .NET.

gRPC retries yêu cầu Grpc.Net.Client phiên bản 2.36.0 trở lên.

Xử lý lỗi tạm thời

Các lệnh gọi gRPC có thể bị gián đoạn bởi các lỗi tạm thời. Lỗi tạm thời bao gồm:

Khi một lệnh gọi gRPC bị gián đoạn, client ném ra RpcException với chi tiết về lỗi. Ứng dụng client phải bắt exception và chọn cách xử lý lỗi.

csharp
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)
{
    // Viết logic để kiểm tra lỗi và thử lại
    // nếu lỗi xuất phát từ lỗi tạm thời.
}

Việc sao chép logic retry khắp ứng dụng rất dài dòng và dễ gây lỗi. May mắn thay, gRPC client của .NET có hỗ trợ tích hợp sẵn cho tính năng tự động retry.

Cấu hình gRPC retry policy

Retry policy được cấu hình một lần khi tạo gRPC channel:

csharp
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ạn code trên:

Các gRPC client được tạo với channel sẽ tự động thử lại các lệnh gọi thất bại:

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

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

Khi nào retry hợp lệ

Các lệnh gọi được thử lại khi:

Một lệnh gọi gRPC trở thành committed trong hai trường hợp:

Các lệnh gọi đã committed sẽ không retry, bất kể status code hay số lần thử trước đó.

Các lệnh gọi streaming

Các lệnh gọi streaming có thể được sử dụng với gRPC retries, nhưng có những điểm quan trọng cần lưu ý khi dùng chúng cùng nhau:

Để biết thêm thông tin, xem phần Khi nào retry hợp lệ.

Độ trễ backoff khi retry

Độ trễ backoff (thời gian chờ) giữa các lần retry được cấu hình với InitialBackoff, MaxBackoffBackoffMultiplier. Thông tin chi tiết về từng tùy chọn có trong phần gRPC retry options.

Độ trễ thực tế giữa các lần retry được ngẫu nhiên hóa. Một độ trễ ngẫu nhiên giữa 0 và backoff hiện tại xác định khi nào lần retry tiếp theo được thực hiện. Lưu ý rằng ngay cả khi exponential backoff (backoff lũy thừa) được cấu hình, làm tăng backoff hiện tại giữa các lần thử, độ trễ thực tế giữa các lần thử không phải lúc nào cũng lớn hơn. Độ trễ được ngẫu nhiên hóa để ngăn các lần retry từ nhiều lệnh gọi tập trung lại với nhau và có thể làm quá tải server.

Phát hiện retry bằng metadata

gRPC retries có thể được phát hiện thông qua metadata grpc-previous-rpc-attempts. Metadata grpc-previous-rpc-attempts:

Hãy xem xét kịch bản retry sau:

  1. Client thực hiện lệnh gọi gRPC đến server.
  2. Server thất bại và trả về response với status code có thể retry.
  3. Client thử lại lệnh gọi gRPC. Vì có một lần thử trước đó, metadata grpc-previous-rpc-attempts có giá trị là 1. Metadata được gửi đến server cùng với lần retry.
  4. Server thành công và trả về OK.
  5. Client báo cáo thành công. grpc-previous-rpc-attempts có trong metadata response và có giá trị là 1.

Metadata grpc-previous-rpc-attempts không có trong lệnh gọi gRPC ban đầu, là 1 cho lần retry đầu tiên, 2 cho lần retry thứ hai, v.v.

Các tùy chọn gRPC retry

Bảng sau mô tả các tùy chọn để cấu hình gRPC retry policy:

Tùy chọnMô tả
MaxAttemptsSố lần thử tối đa, bao gồm lần thử ban đầu. Giá trị này bị giới hạn bởi GrpcChannelOptions.MaxRetryAttempts mặc định là 5. Giá trị bắt buộc và phải lớn hơn 1.
InitialBackoffĐộ trễ backoff ban đầu giữa các lần retry. Một độ trễ ngẫu nhiên giữa 0 và backoff hiện tại xác định khi nào lần retry tiếp theo được thực hiện. Sau mỗi lần thử, backoff hiện tại được nhân với BackoffMultiplier. Giá trị bắt buộc và phải lớn hơn 0.
MaxBackoffBackoff tối đa đặt giới hạn trên cho sự tăng trưởng exponential backoff. Giá trị bắt buộc và phải lớn hơn 0.
BackoffMultiplierBackoff sẽ được nhân với giá trị này sau mỗi lần retry và sẽ tăng theo cấp số nhân khi hệ số nhân lớn hơn 1. Giá trị bắt buộc và phải lớn hơn 0.
RetryableStatusCodesTập hợp các status code. Một lệnh gọi gRPC thất bại với status code khớp sẽ tự động được thử lại. Để biết thêm thông tin về status code, xem Status codes and their use in gRPC. Cần ít nhất một status code có thể retry.

Hedging (gửi song song)

Hedging là một chiến lược retry thay thế. Hedging cho phép gửi tích cực nhiều bản sao của một lệnh gọi gRPC mà không cần chờ phản hồi. Các lệnh gọi gRPC được hedged có thể được thực thi nhiều lần trên server và kết quả thành công đầu tiên sẽ được sử dụng. Điều quan trọng là hedging chỉ nên được bật cho các method an toàn khi thực thi nhiều lần mà không có tác động xấu.

Hedging có ưu điểm và nhược điểm khi so sánh với retries:

Cấu hình gRPC hedging policy

Hedging policy được cấu hình giống như retry policy. Lưu ý rằng hedging policy không thể kết hợp với retry policy.

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

Các tùy chọn gRPC hedging

Bảng sau mô tả các tùy chọn để cấu hình gRPC hedging policy:

Tùy chọnMô tả
MaxAttemptsHedging policy sẽ gửi tối đa số lệnh gọi này. MaxAttempts biểu thị tổng số tất cả các lần thử, bao gồm cả lần thử ban đầu. Giá trị này bị giới hạn bởi GrpcChannelOptions.MaxRetryAttempts mặc định là 5. Giá trị bắt buộc và phải từ 2 trở lên.
HedgingDelayLệnh gọi đầu tiên được gửi ngay lập tức, các lệnh gọi hedging tiếp theo bị trì hoãn theo giá trị này. Khi độ trễ được đặt thành 0 hoặc null, tất cả các lệnh gọi hedged được gửi ngay lập tức. HedgingDelay là tùy chọn và mặc định là 0. Giá trị phải từ 0 trở lên.
NonFatalStatusCodesTập hợp các status code cho biết các lệnh gọi hedge khác vẫn có thể thành công. Nếu một non-fatal status code được server trả về, các lệnh gọi hedged sẽ tiếp tục. Nếu không, các request đang chờ sẽ bị hủy và lỗi được trả về cho ứng dụng. Để biết thêm thông tin về status code, xem Status codes and their use in gRPC.