Laden...

[gelöst] gRPC-Server antwortet SEHR langsam

Erstellt von emuuu vor 3 Jahren Letzter Beitrag vor 3 Jahren 864 Views
emuuu Themenstarter:in
286 Beiträge seit 2011
vor 3 Jahren
[gelöst] gRPC-Server antwortet SEHR langsam

Guten Tag zusammen,

ich habe ein Problem mit gRPC in folgendem Setup:
Api-Gateway <-> gRPC-Server <-> Azure CosmosDB

Die API sowie den gRPC-Server lasse ich beide auf localhost laufen (mit tls). Das Problem nun: Selbst wenn beides Services hot sind dauert eine GetAll-Response (377 Byte response body) 2,08 Sekunden.

Hab jetzt die Dauer der einzelnen Schritte analysiert und hier die Bremse idenzifiziert:


        public async Task<List<ToolDto>> GetAll()
        {
            return await GrpcCallerService.CallService(_urls.GrpcTools, async channel =>
            {
                var client = new ToolStore.ToolStoreClient(channel);
                var response = await client.GetAllToolsAsync(new AllToolsRequest()); //dauert ~2000ms
                return response.Tools.Select(x => _mapper.Map<ToolDto>(x)).ToList();
            });
        }

Auf der anderen Seite von AllToolsRequest antwortet braucht der gRPC-Server allerdings nur ~22ms zum verarbeiten:


        public override async Task<MultipleToolReply> GetAllTools(AllToolsRequest request, ServerCallContext context)
        {
            try
            {
                var tools = await _toolRepository.GetAll();

                var result = new MultipleToolReply();
                result.Tools.AddRange(tools.Select(x => _mapper.Map<ToolReply>(x)));
                return result;
            }
            catch (Exception ex)
            {
                throw new RpcException(new Status(StatusCode.Internal, ex.Message));
            }
        }

Das Problem muss im gRPC-Server verortet sein, da ich bei abrufen mit 3rd party tools wie bloomRPC auf die gleichen response Zeiten komme.
Sprich irgendwas in der Übertragung ist extrem langsam. Habt ihr irgendeine Idee woran das liegen kann?

gRPC-Server:
Program.cs


                .UseKestrel(options =>
                {
                    var ports = GetDefinedPorts(configuration);

                    var serviceName = Environment.GetEnvironmentVariable("service_name") ?? "localhost";

                    options.Listen(IPAddress.Any, ports.grpcPort, listenOptions =>
                    {
                        listenOptions.Protocols = HttpProtocols.Http2;
                        listenOptions.UseHttps($"/etc/certs/{serviceName}.p12", serviceName);
                    });
                })

Startup.cs


            services.AddGrpc();

            //...
            app.UseEndpoints(endpoints =>
            {
                GrpcEndpointRouteBuilderExtensions.MapGrpcService<ToolService>(endpoints);
            });

Beste Grüße
emuuu

2+2=5( (für extrem große Werte von 2)

16.807 Beiträge seit 2008
vor 3 Jahren

Versuch auf Methoden-Ebene raus zu finden, was so lange dauert; also was genau in GetAllToolsAsync.
Weil so bleibt nur raten; und ich rate es ist das Repository. Oder verstehe ich Deine erklärung falsch?

emuuu Themenstarter:in
286 Beiträge seit 2011
vor 3 Jahren

Die Anfrage an den grpc-Server dauert so lang:


//2000ms:
await client.GetAllToolsAsync(new AllToolsRequest())

Auf der anderen ist der grpc-Server in der Verarbeitung aber recht zügig:


//22ms:
public override async Task<MultipleToolReply> GetAllTools(AllToolsRequest request, ServerCallContext context)
{
//..
}

Was also so lang dauert ist die reine Übertragung. Es muss etwas mit .UseKestrel zu tun haben.
Wen ich den Teil komplett rausnehme kriege ich eine vernünftige ResponseTime

Update:
Ok, irgendwie ist UseKestrel broke.
Wenn ich


   .UseKestrel(options =>
   {
      options.Listen(IPAddress.Any, ports.grpcPort, listenOptions =>
      {
         listenOptions.Protocols = HttpProtocols.Http2;
         listenOptions.UseHttps($"/etc/certs/{serviceName}.p12", serviceName);
      });
   })

durch


   .ConfigureKestrel(options =>
   {
      options.ListenAnyIP(ports.grpcPort, o =>
      {
         o.Protocols = HttpProtocols.Http2;
         o.UseHttps($"/etc/certs/{serviceName}.p12", serviceName);
      });
   })

ersetze, funktioniert es problemlos

2+2=5( (für extrem große Werte von 2)

16.807 Beiträge seit 2008
vor 3 Jahren

Wie sieht die originale Startup.Configure() Methode aus?

Was mich auch stutzig macht ist das UseKestrel. Welche ASP.NET Core Version hast Du denn?
Weil Kestrel wird in den neueren Versionen über den Host Builder konfiguriert und nicht über Configure().

emuuu Themenstarter:in
286 Beiträge seit 2011
vor 3 Jahren

Wie sieht die originale Startup.Configure() Methode aus?

Das UseKestrel kommt bei mir aus der Program.cs

Welche ASP.NET Core Version hast Du denn?

3.1

Weil Kestrel wird in den neueren Versionen über den Host Builder konfiguriert und nicht über Configure().

Da hab ichs auch drin, aber eben mit webBuilder.UseKestrel() anstatt .ConfigureKestrel


        private static IHostBuilder CreateHostBuilder(IConfigurationRoot configuration, string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
            //..
            })

2+2=5( (für extrem große Werte von 2)

16.807 Beiträge seit 2008
vor 3 Jahren

Da hab ichs auch drin, aber eben mit webBuilder.UseKestrel() anstatt .ConfigureKestrel

Auch schon davor, oder erst jetzt nach Deinem Edit um 16:07 Uhr?
Oben hast nämlich app.UseKestrel geschrieben was auf Configure() hinweist. builder.UseKestrel gibts nicht, sofern Du die Standardnamen verwendest.

Problem nun mit der richtigen Krestel-Config gelöst?

PS: kannst auch alles über die Json konfigurieren.

emuuu Themenstarter:in
286 Beiträge seit 2011
vor 3 Jahren

Auch schon davor, oder erst jetzt nach Deinem Edit um 16:07 Uhr?
Problem nun mit der richtigen Krestel-Config gelöst?

Jop das Problem besteht wenn ich in der Program.cs im CreateHostBuilder .UseKestrel verwende.
Wenn ich stattdessen .ConfigureKestrel (wie im edit) verwende, funktioniert es.

2+2=5( (für extrem große Werte von 2)

16.807 Beiträge seit 2008
vor 3 Jahren

CreateHostBuilder .UseKestrel das gibts nicht 😃
UseKestrel gibts nur in der AppConfiguration - die App Configuration kannst Du aber auch direkt aus dem Builder manipulieren; leichter Pitfall 😉