2012-05-18 17 views
12

Ich habe einen C# -Server, der auf Visual Studio 2010 und Mono Develop 2.8 entwickelt wurde. NET Framework 4.0C# -Server-Skalierbarkeitsproblem unter Linux

Es sieht so aus, als ob dieser Server unter Windows viel besser (in Bezug auf Skalierbarkeit) verhält als unter Linux. Ich testete die Server-Skalierbarkeit auf nativem Windows (12 physikalische Kerne) und 8 und 12 Kerne Windows und Ubuntu Virtual Machines mit Apache ab-Tool.

Die Reaktionszeit der Fenster ist ziemlich flach. Es fängt an zuzunehmen, wenn die Nebenläufigkeitsebene die Anzahl der Kerne erreicht/überwindet.

Aus irgendeinem Grund sind die Antwortzeiten von Linux viel schlechter. Sie wachsen ziemlich linear ab Level 5 der Nebenläufigkeit. Auch Linux VM mit 8 und 12 Kernen verhält sich ähnlich.

Also meine Frage ist: Warum funktioniert es schlechter auf Linux? (Und wie kann ich das beheben?).

Schauen Sie sich bitte das beigefügte Diagramm an, es zeigt die gemittelte Zeit für die Erfüllung von 75% der Anfragen als Funktion der Anforderungen Nebenläufigkeit (die Bereichsleiste wird auf 50% und 100% gesetzt). time to fulfill 75% of the request as a function of the request concurrency

Ich habe das Gefühl, dass dies auf Monos Garbage Collector zurückzuführen sein könnte. Ich habe versucht, mit den GC-Einstellungen herumzuspielen, aber ich hatte keinen Erfolg. Irgendwelche Vorschläge?

Einige zusätzliche Hintergrundinformationen: Der Server basiert auf einem HTTP-Listener, der die Anforderungen schnell analysiert und sie in einem Threadpool in eine Warteschlange stellt. Der Thread-Pool kümmert sich darum, diese Anfragen mit einigen intensiven Berechnungen zu beantworten (Berechnung einer Antwort in ~ 10 Sekunden).

+1

Was ist ein "C# -Server"? Ist das anders als ein Server? Ich meine, in deinem Titel wird "C#" als Adjektiv verwendet? Ist ein "C# -Server" eine Art Server? –

+0

> einige intensive Mathematik (Berechnung einer Antwort in ~ 10 Sekunden). Ich denke, dein Problem ist da .. Es ist kein typisches Szenario für einen Server. Wie viele Kerne haben Ihre physische Hardware, 12? Wie sieht das Diagramm nach den 10 gleichzeitigen Anfragen aus? – Soonts

+0

Wie ich weiß, ist Mono für diese Anwendungen nicht geeignet. Die Entwicklung von Mono konzentriert sich auf kleine Desktop-Anwendungen. Ich bekomme diese Informationen von einem Mono-Entwickler, ich werde versuchen, weitere Informationen zu finden und werde hier posten, wenn ich finde. – LawfulHacker

Antwort

4

Sie müssen zuerst lokalisieren, wo das Problem zuerst ist. Beginnen Sie mit der Überwachung Ihrer Speichernutzung mit HeapShot. Wenn es sich nicht um Speicher handelt, profilieren Sie Ihren Code, um die zeitaufwendigen Methoden zu ermitteln.

Diese Seite, Performance Tips: Writing better performing .NET and Mono applications, enthält einige nützliche Informationen, einschließlich der Verwendung des Monoprofilers.

Übermäßige String-Manipulation und Boxen sind oft "versteckte" Täter von Code, der nicht gut skaliert.

+0

Danke Mitch.Ich werde die Tools/Dokumente auschecken, die du vorgeschlagen hast. Aber ich kann Ihnen sagen, dass der Server bereits (intensiv) profiliert und auf Windows optimiert wurde (mit eqatec Profiler). Das Serververhalten unter Windows ist großartig: flache Antwort (getestet mit bis zu 12 gleichzeitigen Anfragen auf einem Rechner mit 12 physischen Kernen). Stattdessen führt es auf Linux viel schlechter. Ein Engpass bei der Speicherbandbreite sollte Linux und Windows auf die gleiche Weise beeinflussen, deshalb habe ich es ausgeschlossen. Bitte werfen Sie einen Blick auf die Grafik, die ich hochgeladen habe. Ich konnte es vorher wegen Stackoverflow-Anti-Spam-Richtlinien nicht anhängen (Ich bin ein neuer Benutzer) – Enio

+0

Ich habe das von Ihnen vorgeschlagene Tool (HeapShot) verwendet, um das GC-Verhalten zu profilieren. Es sieht so aus, als gäbe es ~ 10 Speicherbereinigungen für alle 20 Anfragen, die ich an den Server sende. Jedes dieser GC-Ereignisse verarbeitet weniger als 10 MB RAM. Die meiste Arbeit ist getan, um System.Single [] zu befreien. Trotzdem sieht es für mich so aus, dass diese Speicherereignisse zu selten sind, um die Skalierbarkeit des Servers zu beeinträchtigen. Was denken Sie? – Enio

1

Probieren Sie den sgen Garbage Collector aus (und dafür wird Mono 2.11.x empfohlen). Sehen Sie sich die Mono-Manpage für weitere Details an.

+0

Danke. Ich habe versucht, mit mono --gc = sgen zu laufen. Leider ist das Verhalten immer noch gleich – Enio

+0

welche Version von Mono? – knocte

+0

eine andere Option, die Sie ausprobieren könnten, ist das LLVM-Backend – knocte

1

Ich glaube nicht, dass es wegen der GC ist. AFAIK die GC-Nebenwirkungen sollten mehr oder weniger gleichmäßig über die Fäden verteilt sein.

Meine blinde Vermutung ist: Sie können es reparieren, indem Sie mit ThreadPool.SetMinThreads/SetMaxThreads API spielen.

+0

Ich habe versucht, die Anzahl der Min/Max-Working/IO-Threads zu variieren und es scheint keinen (positiven) Effekt auf die Skalierbarkeit zu haben. Danke trotzdem. Btw der Effekt ist gleichmäßig über alle Threads verteilt: Bitte schauen Sie sich die Fehlerbalken auf den braunen und orange Kurven (die auf Mono) bei Parallelität 9-10. Sie können sehen, wie die Antwortzeiten für alle Anfragen gleich sind. – Enio

+0

OK, meine blinde Vermutung # 2: Die I/O-Completion-Ports (verwendet von .NET CLR-Thread-Pool) wurden 1993 (Windows NT 3.5) erfunden und seitdem fein abgestimmt und debuggt. OTOH, das Epoll (IOCP-Klon, von MONO für denselben Zweck verwendet) ist erst seit 2002 hier, also ist das Windows IOCP einfach besser. Unter Linux läuft alles bis zu gleichzeitigen Anfragen * 2 Soonts

+0

Übrigens, starten Sie beim Benchmarking alle Anfragen gleichzeitig? Was ändert sich, wenn Sie sie in Abständen von 1-2 Sekunden nacheinander starten? – Soonts

0

Wenn Sie Code viele Ausnahmen auslöst, dann ist mono 10x schneller als .NET

+2

das ist großartig! Aber mein Problem ist das Gegenteil: Die Server-Skalierbarkeit ist unter Windows viel besser als auf Mono/Linux. – Enio

1

Ich würde Sie tun einige Profile auf den Code in Bezug auf, wie lange einzelne Methoden ausgeführt werden dringend empfohlen. Es ist ziemlich wahrscheinlich, dass Sie einige Locking- oder ähnliche Multithreading-Schwierigkeiten sehen, die von Mono nicht perfekt gehandhabt werden. Die CPU- und RAM-Nutzung würde ebenfalls helfen.

1

Ich glaube, das könnte das gleiche Problem sein, das wir mit dem Thread-Pool und das Startverhalten für neue Threads aufgespürt, sowie einen Fehler in der Mono-Implementierung von SetMinThreads.Bitte beachten Sie meine Antwort auf diesen Thread für weitere Informationen: https://stackoverflow.com/a/12371795/1663096