Sdílet prostřednictvím


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:

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.Clientintegrované 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 IServiceProvider from DI.

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 na DnsResolverFactory. 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 a 127.0.0.101.
  • Nástroj pro vyrovnávání zatížení používá 127.0.0.100:80 a 127.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 na DnsResolverFactory.
    • 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.
  • 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í SayHellogRPC:
    • Překladač DNS získá adresy pro název my-example-hosthostitele .
    • 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í.
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 a localhost:81.
  • Zaregistruje továrnu pomocí injektáže závislostí (DI).
  • Nakonfiguruje vytvořený kanál pomocí:
    • static:///my-example-hostAdresa . Schéma static 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 IServiceProvider from DI.

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.DisableResolverServiceConfigfunkce .
  • Pokud není k dispozici, service config nebo service config nemá nakonfigurovaný nástroj pro vyrovnávání zatížení, kanál se ve výchozím nastavení nastaví na PickFirstLoadBalancerFactoryhodnotu .
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 souboru service config.
  • Spustí volání SayHellogRPC:
    • DnsResolverFactory vytvoří překladač, který získá adresy pro název my-example-hosthostitele .
    • 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 adresy https .
  • ChannelCredentials.Insecure - Volání gRPC nepoužívají zabezpečení přenosu. Ekvivalent adresy 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" });

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 implementuje ResolverFactory. Mapuje se na file schéma a vytváří FileResolver instance.
  • FileResolver implementuje PollingResolver. PollingResolver je abstraktní základní typ, který usnadňuje implementaci překladače s asynchronní logikou přepsáním ResolveAsync.
  • V ResolveAsync:
    • Identifikátor URI souboru se převede na místní cestu. Například z file:///c:/addresses.json se stane c:\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é.

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 implementuje LoadBalancerFactory. Mapuje se na random název zásady a vytváří RandomBalancer instance.
  • RandomBalancer implementuje SubchannelsLoadBalancer. 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:
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 na GrpcChannelOptions.ServiceProviderhodnotu .
    • Adresa kanálu je file:///c:/data/addresses.json. Schéma file se mapuje na FileResolverFactory.
    • service config název nástroje pro vyrovnávání zatížení je random. Mapuje na RandomLoadBalancerFactory.

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.

Další materiály