Udostępnij za pośrednictwem


Równoważenie obciążenia po stronie klienta gRPC

Uwaga

Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Ostrzeżenie

Ta wersja ASP.NET Core nie jest już obsługiwana. Aby uzyskać więcej informacji, zobacz zasady pomocy technicznej platformy .NET i platformy .NET Core. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Ważne

Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.

Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.

Autor: James Newton-King

Równoważenie obciążenia po stronie klienta to funkcja, która umożliwia klientom gRPC optymalną dystrybucję obciążenia na dostępnych serwerach. W tym artykule omówiono sposób konfigurowania równoważenia obciążenia po stronie klienta w celu tworzenia skalowalnych aplikacji gRPC o wysokiej wydajności na platformie .NET.

Równoważenie obciążenia po stronie klienta wymaga:

Konfigurowanie równoważenia obciążenia po stronie klienta usługi gRPC

Równoważenie obciążenia po stronie klienta jest konfigurowane podczas tworzenia kanału. Dwa składniki, które należy wziąć pod uwagę podczas korzystania z równoważenia obciążenia:

  • Program rozpoznawania, który rozpoznaje adresy kanału. Narzędzia rozpoznawania nazw obsługują pobieranie adresów ze źródła zewnętrznego. Jest to również nazywane odnajdywaniem usług.
  • Moduł równoważenia obciążenia, który tworzy połączenia i wybiera adres używany przez wywołanie gRPC.

Wbudowane implementacje rozwiązań rozpoznawania i modułów równoważenia obciążenia są uwzględniane w programie Grpc.Net.Client. Równoważenie obciążenia można również rozszerzyć, pisząc niestandardowe moduły rozpoznawania i moduły równoważenia obciążenia.

Adresy, połączenia i inny stan równoważenia obciążenia są przechowywane w wystąpieniu GrpcChannel . Kanał musi być ponownie używany podczas wykonywania wywołań gRPC w celu poprawnego działania równoważenia obciążenia.

Uwaga

Niektóre konfiguracje równoważenia obciążenia używają wstrzykiwania zależności (DI). Aplikacje, które nie używają di, mogą utworzyć ServiceCollection wystąpienie.

Jeśli aplikacja ma już konfigurację di, podobnie jak witryna internetowa ASP.NET Core, typy powinny być zarejestrowane w istniejącym wystąpieniu di. GrpcChannelOptions.ServiceProvider program jest konfigurowany przez pobranie z IServiceProvider di.

Konfigurowanie narzędzia rozpoznawania nazw

Program rozpoznawania nazw jest konfigurowany przy użyciu adresu, za pomocą której jest tworzony kanał. Schemat identyfikatora URI adresu określa rozpoznawanie.

Schemat Type Opis
dns DnsResolverFactory Usuwa adresy, wysyłając zapytanie o nazwę hosta dla rekordów adresów DNS.
static StaticResolverFactory Rozpoznaje adresy określone przez aplikację. Zalecane, jeśli aplikacja zna już adresy, które wywołuje.

Kanał nie wywołuje bezpośrednio identyfikatora URI zgodnego z rozpoznawaniem nazw. Zamiast tego tworzony jest pasujący program rozpoznawania adresów i używany do rozpoznawania adresów.

Na przykład przy użyciu polecenia GrpcChannel.ForAddress("dns:///my-example-host", new GrpcChannelOptions { Credentials = ChannelCredentials.Insecure }):

  • Schemat dns jest mapowy na DnsResolverFactory. Dla kanału jest tworzone nowe wystąpienie rozpoznawania nazw DNS.
  • Program rozpoznawania tworzy zapytanie DNS dla my-example-host i pobiera dwa wyniki: 127.0.0.100 i 127.0.0.101.
  • Moduł równoważenia obciążenia używa 127.0.0.100:80 metod i 127.0.0.101:80 do tworzenia połączeń i tworzenia wywołań gRPC.

DnsResolverFactory

Tworzy narzędzie rozpoznawania DnsResolverFactory , które ma na celu pobieranie adresów ze źródła zewnętrznego. Rozpoznawanie nazw DNS jest często używane do równoważenia obciążenia w wystąpieniach zasobników, które mają usługi bezgłówne 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" });

Powyższy kod ma następujące działanie:

  • Konfiguruje utworzony kanał przy użyciu adresu dns:///my-example-host.
    • Schemat dns jest mapowy na DnsResolverFactory.
    • my-example-host jest nazwą hosta, która ma zostać rozpoznana.
    • Żaden port nie jest określony w adresie, dlatego wywołania gRPC są wysyłane do portu 80. Jest to domyślny port dla niezabezpieczonych kanałów. Port można opcjonalnie określić po nazwie hosta. Na przykład dns:///my-example-host:8080 konfiguruje wywołania gRPC, które mają być wysyłane do portu 8080.
  • Nie określa modułu równoważenia obciążenia. Kanał domyślnie wybiera pierwszy moduł równoważenia obciążenia.
  • Uruchamia wywołanie SayHellogRPC:
    • Program rozpoznawania nazw DNS pobiera adresy dla nazwy my-example-hosthosta .
    • Wybierz pierwszą próbę nawiązania połączenia z jednym z rozpoznanych adresów.
    • Połączenie jest wysyłane do pierwszego adresu, z którymi kanał pomyślnie nawiązuje połączenie.
Buforowanie adresów DNS

Wydajność jest ważna podczas równoważenia obciążenia. Opóźnienie rozpoznawania adresów jest wyeliminowane z wywołań gRPC przez buforowanie adresów. Podczas pierwszego wywołania gRPC zostanie wywołany program rozpoznawania nazw, a kolejne wywołania używają pamięci podręcznej.

Adresy są automatycznie odświeżane, jeśli połączenie zostanie przerwane. Odświeżanie jest ważne w scenariuszach, w których adresy zmieniają się w czasie wykonywania. Na przykład na platformie Kubernetes ponownie uruchomiony zasobnik wyzwala program rozpoznawania nazw DNS w celu odświeżenia i pobrania nowego adresu zasobnika.

Domyślnie program rozpoznawania nazw DNS jest odświeżany, jeśli połączenie zostanie przerwane. Program rozpoznawania nazw DNS może również opcjonalnie odświeżyć się w okresowym interwale. Może to być przydatne w przypadku szybkiego wykrywania nowych wystąpień zasobników.

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

Powyższy kod tworzy element DnsResolverFactory z interwałem odświeżania i rejestruje go za pomocą iniekcji zależności. Aby uzyskać więcej informacji na temat używania niestandardowego programu rozpoznawania nazw, zobacz Konfigurowanie niestandardowych rozpoznawania nazw i modułów równoważenia obciążenia.

StaticResolverFactory

Statyczny program rozpoznawania nazw jest dostarczany przez StaticResolverFactoryprogram . Ten program rozpoznawania:

  • Nie wywołuje zewnętrznego źródła. Zamiast tego aplikacja kliencka konfiguruje adresy.
  • Jest przeznaczony dla sytuacji, w których aplikacja zna już adresy, które wywołuje.
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);

Powyższy kod ma następujące działanie:

  • Tworzy element StaticResolverFactory. Ta fabryka wie o dwóch adresach: localhost:80 i localhost:81.
  • Rejestruje fabrykę przy użyciu wstrzykiwania zależności (DI).
  • Konfiguruje utworzony kanał za pomocą:
    • Adres static:///my-example-host. Schemat static jest mapowy na statyczny program rozpoznawania nazw.
    • Zestawy GrpcChannelOptions.ServiceProvider z dostawcą usług DI.

W tym przykładzie zostanie utworzony nowy ServiceCollection element di. Załóżmy, że aplikacja ma już konfigurację di, na przykład witrynę internetową platformy ASP.NET Core. W takim przypadku typy powinny być zarejestrowane w istniejącym wystąpieniu di. GrpcChannelOptions.ServiceProvider program jest konfigurowany przez pobranie z IServiceProvider di.

Konfigurowanie modułu równoważenia obciążenia

Moduł równoważenia obciążenia jest określony w obiekcie korzystającym service config z kolekcji ServiceConfig.LoadBalancingConfigs . Dwa moduły równoważenia obciążenia są wbudowane i mapowane na nazwy konfiguracji modułu równoważenia obciążenia:

Nazwisko Pisz Opis
pick_first PickFirstLoadBalancerFactory Próbuje nawiązać połączenie z adresami do momentu pomyślnego nawiązania połączenia. Wszystkie wywołania gRPC są wykonywane do pierwszego pomyślnego połączenia.
round_robin RoundRobinLoadBalancerFactory Próbuje nawiązać połączenie ze wszystkimi adresami. Wywołania gRPC są dystrybuowane we wszystkich pomyślnych połączeniach przy użyciu logiki działania okrężnego.

service config jest skrótem konfiguracji usługi i jest reprezentowany przez ServiceConfig typ. Istnieje kilka sposobów, na które kanał może uzyskać service config skonfigurowany moduł równoważenia obciążenia:

  • Aplikacja może określić service config , kiedy kanał zostanie utworzony przy użyciu polecenia GrpcChannelOptions.ServiceConfig.
  • Alternatywnie program rozpoznawania może rozpoznać service config element dla kanału. Ta funkcja umożliwia zewnętrznemu źródle określenie sposobu, w jaki jego osoby wywołujące powinny wykonywać równoważenie obciążenia. To, czy program rozpoznawania obsługuje rozpoznawanie elementu service config , zależy od implementacji narzędzia rozpoznawania nazw. Wyłącz tę funkcję za pomocą GrpcChannelOptions.DisableResolverServiceConfigpolecenia .
  • Jeśli parametr nie service config jest podany lub service config nie ma skonfigurowanego modułu równoważenia obciążenia, kanał domyślnie ma wartość 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" });

Powyższy kod ma następujące działanie:

  • Określa element RoundRobinLoadBalancerFactory w obiekcie service config.
  • Uruchamia wywołanie SayHellogRPC:
    • DnsResolverFactory Tworzy program rozpoznawania nazw, który pobiera adresy dla nazwy my-example-hosthosta .
    • Moduł równoważenia obciążenia z działaniem okrężnym próbuje nawiązać połączenie ze wszystkimi rozwiązanymi adresami.
    • Wywołania gRPC są dystrybuowane równomiernie przy użyciu logiki działania okrężnego.

Konfigurowanie poświadczeń kanału

Kanał musi wiedzieć, czy wywołania gRPC są wysyłane przy użyciu zabezpieczeń transportu. http i https nie są już częścią adresu, schemat określa teraz rozpoznawanie, więc Credentials należy skonfigurować opcje kanału podczas korzystania z równoważenia obciążenia.

  • ChannelCredentials.SecureSsl- Wywołania gRPC są zabezpieczone za pomocą protokołu Transport Layer Security (TLS). https Odpowiednik adresu.
  • ChannelCredentials.Insecure - Wywołania gRPC nie używają zabezpieczeń transportu. http Odpowiednik adresu.
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" });

Używanie równoważenia obciążenia z fabryką klienta gRPC

Fabrykę klienta gRPC można skonfigurować do używania równoważenia obciążenia:

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();

Powyższy kod ma następujące działanie:

  • Konfiguruje klienta przy użyciu adresu równoważenia obciążenia.
  • Określa poświadczenia kanału.
  • Rejestruje typy DI w aplikacji IServiceCollection.

Pisanie niestandardowych rozwiązań rozpoznawania i modułów równoważenia obciążenia

Równoważenie obciążenia po stronie klienta jest rozszerzalne:

  • Zaimplementuj Resolver , aby utworzyć niestandardowy program rozpoznawania nazw i rozpoznawać adresy z nowego źródła danych.
  • Zaimplementuj LoadBalancer tworzenie niestandardowego modułu równoważenia obciążenia przy użyciu nowego zachowania równoważenia obciążenia.

Ważne

Interfejsy API używane do rozszerzania równoważenia obciążenia po stronie klienta są eksperymentalne. Mogą się zmieniać bez powiadomienia.

Tworzenie niestandardowego rozpoznawania nazw

Program rozpoznawania:

  • Implementuje Resolver element i jest tworzony przez element ResolverFactory. Utwórz niestandardowy program rozpoznawania, implementując te typy.
  • Odpowiada za rozpoznawanie adresów używanych przez moduł równoważenia obciążenia.
  • Opcjonalnie może zapewnić konfigurację usługi.
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);
    }
}

Powyższy kod:

  • FileResolverFactory implementuje ResolverFactory. Mapuje on na file schemat i tworzy FileResolver wystąpienia.
  • FileResolver implementuje PollingResolver. PollingResolver jest abstrakcyjnym typem podstawowym, który ułatwia implementowanie rozpoznawania za pomocą logiki asynchronicznej przez zastąpienie elementu ResolveAsync.
  • W pliku ResolveAsync:
    • Identyfikator URI pliku jest konwertowany na ścieżkę lokalną. Na przykład, file:///c:/addresses.json staje się c:\addresses.json.
    • Kod JSON jest ładowany z dysku i konwertowany na kolekcję adresów.
    • Odbiornik jest wywoływany z wynikami, aby poinformować kanał, że adresy są dostępne.

Tworzenie niestandardowego modułu równoważenia obciążenia

Moduł równoważenia obciążenia:

  • Implementuje LoadBalancer element i jest tworzony przez element LoadBalancerFactory. Utwórz niestandardowy moduł równoważenia obciążenia i fabrykę, implementując te typy.
  • Otrzymuje adresy z narzędzia rozpoznawania nazw i tworzy Subchannel wystąpienia.
  • Śledzi stan połączenia i tworzy element SubchannelPicker. Kanał wewnętrznie używa selektora do wybierania adresów podczas wykonywania wywołań gRPC.

Element SubchannelsLoadBalancer to:

  • Abstrakcyjna klasa bazowa, która implementuje LoadBalancerelement .
  • Zarządza tworzeniem Subchannel wystąpień na podstawie adresów.
  • Ułatwia implementowanie niestandardowych zasad wybierania w kolekcji podkanałów.
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);
    }
}

Powyższy kod:

  • RandomBalancerFactory implementuje LoadBalancerFactory. Mapuje ona random nazwę zasad i tworzy RandomBalancer wystąpienia.
  • RandomBalancer implementuje SubchannelsLoadBalancer. Tworzy obiekt RandomPicker , który losowo wybiera podkanał.

Konfigurowanie niestandardowych modułów rozpoznawania i modułów równoważenia obciążenia

Niestandardowe moduły rozpoznawania i moduły równoważenia obciążenia muszą być zarejestrowane za pomocą wstrzykiwania zależności (DI), gdy są używane. Istnieje kilka opcji:

  • Jeśli aplikacja korzysta już z di, na przykład aplikacji internetowej ASP.NET Core, można je zarejestrować przy użyciu istniejącej konfiguracji di. Element IServiceProvider można rozpoznać z di i przekazać do kanału przy użyciu polecenia GrpcChannelOptions.ServiceProvider.
  • Jeśli aplikacja nie korzysta z di, utwórz:
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);

Powyższy kod ma następujące działanie:

  • Tworzy element ServiceCollection i rejestruje nowe implementacje modułu rozpoznawania nazw i modułu równoważenia obciążenia.
  • Tworzy kanał skonfigurowany do używania nowych implementacji:
    • ServiceCollection element jest wbudowany w element IServiceProvider i ustawiony na GrpcChannelOptions.ServiceProviderwartość .
    • Adres kanału to file:///c:/data/addresses.json. Schemat file jest mapowy na FileResolverFactory.
    • service config Nazwa modułu równoważenia obciążenia to random. Mapuje na RandomLoadBalancerFactory.

Dlaczego równoważenie obciążenia jest ważne

Multipleksy HTTP/2 w jednym połączeniu TCP. Jeśli gRPC i HTTP/2 są używane z modułem równoważenia obciążenia sieciowego (NLB), połączenie jest przekazywane do serwera, a wszystkie wywołania gRPC są wysyłane do tego jednego serwera. Inne wystąpienia serwera w równoważeniu obciążenia sieciowego są bezczynne.

Moduły równoważenia obciążenia sieciowego są typowym rozwiązaniem do równoważenia obciążenia, ponieważ są one szybkie i lekkie. Na przykład platforma Kubernetes domyślnie używa modułu równoważenia obciążenia sieciowego do równoważenia połączeń między wystąpieniami zasobników. Jednak moduły równoważenia obciążenia sieciowego nie są skuteczne podczas dystrybucji obciążenia w przypadku użycia z gRPC i HTTP/2.

Równoważenie obciążenia po stronie klienta lub serwera proxy?

Usługi gRPC i HTTP/2 można skutecznie zrównoważyć przy użyciu serwera proxy modułu równoważenia obciążenia aplikacji lub równoważenia obciążenia po stronie klienta. Obie te opcje umożliwiają dystrybucję poszczególnych wywołań gRPC na dostępnych serwerach. Wybór między serwerem proxy a równoważeniem obciążenia po stronie klienta jest wyborem architektury. Każda z nich ma zalety i wady.

  • Serwer proxy: wywołania gRPC są wysyłane do serwera proxy, serwer proxy podejmuje decyzję o równoważeniu obciążenia, a wywołanie gRPC jest wysyłane do końcowego punktu końcowego. Serwer proxy jest odpowiedzialny za poznanie punktów końcowych. Używanie serwera proxy dodaje:

    • Dodatkowy przeskok sieciowy do wywołań gRPC.
    • Opóźnienie i zużywa dodatkowe zasoby.
    • Serwer proxy musi być poprawnie skonfigurowany i skonfigurowany.
  • Równoważenie obciążenia po stronie klienta: klient gRPC podejmuje decyzję o równoważeniu obciążenia po uruchomieniu wywołania gRPC. Wywołanie gRPC jest wysyłane bezpośrednio do końcowego punktu końcowego. W przypadku korzystania z równoważenia obciążenia po stronie klienta:

    • Klient jest odpowiedzialny za poznanie dostępnych punktów końcowych i podejmowanie decyzji dotyczących równoważenia obciążenia.
    • Wymagana jest dodatkowa konfiguracja klienta.
    • Wywołania gRPC o wysokiej wydajności eliminują potrzebę korzystania z serwera proxy o wysokiej wydajności.

Dodatkowe zasoby