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.
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?
quelle
Antworten:
Nach @DavidSchwartz und @Matt sieht dies wie ein Thread aus, der die Verwaltung sperrt.
Ich schlage vor:
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.
Verwenden Sie Thread-Pools, wenn Sie diese nicht verwenden.
Ü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.
quelle