Warum kommt es zu einem plötzlichen Anstieg der Antwortzeiten?

12

Wir haben eine API, die mit ServiceStack implementiert wird, das in IIS gehostet wird. Während des Auslastungstests der API haben wir festgestellt, dass die Antwortzeiten gut sind, sich jedoch schnell verschlechtern, sobald wir ungefähr 3.500 gleichzeitige Benutzer pro Server erreichen. Wir haben zwei Server und bei 7.000 Benutzern liegen die durchschnittlichen Antwortzeiten für alle Endpunkte unter 500 ms. Die Boxen befinden sich hinter einem Load Balancer, sodass wir 3.500 Concurrents pro Server erhalten. Sobald wir jedoch die Anzahl der gleichzeitigen Benutzer erhöhen, stellen wir eine signifikante Zunahme der Antwortzeiten fest. Wenn Sie die Anzahl der gleichzeitigen Benutzer auf 5.000 pro Server erhöhen, beträgt die durchschnittliche Antwortzeit pro Endpunkt ca. 7 Sekunden.

Der Arbeitsspeicher und die CPU auf den Servern sind recht niedrig, sowohl bei guten Antwortzeiten als auch nach einer Verschlechterung. In der Spitze mit 10.000 gleichzeitigen Benutzern liegt der CPU-Durchschnitt bei knapp 50% und der RAM-Speicher bei 3-4 GB von 16. Dies lässt uns denken, dass wir irgendwo an eine Grenze stoßen. Der folgende Screenshot zeigt einige Schlüsselindikatoren in perfmon während eines Auslastungstests mit insgesamt 10.000 gleichzeitigen Benutzern. Der hervorgehobene Zähler ist Anfragen / Sekunde. Auf der rechten Seite des Screenshots können Sie sehen, wie die Grafik für Anforderungen pro Sekunde sehr unregelmäßig wird. Dies ist der Hauptindikator für langsame Reaktionszeiten. Sobald wir dieses Muster sehen, stellen wir im Belastungstest langsame Reaktionszeiten fest.

Perfmon-Screenshot mit hervorgehobenen Anforderungen pro Sekunde

Wie gehen wir vor, um dieses Leistungsproblem zu beheben? Wir versuchen herauszufinden, ob es sich um ein Codierungs- oder Konfigurationsproblem handelt. Gibt es Einstellungen in web.config oder IIS, die dieses Verhalten erklären könnten? Der Anwendungspool führt .NET v4.0 aus und die IIS-Version ist 7.5. Die einzige Änderung, die wir an den Standardeinstellungen vorgenommen haben, ist die Aktualisierung des Werts für die Warteschlangenlänge des Anwendungspools von 1.000 auf 5.000. Wir haben der Datei Aspnet.config auch die folgenden Konfigurationseinstellungen hinzugefügt:

<system.web>
    <applicationPool 
        maxConcurrentRequestsPerCPU="5000"
        maxConcurrentThreadsPerCPU="0" 
        requestQueueLimit="5000" />
</system.web>

Mehr Details:

Der Zweck der API besteht darin, Daten aus verschiedenen externen Quellen zu kombinieren und als JSON zurückzugeben. Derzeit wird eine InMemory-Cache-Implementierung verwendet, um einzelne externe Aufrufe auf der Datenschicht zwischenzuspeichern. Die erste Anforderung an eine Ressource ruft alle erforderlichen Daten ab und alle nachfolgenden Anforderungen für dieselbe Ressource erhalten Ergebnisse aus dem Cache. Wir haben einen 'Cache Runner', der als Hintergrundprozess implementiert ist und die Informationen im Cache in bestimmten Intervallen aktualisiert. Wir haben den Code gesperrt, der Daten aus den externen Ressourcen abruft. Wir haben auch die Dienste zum asynchronen Abrufen der Daten von externen Quellen implementiert, sodass der Endpunkt nur so langsam sein sollte wie der langsamste externe Aufruf (es sei denn, wir haben Daten im Cache). Dies erfolgt mithilfe der System.Threading.Tasks.Task-Klasse.Könnten wir eine Beschränkung in Bezug auf die Anzahl der Threads treffen, die für den Prozess verfügbar sind?

Christian Hagelid
quelle
5
Wie viele Kerne hat Ihre CPU? Vielleicht schöpfen Sie einen Kern aus. Wenn die magische Zahl 50%, 25% oder 12,5% beträgt, deutet dies darauf hin, dass Sie einen Kern maximal genutzt haben und aus irgendeinem Grund die anderen Kerne, die im Leerlauf sitzen, nicht verwenden können. Überprüfen Sie, ob der Kern voll ist.
David Schwartz
1
Hast du einen Thread pro Anfrage? Haben Sie also für 5000 Anfragen 5000 Threads? Wenn Sie das tun, ist das wahrscheinlich Ihr Problem. Sie sollten stattdessen einen Thread-Pool erstellen und den Thread-Pool zum Verarbeiten der Anforderungen verwenden und die Anforderungen in die Warteschlange stellen, sobald sie in den Thread-Pool eingehen. Wenn ein Thread mit einer Anforderung fertig ist, kann er eine Anforderung aus der Warteschlange verarbeiten. Diese Art der Diskussion eignet sich am besten für den Stapelüberlauf. Zu viele Threads bedeuten zu viele Kontextwechsel.
Matt
1
Haben Sie hier nur eine Sicherheitsüberprüfung durchgeführt und versucht, alle Hintergrundprozesse auszuschalten, um festzustellen, wie sich JSON verhält, wenn statische Daten aus dem Cache zurückgegeben werden? Mit anderen Worten, Ihre JSON fordert statische Daten an und entfernt die "externen asynchronen Aufrufe", die Ihren Cache vollständig aktualisieren. Haben Sie, abhängig von der Menge der JSON-Daten, die bei jeder Anforderung bereitgestellt werden, schon einmal über den Netzwerkdurchsatz nachgedacht und darüber, ob Anforderungen zu sichern beginnen, weil die Server die Daten einfach nicht schnell genug übertragen können?
Robert
1
+1 zu Davids Vorschlag oben. Sie sollten den Test wirklich wiederholen und sich jede Kernauslastung genau ansehen. Ich würde vorschlagen, dass Sie dies so schnell wie möglich tun, um es zu beseitigen, wenn nichts anderes. Zweitens bin ich etwas misstrauisch gegenüber deinem Cache. Sperrenkonflikte können genau diese Art von Verhalten zeigen - an einigen kritischen Punkten verursachen Sperren Verzögerungen, die wiederum dazu führen, dass Sperren länger als normal gehalten werden, was zu einem Wendepunkt führt, an dem die Dinge schnell bergab gehen. Können Sie Ihren Caching- und Sperrcode freigeben?
Steve Cook
1
Was ist das Festplatten-Setup für die Server (vorausgesetzt, dass das Festplatten-Setup identisch ist, da sie über einen Lastausgleich verfügen)? Können Sie alle Spezifikationen für die Laufwerke / Server in Ihrem ersten Beitrag veröffentlichen? Haben Sie auf den Datenträgern der physischen Laufwerke, auf denen IIS UND die IIS-Protokolldateien vorhanden sind, einen Perfmon ausgelöst? Es ist durchaus möglich, dass Probleme mit dem Datenträger auftreten, wenn 3.500 Anforderungen = 3.500+ IIS-Protokolle erforderlich sind. Wenn sie sich auf derselben Festplatte / Partition befinden, besteht möglicherweise ein großes Problem.
Techie Joe

Antworten:

2

Nach @DavidSchwartz und @Matt sieht dies wie ein Thread aus, der die Verwaltung sperrt.

Ich schlage vor:

  1. Frieren Sie die externen Aufrufe und den für sie generierten Cache ein und führen Sie den Auslastungstest mit statischen externen Informationen durch, um alle Probleme zu beseitigen, die nicht mit der Serverumgebung zusammenhängen.

  2. Verwenden Sie Thread-Pools, wenn Sie diese nicht verwenden.

  3. Über externe Anrufe sagten Sie: "Wir haben auch die Dienste zum asynchronen Abrufen der Daten von externen Quellen implementiert, sodass der Endpunkt nur so langsam sein sollte wie der langsamste externe Anruf (es sei denn, wir haben Daten im Cache). "

Fragen sind: - Haben Sie überprüft, ob während des externen Anrufs Cache-Daten gesperrt sind oder nur, wenn Sie das Ergebnis des externen Anrufs in den Cache schreiben? (zu offensichtlich, muss aber sagen). - Sperrst du den gesamten Cache oder schmeißt du Teile davon? (zu offensichtlich, muss aber sagen). - Wie oft werden externe Anrufe ausgeführt, auch wenn sie asynchron sind? Selbst wenn sie nicht so oft ausgeführt werden, können sie durch übermäßige Anforderungen an den Cache von den Benutzeraufrufen blockiert werden, während der Cache gesperrt ist. In diesem Szenario wird normalerweise ein fester Prozentsatz der CPU-Auslastung angezeigt, da viele Threads in festgelegten Intervallen warten und das "Sperren" ebenfalls verwaltet werden muss. - Haben Sie überprüft, ob externe Aufgaben zu einer längeren Reaktionszeit führen, wenn das langsame Szenario eintrifft?

Wenn das Problem weiterhin besteht, sollten Sie die Task-Klasse vermeiden und die externen Aufrufe über denselben Thread-Pool ausführen, der die Benutzeranforderungen verwaltet. Dies dient zur Vermeidung des vorherigen Szenarios.

SaintJob 2.0
quelle