Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
[gelöst] gRPC-Server antwortet SEHR langsam
emuuu
myCSharp.de - Member

Avatar #avatar-4078.jpg


Dabei seit:
Beiträge: 286

Themenstarter:

[gelöst] gRPC-Server antwortet SEHR langsam

beantworten | zitieren | melden

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)
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15536
Herkunft: BW

beantworten | zitieren | melden

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?
private Nachricht | Beiträge des Benutzers
emuuu
myCSharp.de - Member

Avatar #avatar-4078.jpg


Dabei seit:
Beiträge: 286

Themenstarter:

beantworten | zitieren | melden

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
Dieser Beitrag wurde 4 mal editiert, zum letzten Mal von emuuu am .
2+2=5 (für extrem große Werte von 2)
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15536
Herkunft: BW

beantworten | zitieren | melden

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().
private Nachricht | Beiträge des Benutzers
emuuu
myCSharp.de - Member

Avatar #avatar-4078.jpg


Dabei seit:
Beiträge: 286

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
Wie sieht die originale Startup.Configure() Methode aus?
Das UseKestrel kommt bei mir aus der Program.cs
Zitat von Abt
Welche ASP.NET Core Version hast Du denn?
3.1
Zitat von Abt
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)
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15536
Herkunft: BW

beantworten | zitieren | melden

Zitat von emuuu
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.
private Nachricht | Beiträge des Benutzers
emuuu
myCSharp.de - Member

Avatar #avatar-4078.jpg


Dabei seit:
Beiträge: 286

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
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)
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15536
Herkunft: BW

beantworten | zitieren | melden

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 ;-)
private Nachricht | Beiträge des Benutzers