Vyrovnávání zatížení na straně klienta gRPC
Poznámka:
Toto není nejnovější verze tohoto článku. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Upozorňující
Tato verze ASP.NET Core se už nepodporuje. Další informace najdete v zásadách podpory .NET a .NET Core. Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Důležité
Tyto informace se týkají předběžného vydání produktu, který může být podstatně změněn před komerčním vydáním. Microsoft neposkytuje žádné záruky, výslovné ani předpokládané, týkající se zde uváděných informací.
Aktuální verzi najdete v tomto článku ve verzi .NET 9.
Autor: James Newton-King
Vyrovnávání zatížení na straně klienta je funkce, která klientům gRPC umožňuje optimálně distribuovat zatížení mezi dostupné servery. Tento článek popisuje, jak nakonfigurovat vyrovnávání zatížení na straně klienta pro vytváření škálovatelných vysoce výkonných aplikací gRPC v .NET.
Vyrovnávání zatížení na straně klienta vyžaduje:
- .NET 5 nebo novější.
Grpc.Net.Client
verze 2.45.0 nebo novější.
Konfigurace vyrovnávání zatížení na straně klienta gRPC
Vyrovnávání zatížení na straně klienta se konfiguruje při vytvoření kanálu. Při použití vyrovnávání zatížení zvažte tyto dvě komponenty:
- Překladač, který přeloží adresy kanálu. Překladači podporují získávání adres z externího zdroje. Označuje se také jako zjišťování služeb.
- Nástroj pro vyrovnávání zatížení, který vytvoří připojení a vybere adresu, kterou použije volání gRPC.
Součástí jsou Grpc.Net.Client
integrované implementace překladačů a nástrojů pro vyrovnávání zatížení . Vyrovnávání zatížení je také možné rozšířit zápisem vlastních překladačů a nástrojů pro vyrovnávání zatížení.
Adresy, připojení a další stav vyrovnávání zatížení se ukládají v GrpcChannel
instanci. Kanál se musí znovu použít při volání gRPC, aby vyrovnávání zatížení fungovalo správně.
Poznámka:
Některá konfigurace vyrovnávání zatížení používá injektáž závislostí (DI). Aplikace, které nepoužívají distanci, můžou vytvořit ServiceCollection instanci.
Pokud aplikace už má nastavení DI, jako je web ASP.NET Core, měly by být typy zaregistrované u existující instance DI. GrpcChannelOptions.ServiceProvider
nástroj
Konfigurace překladače
Překladač je nakonfigurovaný pomocí adresy, se kterou se kanál vytvoří. Schéma identifikátoru URI adresy určuje překladač.
Schéma | Typ | Popis |
---|---|---|
dns |
DnsResolverFactory |
Řeší adresy dotazováním názvu hostitele pro záznamy adres DNS. |
static |
StaticResolverFactory |
Řeší adresy, které aplikace zadala. Doporučuje se, pokud aplikace už zná adresy, které volá. |
Kanál nevolá přímo identifikátor URI, který odpovídá překladače. Místo toho se vytvoří odpovídající překladač a použije se k překladu adres.
Například pomocí :GrpcChannel.ForAddress("dns:///my-example-host", new GrpcChannelOptions { Credentials = ChannelCredentials.Insecure })
- Schéma
dns
se mapuje naDnsResolverFactory
. Pro kanál se vytvoří nová instance překladače DNS. - Překladač vytvoří dotaz DNS a
my-example-host
získá dva výsledky:127.0.0.100
a127.0.0.101
. - Nástroj pro vyrovnávání zatížení používá
127.0.0.100:80
a127.0.0.101:80
vytváří připojení a volá gRPC.
DnsResolverFactory
Vytvoří DnsResolverFactory
překladač navržený pro získání adres z externího zdroje. Překlad DNS se běžně používá k vyrovnávání zatížení nad instancemi podů, které mají bezobslužné služby 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" });
Předchozí kód:
- Nakonfiguruje vytvořený kanál s adresou
dns:///my-example-host
.- Schéma
dns
se mapuje naDnsResolverFactory
. my-example-host
je název hostitele, který se má přeložit.- V adrese není zadaný žádný port, takže volání gRPC se odesílají na port 80. Toto je výchozí port pro nezabezpečené kanály. Port lze volitelně zadat za názvem hostitele. Nakonfiguruje například
dns:///my-example-host:8080
volání gRPC, která se mají posílat na port 8080.
- Schéma
- Nezadá nástroj pro vyrovnávání zatížení. Výchozí nastavení kanálu je výběr prvního nástroje pro vyrovnávání zatížení.
- Spustí volání
SayHello
gRPC:- Překladač DNS získá adresy pro název
my-example-host
hostitele . - Vyberte první pokus o připojení k jedné z vyřešených adres nástrojem pro vyrovnávání zatížení.
- Volání se odešle na první adresu, ke které se kanál úspěšně připojí.
- Překladač DNS získá adresy pro název
Ukládání adres DNS do mezipaměti
Výkon je důležitý při vyrovnávání zatížení. Latence překladu adres je eliminována z volání gRPC ukládáním adres do mezipaměti. Při prvním volání gRPC se vyvolá překladač a následné volání použije mezipaměť.
Adresy se automaticky aktualizují, pokud dojde k přerušení připojení. Aktualizace je důležitá ve scénářích, kdy se adresy mění za běhu. Například v Kubernetes restartovaný pod aktivuje překladač DNS k aktualizaci a získání nové adresy podu.
Ve výchozím nastavení se překladač DNS aktualizuje, pokud dojde k přerušení připojení. Překladač DNS se také může volitelně aktualizovat v pravidelných intervalech. To může být užitečné pro rychlé zjišťování nových instancí podů.
services.AddSingleton<ResolverFactory>(
sp => new DnsResolverFactory(refreshInterval: TimeSpan.FromSeconds(30)));
Předchozí kód vytvoří DnsResolverFactory
interval aktualizace a zaregistruje ho pomocí injektáže závislostí. Další informace o použití vlastního nakonfigurovaného překladače najdete v tématu Konfigurace vlastních překladačů a nástrojů pro vyrovnávání zatížení.
StaticResolverFactory
Statický překladač poskytuje StaticResolverFactory
. Tento překladač:
- Nevolá externí zdroj. Místo toho klientská aplikace nakonfiguruje adresy.
- Je navržená pro situace, kdy aplikace už zná adresy, které volá.
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);
Předchozí kód:
- Vytvoří .
StaticResolverFactory
Tato továrna ví o dvou adresách:localhost:80
alocalhost:81
. - Zaregistruje továrnu pomocí injektáže závislostí (DI).
- Nakonfiguruje vytvořený kanál pomocí:
static:///my-example-host
Adresa . Schémastatic
se mapuje na statický překladač.- Nastaví
GrpcChannelOptions.ServiceProvider
s poskytovatelem služby DI.
V tomto příkladu se vytvoří nová ServiceCollection funkce DI. Předpokládejme, že aplikace už má nastavení DI, jako je web ASP.NET Core. V takovém případě by měly být typy registrovány u existující instance DI. GrpcChannelOptions.ServiceProvider
nástroj
Konfigurace nástroje pro vyrovnávání zatížení
Nástroj pro vyrovnávání zatížení se zadává v service config
kolekci ServiceConfig.LoadBalancingConfigs
. Dva nástroje pro vyrovnávání zatížení jsou integrované a mapované na názvy konfigurace nástroje pro vyrovnávání zatížení:
Name | Typ | Popis |
---|---|---|
pick_first |
PickFirstLoadBalancerFactory |
Pokusí se připojit k adresám, dokud se připojení úspěšně nesvedou. Volání gRPC jsou všechna provedena na první úspěšné připojení. |
round_robin |
RoundRobinLoadBalancerFactory |
Pokusí se připojit ke všem adresám. Volání gRPC se distribuují napříč všemi úspěšnými připojeními pomocí logiky kruhového dotazování . |
service config
je zkratka konfigurace služby a je reprezentována typem ServiceConfig
. Existuje několik způsobů, jak může kanál získat service config
s nakonfigurovaným nástrojem pro vyrovnávání zatížení:
- Aplikace může určit
service config
, kdy je kanál vytvořen pomocíGrpcChannelOptions.ServiceConfig
. - Případně může překladač přeložit
service config
kanál. Tato funkce umožňuje externímu zdroji určit, jak mají volající provádět vyrovnávání zatížení. Jestli překladač podporuje překladačservice config
, závisí na implementaci překladače. Tuto funkci zakažte pomocíGrpcChannelOptions.DisableResolverServiceConfig
funkce . - Pokud není k dispozici,
service config
neboservice config
nemá nakonfigurovaný nástroj pro vyrovnávání zatížení, kanál se ve výchozím nastavení nastaví naPickFirstLoadBalancerFactory
hodnotu .
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" });
Předchozí kód:
- Určuje
RoundRobinLoadBalancerFactory
v souboruservice config
. - Spustí volání
SayHello
gRPC:DnsResolverFactory
vytvoří překladač, který získá adresy pro názevmy-example-host
hostitele .- Nástroj pro vyrovnávání zatížení s kruhovým dotazováním se pokusí připojit ke všem vyřešeným adresám.
- Volání gRPC se distribuují rovnoměrně pomocí logiky kruhového dotazování.
Konfigurace přihlašovacích údajů kanálu
Kanál musí vědět, jestli se volání gRPC odesílají pomocí zabezpečení přenosu. http
a https
už nejsou součástí adresy, schéma teď určuje překladač, takže Credentials
při použití vyrovnávání zatížení musí být nakonfigurované na možnostech kanálu.
ChannelCredentials.SecureSsl
– Volání gRPC jsou zabezpečená protokolem TLS (Transport Layer Security). Ekvivalent adresyhttps
.ChannelCredentials.Insecure
- Volání gRPC nepoužívají zabezpečení přenosu. Ekvivalent adresyhttp
.
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" });
Použití vyrovnávání zatížení s klientskou továrnou gRPC
Klientská továrna gRPC je možné nakonfigurovat tak, aby používala vyrovnávání zatížení:
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();
Předchozí kód:
- Nakonfiguruje klienta s adresou vyrovnávání zatížení.
- Určuje přihlašovací údaje kanálu.
- Zaregistruje typy DI v aplikaci IServiceCollection.
Zápis vlastních překladačů a nástrojů pro vyrovnávání zatížení
Vyrovnávání zatížení na straně klienta je rozšiřitelné:
- Implementujte
Resolver
vytvoření vlastního překladače a překlad adres z nového zdroje dat. - Implementujte
LoadBalancer
vytvoření vlastního nástroje pro vyrovnávání zatížení s novým chováním vyrovnávání zatížení.
Důležité
Rozhraní API používaná k rozšíření vyrovnávání zatížení na straně klienta jsou experimentální. Můžou se změnit bez předchozího upozornění.
Vytvoření vlastního překladače
Překladač:
- Implementuje
Resolver
a je vytvořen pomocí .ResolverFactory
Vytvořte vlastní překladač implementací těchto typů. - Zodpovídá za překlad adres, které nástroj pro vyrovnávání zatížení používá.
- Volitelně může poskytnout konfiguraci služby.
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);
}
}
V předchozím kódu:
FileResolverFactory
implementujeResolverFactory
. Mapuje se nafile
schéma a vytváříFileResolver
instance.FileResolver
implementujePollingResolver
.PollingResolver
je abstraktní základní typ, který usnadňuje implementaci překladače s asynchronní logikou přepsánímResolveAsync
.- V
ResolveAsync
:- Identifikátor URI souboru se převede na místní cestu. Například z
file:///c:/addresses.json
se stanec:\addresses.json
. - JSON se načte z disku a převede se na kolekci adres.
- Zavolá se naslouchací proces s výsledky, aby kanál věděl, že adresy jsou dostupné.
- Identifikátor URI souboru se převede na místní cestu. Například z
Vytvoření vlastního nástroje pro vyrovnávání zatížení
Nástroj pro vyrovnávání zatížení:
- Implementuje
LoadBalancer
a je vytvořen pomocí .LoadBalancerFactory
Pomocí implementace těchto typů vytvořte vlastní nástroj pro vyrovnávání zatížení a továrnu. - Z překladače se zařadí adresy a vytvoří
Subchannel
instance. - Sleduje stav připojení a vytvoří
SubchannelPicker
. Kanál interně používá nástroj pro výběr adres při volání gRPC.
Jedná se o SubchannelsLoadBalancer
:
- Abstraktní základní třída, která implementuje
LoadBalancer
. - Spravuje vytváření
Subchannel
instancí z adres. - Usnadňuje implementaci vlastní zásady výběru v kolekci podkanály.
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);
}
}
V předchozím kódu:
RandomBalancerFactory
implementujeLoadBalancerFactory
. Mapuje se narandom
název zásady a vytváříRandomBalancer
instance.RandomBalancer
implementujeSubchannelsLoadBalancer
. Vytvoří náhodněRandomPicker
vybraný podkanál.
Konfigurace vlastních překladačů a nástrojů pro vyrovnávání zatížení
Vlastní překladače a nástroje pro vyrovnávání zatížení je potřeba při použití zaregistrovat pomocí injektáže závislostí (DI). Existuje několik možností:
- Pokud aplikace už používá DI, například webovou aplikaci ASP.NET Core, může být zaregistrovaná ve stávající konfiguraci DI. Lze IServiceProvider přeložit z di di a předat do kanálu pomocí
GrpcChannelOptions.ServiceProvider
. - Pokud aplikace nepoužívá DI, vytvořte:
- A ServiceCollection s typy zaregistrovanými v něm.
- Poskytovatel služeb používající 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);
Předchozí kód:
ServiceCollection
Vytvoří a zaregistruje nové implementace překladače a nástroje pro vyrovnávání zatížení.- Vytvoří kanál nakonfigurovaný tak, aby používal nové implementace:
ServiceCollection
je součástíIServiceProvider
a nastaven naGrpcChannelOptions.ServiceProvider
hodnotu .- Adresa kanálu je
file:///c:/data/addresses.json
. Schémafile
se mapuje naFileResolverFactory
. service config
název nástroje pro vyrovnávání zatížení jerandom
. Mapuje naRandomLoadBalancerFactory
.
Proč je vyrovnávání zatížení důležité
Http/2 multiplexes multiplex on a single TCP connection. Pokud se gRPC a HTTP/2 používají s nástrojem pro vyrovnávání zatížení sítě (NLB), připojení se přesměruje na server a na jeden server se odešlou všechna volání gRPC. Ostatní instance serveru v vyrovnávání zatížení sítě jsou nečinné.
Nástroje pro vyrovnávání zatížení sítě jsou běžným řešením pro vyrovnávání zatížení, protože jsou rychlé a jednoduché. Kubernetes například ve výchozím nastavení používá nástroj pro vyrovnávání zatížení sítě k vyrovnávání počtu připojení mezi instancemi podů. Nástroje pro vyrovnávání zatížení sítě ale nejsou efektivní při distribuci zatížení při použití s gRPC a HTTP/2.
Vyrovnávání zatížení na straně proxy serveru nebo na straně klienta?
GRPC a HTTP/2 můžou být efektivně vyrovnávat zatížení pomocí proxy serveru nástroje pro vyrovnávání zatížení aplikace nebo vyrovnávání zatížení na straně klienta. Obě tyto možnosti umožňují distribuci jednotlivých volání gRPC napříč dostupnými servery. Rozhodování mezi proxy serverem a vyrovnáváním zatížení na straně klienta je volba architektury. Existují výhody a nevýhody pro každou z nich.
Proxy: Volání gRPC se odesílají na proxy server, proxy provede rozhodnutí o vyrovnávání zatížení a volání gRPC se odešle do konečného koncového bodu. Proxy server zodpovídá za znalost koncových bodů. Použití proxy serveru přidá:
- Další segment směrování sítě na volání gRPC.
- Latence a spotřebovávají další prostředky.
- Proxy server musí být správně nastavený a nakonfigurovaný.
Vyrovnávání zatížení na straně klienta: Klient gRPC rozhoduje o vyrovnávání zatížení při spuštění volání gRPC. Volání gRPC se odešle přímo do koncového koncového bodu. Při použití vyrovnávání zatížení na straně klienta:
- Klient zodpovídá za znalost dostupných koncových bodů a rozhodování o vyrovnávání zatížení.
- Vyžaduje se další konfigurace klienta.
- Vysoce výkonné volání gRPC s vyrovnáváním zatížení eliminují potřebu proxy serveru.