penyeimbangan beban sisi klien gRPC
Catatan
Ini bukan versi terbaru dari artikel ini. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Peringatan
Versi ASP.NET Core ini tidak lagi didukung. Untuk informasi selengkapnya, lihat Kebijakan Dukungan .NET dan .NET Core. Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Penting
Informasi ini berkaitan dengan produk pra-rilis yang mungkin dimodifikasi secara substansial sebelum dirilis secara komersial. Microsoft tidak memberikan jaminan, tersirat maupun tersurat, sehubungan dengan informasi yang diberikan di sini.
Untuk rilis saat ini, lihat versi .NET 9 dari artikel ini.
Oleh James Newton-King
Penyeimbangan beban sisi klien adalah fitur yang memungkinkan klien gRPC mendistribusikan beban secara optimal di seluruh server yang tersedia. Artikel ini membahas cara mengonfigurasi penyeimbangan beban sisi klien untuk membuat aplikasi gRPC berkinerja tinggi yang dapat diskalakan di .NET.
Penyeimbangan beban sisi klien memerlukan:
- .NET 5 atau yang lebih baru.
Grpc.Net.Client
versi 2.45.0 atau yang lebih baru.
Mengonfigurasi penyeimbangan beban sisi klien gRPC
Penyeimbangan beban sisi klien dikonfigurasi saat saluran dibuat. Dua komponen yang perlu dipertimbangkan saat menggunakan penyeimbangan beban:
- Resolver, yang menyelesaikan alamat untuk saluran. Resolver mendukung mendapatkan alamat dari sumber eksternal. Ini juga dikenal sebagai penemuan layanan.
- Load balancer, yang membuat koneksi dan memilih alamat yang akan digunakan oleh panggilan gRPC.
Implementasi bawaan resolver dan load balancer disertakan dalam Grpc.Net.Client
. Penyeimbangan beban juga dapat diperluas dengan menulis pemecah masalah kustom dan load balancer.
Alamat, koneksi, dan status penyeimbangan beban lainnya disimpan dalam GrpcChannel
instans. Saluran harus digunakan kembali saat melakukan panggilan gRPC agar penyeimbangan beban berfungsi dengan benar.
Catatan
Beberapa konfigurasi penyeimbangan beban menggunakan injeksi dependensi (DI). Aplikasi yang tidak menggunakan DI dapat membuat ServiceCollection instans.
Jika aplikasi sudah memiliki penyiapan DI, seperti situs web ASP.NET Core, maka jenis harus didaftarkan dengan instans DI yang ada. GrpcChannelOptions.ServiceProvider
dikonfigurasi dengan mendapatkan IServiceProvider dari DI.
Mengonfigurasi pemecah masalah
Resolver dikonfigurasi menggunakan alamat yang dibuat saluran. Skema URI alamat menentukan resolver.
Skema | Tipe | Deskripsi |
---|---|---|
dns |
DnsResolverFactory |
Menyelesaikan alamat dengan mengkueri nama host untuk rekaman alamat DNS. |
static |
StaticResolverFactory |
Menyelesaikan alamat yang telah ditentukan aplikasi. Disarankan jika aplikasi sudah mengetahui alamat yang dipanggilnya. |
Saluran tidak secara langsung memanggil URI yang cocok dengan resolver. Sebagai gantinya, resolver yang cocok dibuat dan digunakan untuk menyelesaikan alamat.
Misalnya, menggunakan GrpcChannel.ForAddress("dns:///my-example-host", new GrpcChannelOptions { Credentials = ChannelCredentials.Insecure })
:
dns
Skema memetakan keDnsResolverFactory
. Instans baru pemecah masalah DNS dibuat untuk saluran.- Resolver membuat kueri DNS untuk
my-example-host
dan mendapatkan dua hasil:127.0.0.100
dan127.0.0.101
. - Load balancer menggunakan
127.0.0.100:80
dan127.0.0.101:80
untuk membuat koneksi dan melakukan panggilan gRPC.
DnsResolverFactory
membuat DnsResolverFactory
resolver yang dirancang untuk mendapatkan alamat dari sumber eksternal. Resolusi DNS umumnya digunakan untuk memuat keseimbangan atas instans pod yang memiliki layanan tanpa kepala Kubernetes.
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" });
Kode sebelumnya:
- Mengonfigurasi saluran yang dibuat dengan alamat
dns:///my-example-host
.dns
Skema memetakan keDnsResolverFactory
.my-example-host
adalah nama host untuk diselesaikan.- Tidak ada port yang ditentukan dalam alamat, sehingga panggilan gRPC dikirim ke port 80. Ini adalah port default untuk saluran yang tidak aman. Port secara opsional dapat ditentukan setelah nama host. Misalnya,
dns:///my-example-host:8080
mengonfigurasi panggilan gRPC untuk dikirim ke port 8080.
- Tidak menentukan load balancer. Saluran default ke load balancer pertama pilihan.
- Memulai panggilan
SayHello
gRPC :- Resolver DNS mendapatkan alamat untuk nama
my-example-host
host . - Pilih penyeimbang muatan pertama yang mencoba menyambungkan ke salah satu alamat yang diselesaikan.
- Panggilan dikirim ke alamat pertama yang berhasil disambungkan oleh saluran.
- Resolver DNS mendapatkan alamat untuk nama
Penembolokan alamat DNS
Performa penting saat penyeimbangan beban. Latensi mengatasi alamat dihilangkan dari panggilan gRPC dengan penembolokan alamat. Resolver akan dipanggil saat melakukan panggilan gRPC pertama, dan panggilan berikutnya menggunakan cache.
Alamat disegarkan secara otomatis jika koneksi terganggu. Penyegaran penting dalam skenario di mana alamat berubah saat runtime. Misalnya, di Kubernetes sebuah pod yang dimulai ulang memicu pemecah masalah DNS untuk merefresh dan mendapatkan alamat baru pod.
Secara default, pemecah masalah DNS disegarkan jika koneksi terganggu. Pemecah masalah DNS juga dapat secara opsional menyegarkan dirinya sendiri pada interval berkala. Ini dapat berguna untuk mendeteksi instans pod baru dengan cepat.
services.AddSingleton<ResolverFactory>(
sp => new DnsResolverFactory(refreshInterval: TimeSpan.FromSeconds(30)));
Kode sebelumnya membuat DnsResolverFactory
dengan interval refresh dan mendaftarkannya dengan injeksi dependensi. Untuk informasi selengkapnya tentang menggunakan pemecah masalah yang dikonfigurasi khusus, lihat Mengonfigurasi pemecah masalah kustom dan load balancer.
StaticResolverFactory
Resolver statis disediakan oleh StaticResolverFactory
. Pemecah masalah ini:
- Tidak memanggil sumber eksternal. Sebagai gantinya, aplikasi klien mengonfigurasi alamat.
- Dirancang untuk situasi di mana aplikasi sudah mengetahui alamat yang dipanggilnya.
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);
Kode sebelumnya:
StaticResolverFactory
Membuat . Pabrik ini tahu tentang dua alamat:localhost:80
danlocalhost:81
.- Mendaftarkan pabrik dengan injeksi dependensi (DI).
- Mengonfigurasi saluran yang dibuat dengan:
- Alamat
static:///my-example-host
.static
Skema memetakan ke resolver statis. GrpcChannelOptions.ServiceProvider
Diatur dengan penyedia layanan DI.
- Alamat
Contoh ini membuat baru ServiceCollection untuk DI. Misalkan aplikasi sudah memiliki penyiapan DI, seperti situs web ASP.NET Core. Dalam hal ini, jenis harus didaftarkan dengan instans DI yang ada. GrpcChannelOptions.ServiceProvider
dikonfigurasi dengan mendapatkan IServiceProvider dari DI.
Mengonfigurasi penyeimbang beban
Load balancer ditentukan dalam service config
menggunakan ServiceConfig.LoadBalancingConfigs
koleksi. Dua load balancer adalah bawaan dan memetakan ke nama konfigurasi load balancer:
Nama | Tipe | Deskripsi |
---|---|---|
pick_first |
PickFirstLoadBalancerFactory |
Mencoba menyambungkan ke alamat hingga koneksi berhasil dibuat. Semua panggilan gRPC dilakukan ke koneksi pertama yang berhasil. |
round_robin |
RoundRobinLoadBalancerFactory |
Mencoba menyambungkan ke semua alamat. Panggilan gRPC didistribusikan di semua koneksi yang berhasil menggunakan logika round-robin . |
service config
adalah singkatan dari konfigurasi layanan dan diwakili oleh jenisnya ServiceConfig
. Ada beberapa cara saluran bisa mendapatkan dengan load balancer yang service config
dikonfigurasi:
- Aplikasi dapat menentukan
service config
kapan saluran dibuat menggunakanGrpcChannelOptions.ServiceConfig
. - Atau, resolver dapat menyelesaikan
service config
untuk saluran. Fitur ini memungkinkan sumber eksternal untuk menentukan bagaimana pemanggilnya harus melakukan penyeimbangan beban. Apakah resolver mendukung penyelesaianservice config
tergantung pada implementasi resolver. Nonaktifkan fitur ini denganGrpcChannelOptions.DisableResolverServiceConfig
. - Jika tidak
service config
disediakan, atau tidak memiliki load balancer yang dikonfigurasiservice config
, saluran default kePickFirstLoadBalancerFactory
.
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" });
Kode sebelumnya:
RoundRobinLoadBalancerFactory
Menentukan diservice config
.- Memulai panggilan
SayHello
gRPC :DnsResolverFactory
membuat resolver yang mendapatkan alamat untuk namamy-example-host
host .- Load balancer round-robin mencoba menyambungkan ke semua alamat yang diselesaikan.
- Panggilan gRPC didistribusikan secara merata menggunakan logika round-robin.
Mengonfigurasi kredensial saluran
Saluran harus mengetahui apakah panggilan gRPC dikirim menggunakan keamanan transportasi. http
dan https
bukan lagi bagian dari alamat, skema sekarang menentukan pemecah masalah, jadi Credentials
harus dikonfigurasi pada opsi saluran saat menggunakan penyeimbangan beban.
ChannelCredentials.SecureSsl
- Panggilan gRPC diamankan dengan Keamanan Lapisan Transportasi (TLS). Setara denganhttps
alamat.ChannelCredentials.Insecure
- Panggilan gRPC tidak menggunakan keamanan transportasi. Setara denganhttp
alamat.
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" });
Menggunakan penyeimbangan beban dengan pabrik klien gRPC
Pabrik klien gRPC dapat dikonfigurasi untuk menggunakan penyeimbangan beban:
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();
Kode sebelumnya:
- Mengonfigurasi klien dengan alamat penyeimbang beban.
- Menentukan kredensial saluran.
- Mendaftarkan jenis DI dengan aplikasi IServiceCollection.
Menulis pemecah masalah kustom dan load balancer
Penyeimbangan beban sisi klien dapat diperluas:
- Terapkan
Resolver
untuk membuat resolver kustom dan mengatasi alamat dari sumber data baru. - Terapkan
LoadBalancer
untuk membuat load balancer kustom dengan perilaku penyeimbangan beban baru.
Penting
API yang digunakan untuk memperluas penyeimbangan beban sisi klien bersifat eksperimental. Mereka dapat berubah tanpa pemberitahuan.
Membuat pemecah masalah kustom
Pemecah masalah:
Resolver
Mengimplementasikan dan dibuat olehResolverFactory
. Buat resolver kustom dengan menerapkan jenis ini.- Bertanggung jawab untuk menyelesaikan alamat yang digunakan load balancer.
- Dapat secara opsional menyediakan konfigurasi layanan.
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)
{
// Load JSON from a file on disk and deserialize into endpoints.
var jsonString = await File.ReadAllTextAsync(_address.LocalPath);
var results = JsonSerializer.Deserialize<string[]>(jsonString);
var addresses = results.Select(r => new BalancerAddress(r, _port)).ToArray();
// Pass the results back to the channel.
Listener(ResolverResult.ForResult(addresses));
}
}
public class FileResolverFactory : ResolverFactory
{
// Create a FileResolver when the URI has a 'file' scheme.
public override string Name => "file";
public override Resolver Create(ResolverOptions options)
{
return new FileResolver(options.Address, options.DefaultPort, options.LoggerFactory);
}
}
Dalam kode sebelumnya:
FileResolverFactory
penerapanResolverFactory
. Ini memetakan kefile
skema dan membuat instansFileResolver
.FileResolver
penerapanPollingResolver
.PollingResolver
adalah jenis dasar abstrak yang memudahkan untuk mengimplementasikan resolver dengan logika asinkron dengan mengambilResolveAsync
alih .- Dalam:
ResolveAsync
- URI file dikonversi ke jalur lokal. Misalnya,
file:///c:/addresses.json
menjadic:\addresses.json
. - JSON dimuat dari disk dan dikonversi menjadi kumpulan alamat.
- Listener dipanggil dengan hasil untuk memberi tahu saluran bahwa alamat tersedia.
- URI file dikonversi ke jalur lokal. Misalnya,
Membuat load balancer kustom
Load balancer:
LoadBalancer
Mengimplementasikan dan dibuat olehLoadBalancerFactory
. Buat load balancer dan pabrik kustom dengan menerapkan jenis ini.- Diberikan alamat dari resolver dan membuat instans
Subchannel
. - Melacak status tentang koneksi dan membuat
SubchannelPicker
. Saluran secara internal menggunakan pemilih untuk memilih alamat saat melakukan panggilan gRPC.
adalah SubchannelsLoadBalancer
:
- Kelas dasar abstrak yang mengimplementasikan
LoadBalancer
. - Mengelola pembuatan
Subchannel
instans dari alamat. - Memudahkan penerapan kebijakan pemilihan kustom atas kumpulan subchannels.
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)
{
// Pick a random subchannel.
return PickResult.ForSubchannel(_subchannels[Random.Shared.Next(0, _subchannels.Count)]);
}
}
}
public class RandomBalancerFactory : LoadBalancerFactory
{
// Create a RandomBalancer when the name is 'random'.
public override string Name => "random";
public override LoadBalancer Create(LoadBalancerOptions options)
{
return new RandomBalancer(options.Controller, options.LoggerFactory);
}
}
Dalam kode sebelumnya:
RandomBalancerFactory
penerapanLoadBalancerFactory
. Ini memetakan kerandom
nama kebijakan dan membuat instansRandomBalancer
.RandomBalancer
penerapanSubchannelsLoadBalancer
. Ini membuatRandomPicker
yang secara acak memilih subsaluran.
Mengonfigurasi resolver kustom dan load balancer
Resolver kustom dan load balancer perlu didaftarkan dengan injeksi dependensi (DI) saat digunakan. Ada beberapa opsi:
- Jika aplikasi sudah menggunakan DI, seperti aplikasi web ASP.NET Core, aplikasi web tersebut dapat didaftarkan dengan konfigurasi DI yang ada. Dapat IServiceProvider diselesaikan dari DI dan diteruskan ke saluran menggunakan
GrpcChannelOptions.ServiceProvider
. - Jika aplikasi tidak menggunakan DI, buat:
- Dengan ServiceCollection jenis yang terdaftar di dalamnya.
- Penyedia layanan menggunakan BuildServiceProvider.
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);
Kode sebelumnya:
ServiceCollection
Membuat dan mendaftarkan implementasi resolver dan load balancer baru.- Membuat saluran yang dikonfigurasi untuk menggunakan implementasi baru:
ServiceCollection
dibangun ke dalamIServiceProvider
dan diatur keGrpcChannelOptions.ServiceProvider
.- Alamat saluran adalah
file:///c:/data/addresses.json
.file
Skema memetakan keFileResolverFactory
. service config
nama load balancer adalahrandom
. Memetakan keRandomLoadBalancerFactory
.
Mengapa penyeimbangan beban penting
Multipleks HTTP/2 beberapa panggilan pada satu koneksi TCP. Jika gRPC dan HTTP/2 digunakan dengan penyeimbang beban jaringan (NLB), koneksi diteruskan ke server, dan semua panggilan gRPC dikirim ke satu server tersebut. Instans server lain pada NLB tidak aktif.
Penyeimbang beban jaringan adalah solusi umum untuk penyeimbangan beban karena cepat dan ringan. Misalnya, Kubernetes secara default menggunakan penyeimbang beban jaringan untuk menyeimbangkan koneksi antar instans pod. Namun, penyeimbang beban jaringan tidak efektif dalam mendistribusikan beban saat digunakan dengan gRPC dan HTTP/2.
Proksi atau penyeimbangan beban sisi klien?
gRPC dan HTTP/2 dapat secara efektif dimuat seimbang menggunakan proksi load balancer aplikasi atau penyeimbangan beban sisi klien. Kedua opsi ini memungkinkan panggilan gRPC individual didistribusikan di seluruh server yang tersedia. Memutuskan antara proksi dan penyeimbangan beban sisi klien adalah pilihan arsitektur. Ada pro dan kontra untuk masing-masing.
Proksi: panggilan gRPC dikirim ke proksi, proksi membuat keputusan penyeimbangan beban, dan panggilan gRPC dikirim ke titik akhir. Proksi bertanggung jawab untuk mengetahui tentang titik akhir. Menggunakan proksi menambahkan:
- Lompatan jaringan tambahan ke panggilan gRPC.
- Latensi dan mengonsumsi sumber daya tambahan.
- Server proksi harus disiapkan dan dikonfigurasi dengan benar.
Penyeimbangan beban sisi klien: Klien gRPC membuat keputusan penyeimbangan beban saat panggilan gRPC dimulai. Panggilan gRPC dikirim langsung ke titik akhir. Saat menggunakan penyeimbangan beban sisi klien:
- Klien bertanggung jawab untuk mengetahui tentang titik akhir yang tersedia dan membuat keputusan penyeimbangan beban.
- Konfigurasi klien tambahan diperlukan.
- Panggilan gRPC berkinerja tinggi dan seimbang beban menghilangkan kebutuhan akan proksi.
Sumber Daya Tambahan:
ASP.NET Core