Laden...

Performance eines Webservice

Erstellt von S.R. vor 10 Jahren Letzter Beitrag vor 10 Jahren 5.096 Views
S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren
Performance eines Webservice

Hallo,

ich bin gerade dabei einen Webservice in C# unter VS 2012 zu entwickelt - die ersten Funktionen stehen bereits 😃

Nun habe ich mir eine kleine Windows-Test-App geschrieben, mit der ich meine Requests und Reponses testen kann - neben Funktion auch die Performance. Folgend der Code der Test-App:

Stopwatch watch = new Stopwatch();
            watch.Start();

            WebRequest request = WebRequest.Create("http://172.17.1.24/SuSy.asmx");
            request.Method = "POST";
            string postData = textBox3.Text;
            byte[] byteArray = Encoding.UTF8.GetBytes(postData);
            request.ContentType = "application/soap+xml; charset=utf-8";
            request.ContentLength = byteArray.Length;

            request.Proxy = null;
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(byteArray, 0, byteArray.Length);
            dataStream.Close();

            WebResponse response = request.GetResponse();
            dataStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(dataStream);
            this.textBox2.Text += reader.ReadToEnd();

            reader.Close();
            dataStream.Close();
            response.Close();

            watch.Stop();
            MessageBox.Show("Time spent: " + watch.Elapsed);

Den Request habe ich in meiner textBox3 fest hinterlegt - für die ersten Tests reicht mir dies 😃 Folgendes habe ich nun festgestellt:

  1. Aufruf => 227 ms
  2. Aufruf => 82 ms
  3. Aufruf => 94 ms

Wenn ich dann wieder das Programm schließe und neu starte, dann erhalte ich folgende Werte:

  1. Aufruf => 241 ms
  2. Aufruf => 95 ms
  3. Aufruf => 94 ms

Ich bin jetzt total verwundert, wieso der erste Aufruf im Verhältnis zu den darauf folgenden zu lange dauert. Folgende Gedanken habe ich mir dazu gemacht:

  1. Ich verwende eine feste IP, d.h. alles was mit DNS zu tun hat fällt raus

  2. Ich habe vorerst http verwendet und kein https => d.h. alles was mit dem ersten SSL-Handshake zu tun hat, fällt auch raus.

  3. Der Quellcode steht in der Funktion button1_Click. Bei jedem Button-Click wird ja alles neu initialisiert, d.h. es dürfte doch "nichts irgendwo gecached" werden, oder?

  4. Kann ich den IIS als Ursache ausschließen? Ich würde sagen ja, weil irgendwo muss ja in meiner Test-App ein Unterschied zwischen Neustart der App und erneutem Aufruf der Funktion sein, oder?

Mein Traum wäre natürlich, dass ich auch beim ersten Aufruf die Zeit vom zweiten/dritten/... Aufruf bekomme 😃

Bin für jeden Tipp mehr als dankbar!

Gruß

Stefan

16.835 Beiträge seit 2008
vor 10 Jahren

Nö, das ist völlig normal und solltest Du eigentlich herausgefunden haben, wenn Du Dich ein wenig mit dem IIS beschäftigt hättest.

Alle Anwendungen, die der IIS hostet, sind nach dem Serverstart nicht automatisch auch gestartet.
Der Start der Anwendung findet beim ersten Request statt. Erst dann wird der AppPool geladen, werden alle nötigen DLLs geladen, die ersten Sachen in den Cache gelegt etc etc

Daher braucht der erste Zugriff bei ALLEN im IIS gehosteten Anwendungen etwas länger, als die folgenden Anwendungen. Und, das wiederholt sich, wenn die Idle-Time (siehe AppPool-Einstellung) erreicht wurde und der IIS die Anwendung "schlafen legt".
Man kann die Idle-Time zwar auf 0 setzen, aber der erste Request ist nicht "deutlich schneller" zu machen. Bei ASP.NET gibts eine PreCaching-Einstellung beim Kompilieren; bei Webservices nicht.

S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren

Hi,

vielen Dank für deine Antwort. Ich glaube da haben wir ein bisschen aneinander vorbei geredet - ich versuche es nochmal anders zu beschreiben 😃

Wenn ich meine Test-App starte und auf den Button klicke, dann dauert der Aufruf meiner Funktion rund 230 ms. Wenn ich dann warte - ruhige eine Minute - und dann erneute auf den Button klicke, dann dauert die Aktion rund 90 ms.

Wenn ich hingegen meine Test-App starte, auf den Button klicke, die Test-App schließe, dann sofort neu starte und erneut auf den Button klicke, dann dauert auch dieser Aufruf 230 ms.

Für mich bedeutet das im ersten Beispiel, dass der IIS die Anwendung noch nicht gestartet hat (daher dauert es etwas länger) und dann beim zweiten Aufruf was schneller ist, weil die Anwendung schon gestartet ist=> verständlich.

Im zweiten Beispiel hingegen dauert ja auch der zweite Aufruf länger, obwohl der IIS die Anwendung ja schon gestartet haben muss (durch den ersten Aufruf).

Der Unterschied liegt ja in diesen zwei Beispielen ja nur daran, ob ich die App zwischendurch neu starte oder nicht... Der IIS sollte doch gar nichts davon mitbekommen, ob die Anwendung neu gestartet wurde oder nicht... oder sehe ich das falsch?

Bin für jeden Tipp dankbar! Bzgl. Idle-Time werde ich mich jetzt mal schlauer machen - das klingt grundsätzlich sehr interessant - obwohl ich glaube, dass es mir in diesem aktuellen Problem nicht hilft oder docht?

DANKE!

Gruß

Stefan

16.835 Beiträge seit 2008
vor 10 Jahren

Von der zweiten Sache hast Du genau 0 in Deinem Eintragsthread erwähnt; und meine Antwort ist daher auch genau diese Sache gerichtet: auf den Webservice.

Was das ganze dann mit Deiner Client-Anwendung zutun hat: keine Ahnung.
Auf alle Fälle dauert ein InitialRequest einer IIS-Anwendung immer etwas länger; und das gehört sich so.

Und was heisst TestApp-Starten? Doppelklick auf die Exe oder Start über VS?
Wenn Du das ganze lokal testest, und auch Dein Webservice lokal ist, dann wird Dein Webservice von Visual Studio beim Starten der Anwendung recycled und damit braucht auch dieser vermeintliche "zweite Request" länger.

Aber da Du gar nich sagst, wie Deine Umgebung aussieht, können wir oder ich nur raten.

W
955 Beiträge seit 2010
vor 10 Jahren

Hi,

schneide doch mal den Verkehr mit Wireshark, Fiddler o.ä. mit.Vllt passiert da noch eine Authentification o.dgl.

S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren

Hi,

vielen Dank für deine Mühe! Wenn man manchmal so in seinen Gedanken ist, dann vergisst man doch leider hin und wieder das Westentliche sorry

Was genau ist denn der "InitialRequest einer IIS-Anwendung"? Folgende Unklarheiten wirren da in meinem Kopf 😃

  1. Wenn ich meine Test-Anwendung auf meinem Rechner starte und das erste Mal auf den Button klicke => ist das der InitialRequest?

  2. Der InitRequest gilt doch nicht pro Anwendung, oder? Weil http ist doch ein zustandsloses Protokoll und daher sollte es egal sein, von welcher Anwendung der Request kommt...

Ich habe meine Test-App über Doppelklick aus dem Windows Explorer gestartet, nicht über VS; wobei die Ergebnisse vollkommen identisch sind!

Der Webservice läuft auf eigener Hardware; mein Rechner und der IIS hängen am gleichen Switch im gleichen Netzwerk.

Wenn ich meine Test-App zwei Mal starte, dann klicke ich auf beiden kurz hintereinander den Button => beide brauchen ~230 ms. Dann warte ich (gerade knapp 10 Minuten) und klicke dann bei beiden erneut auf den Button => beide brauchen ~90ms.

Das gleiche Phänomen habe ich auch, wenn ich per php-Script auf meinen Webservice zugreifen => daher schließe ich die Fehlerursache wohl in meiner Test-App aus.

Bzgl. Netzwerkverkehr mitschneiden, habe ich null Erfahrung - wird wohl Zeit sich damit mal zu beschäftigen... 😃

Danke - bin weiterhin für jeden Tipp dankbar!

Gruß

Stefan

16.835 Beiträge seit 2008
vor 10 Jahren

Der Initialrequest ist der Request, der das Laden des Webservices erzwingt. Dies kann sein* Während dem Betrieb nach einem Recycle

  • Nach dem Server-Start

Ein Reycle wird ausgeführt...* bei einer Konfigurationsänderung des AppPool

  • bei einer Änderung der web.config
  • nach der Idle-Time
  • ...

Wenn man nun mit Visual Studio eine Anwendung per Debug startet und der Webservice ebenfalls als Projekt enthalten ist, dann wird ebenfalls ein Recycle ausgelöst.

Was Deine Sache angeht wird Dir wohl nur ein Profiler auf den Webdienst helfen können.
Und schau Dir endlich den IIS an. Waren jetzt genug Möglichkeiten, auch in einem anderen Thema, wo Du das hättest längst tun können. Das gehört im Prinzip zu den absoluten IIS Grundlagen, die ich Dir nicht beibringen muss.

P
48 Beiträge seit 2005
vor 10 Jahren

Hallo,

in Deinem Fall liegt es daran, dass der erste Aufruf vin WebRequest.Create() immer langsamer ist als die Folgeaufrufe. Jedenfalls bist Du nicht der einzige mit diesem Problem.

Möglicherweise wird das WebRequest Objekt gecached oder es ist einfach ein Initialisierungsproblem, da weiss ich nichts genaues. Aber es kommt wohl immer wieder vor, dass innerhalb einer Applikation der erste Aufruf von WebRequest.Create länger dauert.

Hier vielleicht ein Lösungsansatz?

First WebRequest slow

--
mfG.
Marcel Eckhoff

16.835 Beiträge seit 2008
vor 10 Jahren

in Deinem Fall liegt es daran, dass der erste Aufruf vin WebRequest.Create() immer langsamer ist als die Folgeaufrufe.

Ich kanns mit .NET 3.0, .NET 3.5 und .NET 4.0 tatsächlich nachvollziehen. Erster Request 160-190ms auf meine Testmaschine, die folgenden max 120ms.
Unter .NET 2.0 und .NET 4.5 kann ich keinen Unterschied zwischen den Anfragen messen. Alle um die 105ms.

Sollte man mal per Reflector schauen, was bei 2.0 und 3.0 und dann wieder bei 4.5 anders oder ob es einfach "Zufall ist".

S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren

Hi,

sorry, dass ich erst jetzt wieder antworte - viel um die Ohren - aber wer kennt das nicht 😃

Meine weiter durchgeführten Tests:
Ich habe es soeben erneut mit php getestet: Wenn ich in einem php-Script (läuft lokal auf einem Apache unter W7) zwei SOAP-Requests hintereinander ausführe, dann dauert der erste lang und der zweite kurz. Dieses Phänomen habe ich bei jedem Aufruf.

Es ist auch vollkommen egal, ob der erste und der zweite SOAP-Request gleich oder unterschiedlich ist.

Also meine Einschätzung zum "WebRequest.Create()":
Ich würde behaupten, daran liegt es nicht, da es egal ist, ob der SOAP-Server via C#-WebRequest oder via php angesprochen wird. Meiner Einschätzung nach liegt das Problem ganz klar auf Server-Seite (IIS). Hier gehe ich allerdings auch nicht von einem "Start/Initialisierungs-Problem" aus, denn auch folgendes lässt sich bei mir immer reproduzieren:

  • Start C#-App1
  • Start C#-App2 (gleiches Programm wie App1, nur das zweite Mal ausgeführt)
  • App1: 1. SOAP-Request => langsam
  • App2: 1. SOAP-Request => langsam
  • App1: 2. SOAP-Request => schnell
  • App2: 2. SOAP-Request => schnell

Ich finde das echt spannend und interessant, was dies sein könnte - weil erklären kann ich mir das nicht, weil für mich jeder Request an den SOAP-Server gleich sein sollte und da dies via http passiert und http zustandlos ist, ... keine Ahnung... ich kann es mir nicht erklären.

Mein erklärtes Ziel wäre es natürlich, dass jeder SOAP-Request schnell ist und evtl. nur der erste SOAP-Request nach einem Server-Neustart bzw. einer Initialisierung langsam ist.

Teilt ihr meine Einschätzung? Wenn ja - den Reflector kenne ich nicht. Kennt ihr ein gutes HowTo, wie ich dies am IIS anwenden kann? Würde da gerne mal mein Glück versuchen und mein Wissen erweitern...

Danke und Gruß

Stefan

16.835 Beiträge seit 2008
vor 10 Jahren

Also ich kenn den IIS sehr sehr gut; und was er macht, dass es zu diesem Zeitverzug kommt, hab ich Dir bereits gesagt.

S
S.R. Themenstarter:in
221 Beiträge seit 2007
vor 10 Jahren

Hallo,

vielen Dank für deine Mühen. Meine WebMethod habe ich jetzt komplett reduziert, um jegliche Fälle wie z.B. Dateizugriff oder Datenbankzugriffe auszuschließen:

// Soap-Performance-Test
        [WebMethod(Description = "")]
        public string Test_SOAP()
        {
            return "123";
        }

Nachdem ich diesen Code veröffentlicht habe, hat der erste SOAP-Request rund 600ms gedauert => das verstehe ich vollkommen, weil hier die Erst-Initialisierung stattfindet. Der zweite Aufruf hat dann nur 9ms gedauert. Soweit alles OK und verständlich.

Dann schließe ich meine C#-Anwendung und start sie neu. Dann führe ich den ersten SOAP-Request aus und dann dauert die Antwort 109ms, dann führe ich den zweiten SOAP-Request aus und es dauert 11ms.
=> Hier hört es mit meinem Verständnis dann auf, denn hier sollte kein Initialial-Request stattfinden und jeder Request sollte gleich lange dauern (plus minus ein paar ms Abweichung, aber nicht um den Faktor 10).

Der erste Zeitverzug ist klar - absolut verstanden und daran störe ich mich auch gar nicht; der zweite Zeitverzug wo also keine Initialisierung mehr stattfindet - der stört mich enorm und ich kann ihn mir absolut nicht erklären...

Und so wie ich dich verstanden habe, ist doch genau der zweite Zeitverzug auch bei dir "tatsächlich nachvollziehbar" und hier sprichst du vom Reflector, oder sprechen wir aneinander vorbei?

Danke und Gruß!

Stefan

16.835 Beiträge seit 2008
vor 10 Jahren

Ich kann jetzt kein neues Verhalten an Deiner Anwendung erkennen.

Zum IIS: der erste Request dauert immer länger aufgrund des Initial-Verhaltens.

Zum Client: der erste Request von WebClient braucht anscheinend auch etwas länger. Kann am Verhalten der CLR liegen, zB dass hier gewisse Win32 API-Dinge noch abgerufen und gecached werden (zB Proxy Settings) - der initialisiert eben auch!
Schließ Du die Anwendung wieder, dann wird das Zeug natürlich aus dem Cache geworfen und muss beim neuen Starten wieder geladen werden.

Ich kann also jetzt absolut nichts Ungewöhnliches an Deinen "Messungen" feststellen.

Edit nach kurzem Blick in die WebRequest-Sourcen: und so ist es auch. Beim Aufruf der statischen Methode WebRequest.Create wird als aller erstes ein WebRequest-Objekt als erstellt (genauer gesagt ein Context), das anschließend für alle weiteren Requests verwendet wird (+ zusätzlich ein paar API-Abfragen bzgl. Security, Berechtigungen, Einstellungen.....).

Ergo: der erste Aufruf braucht länger, sowohl der IIS wie auch die Client-Seite aufgrund der Initialisierung.