End2End-CPU

Ich habe nicht gedacht, dass ich wirklich mal diese Seite erstelle aber ein Vorfall mit VMWare hat mir gezeigt, dass man auch die CPU-Leistung ab und an mal müssen sollte. Diese Seite beschreibt ein einfaches, wenngleich sicher nicht ausgereiftes, Verfahren um eine CPU einem kurzen Test zu unterziehen.

Der Auslöser

Angefangen hat alles mit der Installation einiger neuer Exchange 2013 Server und DCs auf einer VMWare-Farm die wirklich "mächtig" war. Hosts mit 4 Sockeln, in der je ein Xeon E7-8837 mit 2,67GHz a 8 Cores steckt, also 32 CPUs und von 1TByte RAM flankiert werden, sollte kein Problem mit etwas Exchange und Domain Controller haben. Die DCs hatten einfach nur zwei virtuelle CPUs aber schon bei der normalen Arbeit machte das System einen doch "trägen" Eindruck. Immer häufiger sah die CPU-Anzeige im Taskmanager des Gast wie folgt aus:

Als ich dann noch mit NetMon 3 einen LDAP-Client analysieren durfte, war die Last gar bei 100% und jede Aktion deutlich verzögert. Ein Blick auf den VMWare-Host zeigte aber nichts ungewöhnliches. Angeblich hat der Gast nur 22% der dedizierte zugewiesenen CPU verwendet. Also habe ich parallel noch einen End2End-LDAP gestartet und hier sehr wohl gesehen, das die Antwortzeit des Domaincontrollers im Vergleich zu anderen DCs deutlich langsamer war.

Die Messung

Damit war natürlich mein Ehrgeiz gepackt. Zum einen sollte VMWare endlich den Gast auch auf 100% der zugeteilten Ressourcen bringen und ich wollte etwas zu Vergleichen haben, ohne auf produktiven Servern extra eine Software zu installieren. Dass eine Taschenrechner mit der Fakultät eine CPU zum Schwitzen bringen kann, ist ja bekannt, aber ich habe einen anderen Weg gewählt. Ich habe einfach ein PowerShell-Script geschrieben, welches eine Schleife wiederholt und zählt, wie oft diese in 1 Sekunde durchlaufen wird. Eigentlich ganz unspektakulär.

$start = get-date
$count = 0
while ($true) {
   if (((get-date) - $start).totalseconds -ge 1) {
      write-host $count
      $start = get-date
      $count = 0
   }
   $count++
}

Sie können der Code per Zwischenablage problemlos in eine geöffnete PowerShell kopieren und direkt ausgeführen. Das Skript kann mit CTRL-C jederzeit abgebrochen werden. Das sieht dann wie folgt aus:

Das Skript ist natürlich nicht auf Performance "optimiert", wird nur interpretiert, macht kein Multithreading etc. Da das PowerShell-Script immer nur auf einer CPU als Single Thread läuft, kann der Test auch nur einen Kern auf 100% bringen. Um alle Kerne auf Volllast zu bringen, müssen Sie das Script einfach mehrfach starten. Da dabei aber kein Disk-IO oder LAN-IO oder Abgleich erfolgt, skaliert dies ziemlich linear, bis alle CPUs beschäftigt sind. Mehrere Instanzen verändern das Ergebnis einer Instanz fast gar nicht. Daher reicht es das Skript einfach einmal auszuführen und dort die Schleifenanzahl zu notieren, die jede Sekunde ausgegeben wird. Die Werte schwanken, wenn die VM nicht "unbeschäftigt" ist oder die Virtualisierung die Ressourcen anders verteilt. Auch Hyperthreading könnte die Werte natürlich verändern.

Das Ziel dieses Tests ist aber mit einfachsten Mitteln mal zu sehen, in welche Bereiche welche CPU vorstoßen und vielleicht extreme Ausreißer zu erkennen.

Die Ergebnisse

Ich habe mir Auswirkungen durch den CPU-Typ und natürlich die Taktrate erwartet. Da das Skript sehr kurz ist, kann man damit natürlich kaum den CPU-Cache ausreizten o.ä. Hier mal ein paar Messwerte.

Wenn Sie das selbst Skript ausführen, dann können Sie mir gerne ihre Werte zukommen lassen.

Messung

CPU-Typ

Taktrate
in GHz
Socket/
Kern/Threads
Taskmanager P/V

Bemerkung

Count

1

i3-2120

3,3

4

4

P

HP Desktop

10000-12000

2

Xeon E5620

2,4

1/4/8

2

V

Net at Work Terminal Server

4600-6600

3

Xeon E5-2650

2,0

1/8/16

16

P

physikalischer Domaincontroller

6000-8000

4

Xeon E7-8837

2,67

2

2

V

Virtueller DC

800-1600

5

Xeon E7-8837

2,67

4/8/8

8

V

Virtueller Exchange CAS

1800-2300

6

Xeon E7-8837

2,67

2

2

V

Virtuelle PKI-CA

2400-2600

7

Core i7 M620

2,67

1/2/4

4

P

Mein T510 Notebook

5000-5200

8

Core i7 860

2,80

1/4/8

8

P

Dell Vosto 430 HyperV Host

11800-12500

9

Core i7 860

2,80

1

1

V

PRTG VM auf Dell Vosto

11500-13800

Interessant ist, dass der kleine i3 oder i7 mit der hohen Taktrate (Messing 1) in dem Test alle anderen Server-Prozessoren schlägt. Aber ebenso ist zu sehen, dass die CPU-Anzahl keinen direkten Einfluss hat, was ich aber erwartet hatte. Allerdings irritiert schon, dass der virtuelle DC (Messung 4) und die anderen Systeme so deutlich zurück hängen und dass die virtuellen Systeme (Messungen 4,5,6) auf dem High-End Xeon E7 so viel Abstand zu den anderen virtuellen und physikalischen Server haben. Da muss also etwas faul sein. Der Eindruck hier auf "lahmen Servern" zu arbeiten, hat mich also nicht getäuscht.

Bei dem Kunden wurde eine VM auf verschiedene VMWare-Server mit unterschiedlichen CPUs verschoben und auf allen anderen Servern waren die Zahlen in Ordnung. Nur auf den neuen Hosts mit dem E7-8837 war die Performance aller Server in Hinblick auf diesen Test sehr schlecht.

Ursache und Behebung

Nachdem die "Problemserver" derart eingekreist waren, wurde nach Updates und bekannten Bugs bei den Herstellern gesucht. Hierbei ist dann auch aufgefallen, dass das installierte Bios nicht die aktuellste Version war. Es handelte sich um HP ProLiant DL580 G7 Server und diese hatten noch das Bios 2013.07.1. Auf der Seite von HP (http://h20564.www2.hp.com/hpsc/swd/public/readIndex?sp4ts.oid=4142793&swLangOid=8&swEnvOid=4115) gibt es aber schon ein wichtiges Updates zum VMWare:

Natürlich kann man fragen, warum das nicht schon früher aufgefallen ist. Auf der anderen Seite stellt sich natürlich die Frage, warum vor kurzem gelieferte Server eine so alte Firmware hatten. Kaum war die Firmware aktuell, liefen nicht nur die VMs gefühlt viel flotter, sondern auch mein Testprogramm konnte die CPU zwar weiterhin auf 100% bringen, aber schaffte dann 12000 statt 800 Durchläufe und die VM-Ware Konsole zeigte dann auch 100% Auslastung für diesen Gast.

Bewertung

Aufgefallen ist dies aber letztlich nur daran, dass ich ein gänzlich anderes nachverfolgt habe und mir dabei die ungewöhnliche Performance (weniger als ein zehntel) aufgefallen ist. Was wäre aber passiert, wenn so ein umstand vielleicht nur ein Viertel Performance brach liegen lassen würde. Das würde vermutlich gar nicht auffallen. Ich nehme für mich mit, dass man jedes System zumindest einem einfachen Test unterziehen sollte, um zumindest grobe Konfigurationsfehler zu erkennen. Dies betrifft alle Kernkomponenten:

  • CPU
    z.B. mit dem hier beschriebenen PowerShell kann man nur schätzen, ob die CPU-Leistung sich auf dem gleichen Niveau wie andere Server bewegt. Es kann aber nicht auf die Besonderheiten von CPUs, L1/L2/L3-Cache und verschiedene Befehle eingehen. Das ist aber vielleicht sogar ein Vorteil, wenn alle CPUs mit letztlich dem gleichen Code konfrontiert werden.
  • Netzwerk/LAN
    Mit Programme wie NETIO/IPERF u.a. kann man zumindest zwischen zwei Systemen mal kurzfristig ermitteln, was technisch möglich wäre und ist allemal besser als ein Kopiervorgang mit dem Explorer, der dann eine Datei von einem anderen Server überträgt. Da verfälschen die Leseperformance auf dem Sender, Schreiben auf dem Ziel und der Protokolloverhead die Daten.
  • Disk
    Für Exchange gibt es mit JetStress ein gutes Werkzeug für einen Test vor der Produktivinstallation. Aber Disks zu müssen ist nicht einfach, da jeder Service andere Anforderungen braucht. Ein einfacher COPY kann nie die Leistung ermitteln

All diese Tests sind natürlich nur bedingt für die Produktion aussagekräftig. Ein Single Thread-Programm kann z.B. nie das Zugriffsmuster von SQL, Exchange oder anderen Diensten nachstellen. Es ist also eher das Schätzen einer Höchstgeschwindigkeit eines Autos ohne geeichte Messeinrichtungen, normierte Straße, ohne Berücksichtigung der Wetterbedingungen oder sonstigen Verkehren.

Regelmäßige Überwachung

Physik ändert sich in der Regel nicht, es sei denn ein Kern fällt aus und das Bios schaltet die CPU nach dem Reboot einfach ab. Das sollten Sie aber schon durch das Board-Management feststellen können. Wenn Sie aber mit virtuellen Systemen arbeiten, dann könnte es schon sein, dass im Laufe der der Zeit vom Betreiber der Plattform andere Gäste mit anderen Lasten ihrem Gast Leistung entziehen. Das ist wahrscheinlicher, wenn der Betreiber entgegen den Empfehlungen mit "Thin Provisioning" und "Over-Subscription" arbeitet, d.h. darauf spekuliert, dass VMs nicht immer die komplette Leistung beziehen und man damit mit genug VMs den Server überbuchen kann. Wenn dann mal alle VMs wirklich alle ihre Leistung abrufen wollen, dann wird es eben langsamer, als versprochen.

Natürlich kann man nun per Performancecounter die CPU-Last eines Server ermitteln. solche Messungen sind aber immer eine Stichprobe. Leider geben die meisten Betriebssysteme immer nur die aktuelle Auslastung her und keine Mittel/Max/Min/Burst-Werte. So ist es oftmals bei einer Messung nur Glückssache, ob man nun eine Lastspitze oder Senke erwischt. Sicher mitteln sich die Werte über die Zeit aber wie beim Netzwerk kann eine Messung alle Minute keine kürzeren Hochlastphasen zuverlässig erkennen.

Wenn ich aber mit dem obigen PowerShell einen einzelnen Core schon auf 100% bringen kann, kann könnte ich doch eine Schleife kurz laufen und den Counter müssen und dann wieder einige Zeit "warten" und dann den gleichen test wiederholen. Wenn ich mir die Counter oben ansehe, dann erhalte ich 2000-4000 Durchläufe pro Sekunde pro GHz. Also könnte ich z.B. 50 Millisekunden laufen und 950 Millisekunden schlafen und so immer werde zwischen 100-200 erhalten. Die CPU hätte dann gerade mal 5% mehr "Grundlast".

Damit wird es schon mal interessant, einfach eine solche Überwachung zu bauen. Im Kern ist es folgender Code:

while ($true) {
   $count = 0
   (measure-command {1..100| %{$count++}}).totalseconds
   start-sleep -seconds 1
}

Der ganze Code muss natürlich wieder in ein Skript verpackt werden, welche die Dauer ermittelt, Mittelwerte und Maximalwerte bildet und bei Überschreitungen alarmiert. Langfristig sollte der Aufruf der Schleife immer die gleichen Laufzeiten liefern, es sei denn ihre CPU ist mit etwas anderem beschäftigt, z.B. eine anderen Gast auf der gleichen Virtualisierung.

Ein passender Sensor, z.B. .für PRTG, steht noch auf meiner Agenda.

Weitere Links