ASP.NET Core: Cân bằng tải phía máy khách gRPC


Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên

Trong bài viết này

  1. Định cấu hình cân bằng tải phía máy khách gRPC
  2. Định cấu hình trình phân giải
  3. Cấu hình bộ cân bằng tải
  4. Định cấu hình thông tin xác thực kênh
  5. Sử dụng cân bằng tải với factory máy khách gRPC
  6. Viết trình phân giải tùy chỉnh và bộ cân bằng tải
  7. Định cấu hình trình phân giải tùy chỉnh và bộ cân bằng tải
  8. Tại sao cân bằng tải lại quan trọng
  9. Tài nguyên bổ sung

Cân bằng tải (load blancing) phía máy khách là một tính năng cho phép máy khách gRPC phân phối tải một cách tối ưu trên các máy chủ có sẵn. Bài viết này thảo luận về cách định cấu hình cân bằng tải phía máy khách để tạo các ứng dụng gRPC hiệu suất cao, có thể mở rộng trong .NET.

Cân bằng tải phía máy khách yêu cầu:

Định cấu hình cân bằng tải phía máy khách gRPC

Cân bằng tải phía máy khách được định cấu hình khi kênh được tạo. Hai thành phần cần cân nhắc khi sử dụng cân bằng tải:

  • Trình phân giải, giải quyết các địa chỉ cho kênh. Trình giải quyết hỗ trợ nhận địa chỉ từ nguồn bên ngoài. Điều này còn được gọi là khám phá dịch vụ.
  • Bộ cân bằng tải tạo kết nối và chọn địa chỉ mà lệnh gọi gRPC sẽ sử dụng.

Việc triển khai tích hợp các bộ phân giải và bộ cân bằng tải được bao gồm trong Grpc.Net.Client. Cân bằng tải cũng có thể được mở rộng bằng cách viết các trình phân giải và cân bằng tải tùy chỉnh .

Địa chỉ, kết nối và trạng thái cân bằng tải khác được lưu trữ trong một thể hiện của GrpcChannel. Một kênh phải được sử dụng lại khi thực hiện lệnh gọi gRPC để cân bằng tải hoạt động chính xác.

Ghi chú

Một số cấu hình cân bằng tải sử dụng tính năng chèn phụ thuộc (DI). Các ứng dụng không sử dụng DI có thể tạo phiên bản ServiceCollection.

Nếu một ứng dụng đã có thiết lập DI, chẳng hạn như trang web ASP.NET Core, thì các kiểu phải được đăng ký với phiên bản DI hiện có. GrpcChannelOptions.ServiceProvider được định cấu hình bằng cách lấy IServiceProvider từ DI.

Định cấu hình trình phân giải

Trình phân giải được định cấu hình bằng địa chỉ mà kênh được tạo. Lược đồ URI của địa chỉ chỉ định trình phân giải.

Cơ chế Kiểu Mô tả
dns DnsResolverFactory Phân giải địa chỉ bằng cách truy vấn tên máy chủ để tìm bản ghi địa chỉ DNS .
static StaticResolverFactory Giải quyết các địa chỉ mà ứng dụng đã chỉ định. Được khuyến nghị nếu ứng dụng đã biết địa chỉ mà nó gọi.

Kênh không gọi trực tiếp URI khớp với trình phân giải. Thay vào đó, một trình phân giải phù hợp sẽ được tạo và sử dụng để phân giải các địa chỉ.

Ví dụ: sử dụng GrpcChannel.ForAddress("dns:///my-example-host", new GrpcChannelOptions { Credentials = ChannelCredentials.Insecure }):

  • Lược đồ dns ánh xạ tới DnsResolverFactory. Một phiên bản mới của trình phân giải DNS được tạo cho kênh.
  • Trình phân giải thực hiện truy vấn DNS my-example-host và nhận được hai kết quả: 127.0.0.100 và 127.0.0.101.
  • Bộ cân bằng tải sử dụng 127.0.0.100:80 và 127.0.0.101:80 để tạo kết nối và thực hiện lệnh gọi gRPC.

DnsResolverFactory

Việc DnsResolverFactory tạo một trình phân giải được thiết kế để lấy địa chỉ từ nguồn bên ngoài. Độ phân giải DNS thường được sử dụng để cân bằng tải trên các phiên bản nhóm có dịch vụ Kubernetes headless.

var channel = GrpcChannel.ForAddress(
    "dns:///my-example-host",
    new GrpcChannelOptions { Credentials = ChannelCredentials.Insecure });
var client = new Greet.GreeterClient(channel);

var response = await client.SayHelloAsync(new HelloRequest { Name = "world" });

Đoạn code trên:

  • Định cấu hình kênh đã tạo bằng địa chỉ dns:///my-example-host.
    • Lược đồ dns ánh xạ tới DnsResolverFactory.
    • my-example-host là tên máy chủ cần giải quyết.
    • Không có cổng nào được chỉ định trong địa chỉ, vì vậy các lệnh gọi gRPC sẽ được gửi đến cổng 80. Đây là cổng mặc định cho các kênh không bảo mật. Một cổng có thể được chỉ định tùy ý sau tên máy chủ. Ví dụ: dns:///my-example-host:8080 định cấu hình các lời gọi gRPC để được gửi đến cổng 8080.
  • Không chỉ định bộ cân bằng tải. Kênh mặc định là bộ cân bằng tải chọn đầu tiên.
  • Bắt đầu lời gọi gRPC SayHello:
    • Trình phân giải DNS lấy địa chỉ cho tên máy chủ my-example-host.
    • Chọn lần thử cân bằng tải đầu tiên để kết nối với một trong các địa chỉ đã được giải quyết.
    • Lời gọi được gửi đến địa chỉ đầu tiên mà kênh kết nối thành công.

Bộ nhớ đệm địa chỉ DNS

Hiệu suất rất quan trọng khi cân bằng tải. Độ trễ của việc phân giải địa chỉ được loại bỏ khỏi lệnh gọi gRPC bằng cách lưu địa chỉ vào bộ nhớ đệm. Trình phân giải sẽ được gọi khi thực hiện lệnh gọi gRPC đầu tiên và các lệnh gọi tiếp theo sẽ sử dụng bộ đệm.

Địa chỉ sẽ tự động được làm mới nếu kết nối bị gián đoạn. Việc làm mới rất quan trọng trong các trường hợp địa chỉ thay đổi trong thời gian chạy. Ví dụ: trong Kubernetes, nhóm được khởi động lại sẽ kích hoạt trình phân giải DNS làm mới và nhận địa chỉ mới của nhóm.

Theo mặc định, trình phân giải DNS được làm mới nếu kết nối bị gián đoạn. Trình phân giải DNS cũng có thể tùy chọn tự làm mới theo định kỳ. Điều này có thể hữu ích để nhanh chóng phát hiện các phiên bản nhóm mới.

services.AddSingleton<ResolverFactory>(
    sp => new DnsResolverFactory(refreshInterval: TimeSpan.FromSeconds(30)));

Đoạn code trên tạo một DnsResolverFactory với khoảng thời gian làm mới và đăng ký nó với tính năng chèn phụ thuộc. Để biết thêm thông tin về cách sử dụng trình phân giải được định cấu hình tùy chỉnh, hãy xem Định cấu hình trình phân giải tùy chỉnh và cân bằng tải.

Factory phân giải tĩnh

Trình phân giải tĩnh được cung cấp bởi StaticResolverFactory. Trình giải quyết này:

  • Không gọi nguồn bên ngoài. Thay vào đó, ứng dụng khách sẽ định cấu hình địa chỉ.
  • Được thiết kế cho các tình huống mà ứng dụng đã biết địa chỉ mà nó gọi.
var factory = new StaticResolverFactory(addr => new[]
{
    new BalancerAddress("localhost", 80),
    new BalancerAddress("localhost", 81)
});

var services = new ServiceCollection();
services.AddSingleton<ResolverFactory>(factory);

var channel = GrpcChannel.ForAddress(
    "static:///my-example-host",
    new GrpcChannelOptions
    {
        Credentials = ChannelCredentials.Insecure,
        ServiceProvider = services.BuildServiceProvider()
    });
var client = new Greet.GreeterClient(channel);

Đoạn code trên:

  • Tạo một file StaticResolverFactory. Factory này biết về hai địa chỉ: localhost:80 và localhost:81.
  • Đăng ký factory với tính năng chèn phụ thuộc (DI).
  • Định cấu hình kênh đã tạo bằng:
    • Địa chỉ static:///my-example-host. Lược đồ static ánh xạ tới một trình phân giải tĩnh.
    • Đặt GrpcChannelOptions.ServiceProvider với nhà cung cấp dịch vụ DI.

Ví dụ này tạo một ServiceCollection mới cho DI. Giả sử một ứng dụng đã có thiết lập DI, chẳng hạn như trang web ASP.NET Core. Trong trường hợp đó, các kiểu phải được đăng ký với phiên bản DI hiện có. GrpcChannelOptions.ServiceProvider được định cấu hình bằng cách lấy IServiceProvider từ DI.

Cấu hình bộ cân bằng tải

Bộ cân bằng tải được chỉ định trong tập tin service config sử dụng ServiceConfig.LoadBalancingConfigs. Hai bộ cân bằng tải được tích hợp sẵn và ánh xạ tới tên cấu hình của bộ cân bằng tải:

Tên Kiểu Mô tả
pick_first PickFirstLoadBalancerFactory Cố gắng kết nối với các địa chỉ cho đến khi kết nối được thực hiện thành công. Tất cả các cuộc gọi gRPC đều được thực hiện cho kết nối thành công đầu tiên.
round_robin RoundRobinLoadBalancerFactory Cố gắng kết nối với tất cả các địa chỉ. Các cuộc gọi gRPC được phân phối trên tất cả các kết nối thành công bằng cách sử dụng logic quay vòng .

service config là tên viết tắt của cấu hình dịch vụ và được thể hiện bằng kiểu ServiceConfig. Có một số cách mà kênh có thể nhận được service config khi định cấu hình bộ cân bằng tải:

  • Một ứng dụng có thể chỉ định service config khi tạo kênh bằng cách sử dụng GrpcChannelOptions.ServiceConfig.
  • Ngoài ra, trình phân giải có thể giải quyết một service config cho một kênh. Tính năng này cho phép một nguồn bên ngoài chỉ định cách người gọi nó thực hiện cân bằng tải. Việc trình phân giải có hỗ trợ giải quyết service config ay không phụ thuộc vào việc triển khai trình phân giải. Tắt tính năng này bằng GrpcChannelOptions.DisableResolverServiceConfig.
  • Nếu không có service config nào được cung cấp hoặc service config không có cấu hình cân bằng tải thì kênh sẽ mặc định là PickFirstLoadBalancerFactory.
var channel = GrpcChannel.ForAddress(
    "dns:///my-example-host",
    new GrpcChannelOptions
    {
        Credentials = ChannelCredentials.Insecure,
        ServiceConfig = new ServiceConfig { LoadBalancingConfigs = { new RoundRobinConfig() } }
    });
var client = new Greet.GreeterClient(channel);

var response = await client.SayHelloAsync(new HelloRequest { Name = "world" });

Đoạn code trên:

  • Chỉ định một RoundRobinLoadBalancerFactory trong service config.
  • Bắt đầu lời gọi gRPC SayHello:
    • DnsResolverFactory tạo một trình phân giải lấy địa chỉ cho tên máy chủ my-example-host.
    • Bộ cân bằng tải quay vòng cố gắng kết nối với tất cả các địa chỉ đã được phân giải.
    • Các lời gọi gRPC được phân bổ đồng đều bằng cách sử dụng logic luân phiên.

Định cấu hình thông tin xác thực kênh

Kênh phải biết liệu các lời gọi gRPC có được gửi bằng bảo mật truyền tải hay không. http và https không còn là một phần của địa chỉ, lược đồ hiện chỉ định một trình phân giải, do đó Credentials phải được định cấu hình trên các tùy chọn kênh khi sử dụng cân bằng tải.

  • ChannelCredentials.SecureSsl - Các lời gọi gRPC được bảo mật bằng Transport Layer Security (TLS). Tương đương với một địa chỉ https
  • ChannelCredentials.Insecure - Lời gọi gRPC không sử dụng bảo mật truyền tải. Tương đương với một địa chỉ http
var channel = GrpcChannel.ForAddress(
    "dns:///my-example-host",
    new GrpcChannelOptions { Credentials = ChannelCredentials.Insecure });
var client = new Greet.GreeterClient(channel);

var response = await client.SayHelloAsync(new HelloRequest { Name = "world" });

Sử dụng cân bằng tải với factory máy khách gRPC

Factory máy khách gRPC có thể được cấu hình để sử dụng cân bằng tải:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddGrpcClient<Greeter.GreeterClient>(o =>
    {
        o.Address = new Uri("dns:///my-example-host");
    })
    .ConfigureChannel(o => o.Credentials = ChannelCredentials.Insecure);

builder.Services.AddSingleton<ResolverFactory>(
    sp => new DnsResolverFactory(refreshInterval: TimeSpan.FromSeconds(30)));

var app = builder.Build();

Đoạn code trên:

Viết trình phân giải tùy chỉnh và bộ cân bằng tải

Bộ cân bằng tải phía máy khách có thể mở rộng:

  • Triển khai Resolver để tạo trình phân giải tùy chỉnh và phân giải địa chỉ từ nguồn dữ liệu mới.
  • Triển khai LoadBalancer để tạo bộ cân bằng tải tùy chỉnh với hành vi cân bằng tải mới.

Quan trọng

Các API được sử dụng để mở rộng tính năng cân bằng tải phía máy khách chỉ mang tính thử nghiệm. Chúng có thể thay đổi mà không cần thông báo trước.

Tạo một trình phân giải tùy chỉnh

Trình phân giải:

  • Triển khai Resolver và được tạo bởi ResolverFactory. Tạo một trình phân giải tùy chỉnh bằng cách triển khai các kiểu này.
  • Chịu trách nhiệm giải quyết các địa chỉ mà bộ cân bằng tải sử dụng.
  • Có thể tùy chọn cung cấp một cấu hình dịch vụ.
public class FileResolver : PollingResolver
{
    private readonly Uri _address;
    private readonly int _port;

    public FileResolver(Uri address, int defaultPort, ILoggerFactory loggerFactory)
        : base(loggerFactory)
    {
        _address = address;
        _port = defaultPort;
    }

    public override async Task ResolveAsync(CancellationToken cancellationToken)
    {
        // Tải JSON từ file trên ổ đĩa và giải tuần tự hóa vào endpoint.
        var jsonString = await File.ReadAllTextAsync(_address.LocalPath);
        var results = JsonSerializer.Deserialize<string[]>(jsonString);
        var addresses = results.Select(r => new BalancerAddress(r, _port)).ToArray();

        // Truyền kết quả ngược trở về kênh.
        Listener(ResolverResult.ForResult(addresses));
    }
}

public class FileResolverFactory : ResolverFactory
{
    // Tạo một FileResolver khi URI có một lược đồ 'file'.
    public override string Name => "file";

    public override Resolver Create(ResolverOptions options)
    {
        return new FileResolver(options.Address, options.DefaultPort, options.LoggerFactory);
    }
}

Trong đoạn code trên:

  • FileResolverFactory thực thi ResolverFactory. Nó ánh xạ tới lược đồ file và tạo ra các thể hiện FileResolver.
  • FileResolver thực thi PollingResolverPollingResolver là kiểu cơ sở trừu tượng giúp dễ dàng triển khai trình phân giải với logic không đồng bộ bằng cách ghi đè ResolveAsync.
  • Trong ResolveAsync:
    • URI file được chuyển đổi thành đường dẫn cục bộ. Ví dụ, file:///c:/addresses.json trở thành c:\addresses.json.
    • JSON được tải từ đĩa và được chuyển đổi thành tập hợp các địa chỉ.
    • Listener được gọi với kết quả để cho kênh biết rằng địa chỉ có sẵn.

Tạo bộ cân bằng tải tùy chỉnh

Bộ cân bằng tải:

  • Triển khai LoadBalancer và được tạo bởi LoadBalancerFactory. Tạo factory và bộ cân bằng tải tùy chỉnh bằng cách triển khai các kiểu này.
  • Được cung cấp địa chỉ từ trình phân giải và tạo các thể hiện của Subchannel.
  • Theo dõi trạng thái về kết nối và tạo file SubchannelPicker. Kênh nội bộ sử dụng bộ chọn để chọn địa chỉ khi thực hiện lệnh gọi gRPC.

SubchannelsLoadBalancer là:

  • Một lớp cơ sở trừu tượng triển khai LoadBalancer.
  • Quản lý việc tạo thể hiện Subchannel từ địa chỉ.
  • Giúp dễ dàng thực hiện chính sách chọn tùy chỉnh trên một tập hợp các kênh phụ.
public class RandomBalancer : SubchannelsLoadBalancer
{
    public RandomBalancer(IChannelControlHelper controller, ILoggerFactory loggerFactory)
        : base(controller, loggerFactory)
    {
    }

    protected override SubchannelPicker CreatePicker(List<Subchannel> readySubchannels)
    {
        return new RandomPicker(readySubchannels);
    }

    private class RandomPicker : SubchannelPicker
    {
        private readonly List<Subchannel> _subchannels;

        public RandomPicker(List<Subchannel> subchannels)
        {
            _subchannels = subchannels;
        }

        public override PickResult Pick(PickContext context)
        {
            // Chọn một kênh phụ tùy chỉnh.
            return PickResult.ForSubchannel(_subchannels[Random.Shared.Next(0, _subchannels.Count)]);
        }
    }
}

public class RandomBalancerFactory : LoadBalancerFactory
{
    // Tạo một RandomBalancer khi tên là 'random'.
    public override string Name => "random";

    public override LoadBalancer Create(LoadBalancerOptions options)
    {
        return new RandomBalancer(options.Controller, options.LoggerFactory);
    }
}

Trong đoạn code trên:

  • RandomBalancerFactory thực thi LoadBalancerFactory. Nó ánh xạ tới tên chính sách random và tạo các thể hiện của RandomBalancer.
  • RandomBalancer thực thi SubchannelsLoadBalancer. Nó tạo ra một RandomPicker để chọn ngẫu nhiên một kênh con.

Định cấu hình trình phân giải tùy chỉnh và bộ cân bằng tải

Bộ phân giải tùy chỉnh và bộ cân bằng tải cần phải được đăng ký với tính năng chèn phụ thuộc (DI) khi chúng được sử dụng. Có một vài sự lựa chon:

  • Nếu một ứng dụng đã sử dụng DI, chẳng hạn như ứng dụng web ASP.NET Core, thì chúng có thể được đăng ký với cấu hình DI hiện có. IServiceProvider có thể được phân giải từ DI và được chuyển đến kênh bằng cách sử dụng GrpcChannelOptions.ServiceProvider.
  • Nếu một ứng dụng không sử dụng DI thì hãy tạo:
var services = new ServiceCollection();
services.AddSingleton<ResolverFactory, FileResolverFactory>();
services.AddSingleton<LoadBalancerFactory, RandomLoadBalancerFactory>();

var channel = GrpcChannel.ForAddress(
    "file:///c:/data/addresses.json",
    new GrpcChannelOptions
    {
        Credentials = ChannelCredentials.Insecure,
        ServiceConfig = new ServiceConfig { LoadBalancingConfigs = { new LoadBalancingConfig("random") } },
        ServiceProvider = services.BuildServiceProvider()
    });
var client = new Greet.GreeterClient(channel);

Đoạn code trên:

  • Tạo ServiceCollection và đăng ký triển khai trình phân giải và cân bằng tải mới.
  • Tạo một kênh được định cấu hình để sử dụng các triển khai mới:
    • ServiceCollection được tích hợp vào một IServiceProvider và được đặt thành GrpcChannelOptions.ServiceProvider.
    • Địa chỉ kênh là file:///c:/data/addresses.json. Lược đồ file ánh xạ tới FileResolverFactory.
    • Tên của bộ cân bằng tải service config là random. Ánh xạ tới RandomLoadBalancerFactory.

Tại sao cân bằng tải lại quan trọng

HTTP/2 ghép nhiều lời gọi trên một kết nối TCP. Nếu gRPC và HTTP/2 được sử dụng với bộ cân bằng tải mạng (NLB), thì kết nối sẽ được chuyển tiếp đến một máy chủ và tất cả lệnh gọi gRPC sẽ được gửi đến một máy chủ đó. Các phiên bản máy chủ khác trên NLB không hoạt động.

Cân bằng tải mạng là một giải pháp phổ biến để cân bằng tải vì chúng nhanh và nhẹ. Ví dụ: Kubernetes theo mặc định sử dụng bộ cân bằng tải mạng để cân bằng kết nối giữa các phiên bản nhóm. Tuy nhiên, bộ cân bằng tải mạng không hiệu quả trong việc phân phối tải khi sử dụng với gRPC và HTTP/2.

Cân bằng tải phía proxy hay phía máy khách?

gRPC và HTTP/2 có thể được cân bằng tải một cách hiệu quả bằng cách sử dụng proxy cân bằng tải ứng dụng hoặc cân bằng tải phía máy khách. Cả hai tùy chọn này đều cho phép các lệnh gọi gRPC riêng lẻ được phân phối trên các máy chủ có sẵn. Quyết định giữa cân bằng tải phía proxy và phía máy khách là một lựa chọn mang tính kiến ​​trúc, có những ưu và nhược điểm riêng.

  • Proxy: các lệnh gọi gRPC được gửi đến proxy, proxy đưa ra quyết định cân bằng tải và lệnh gọi gRPC được gửi đến endpoint cuối cùng. Proxy có trách nhiệm biết về endpoint. Sử dụng proxy sẽ thêm:

    • Một bước nhảy (hop) mạng bổ sung tới các lời gọi gRPC.
    • Độ trễ và tiêu thụ tài nguyên bổ sung.
    • Máy chủ proxy phải được thiết lập và cấu hình chính xác.
  • Cân bằng tải phía máy khách: Máy khách gRPC đưa ra quyết định cân bằng tải khi lời gọi gRPC được bắt đầu. Lời gọi gRPC được gửi trực tiếp đến endpoint cuối cùng. Khi sử dụng cân bằng tải phía máy khách:

    • Máy khách có trách nhiệm biết về các endpoint có sẵn và đưa ra quyết định cân bằng tải.
    • Cần có cấu hình máy khách bổ sung.
    • Các lệnh gọi gRPC cân bằng tải, hiệu suất cao loại bỏ nhu cầu về proxy.

Tài nguyên bổ sung

Nguồn: learn.microsoft.com
» Tiếp: Sử dụng ứng dụng khách gRPC với .NET Standard 2.0
« Trước: Xử lý lỗi tạm thời bằng cách thử lại gRPC
Khóa học qua video:
Lập trình Python All Lập trình C# All SQL Server All Lập trình C All Java PHP HTML5-CSS3-JavaScript
Đăng ký Hội viên
Tất cả các video dành cho hội viên
Copied !!!