Oder: wenn Debian nicht mehr richtig tickt.
Seit einer ganzen Weile benutzen ein paar Freunde und ich einen Hetzner EQ 6 Root-Server. Da dieser ganz vernünftige Systemperformance bietet, haben wir uns dazu entschieden, diesen als Host für VirtualBox zu benutzen, sodass jeder seine eigene virtuelle Maschine haben kann. Also haben wir ein paar virtuelle Maschinen mit identischer Konfiguration eingerichtet, was auch ganz gut funktionierte — bei den anderen jedenfalls. An diese Stelle sollte ich vielleicht erwähnen, dass es sich bei der Host-CPU um einen Intel Core i7 920 handelt, d.h. vier Kerne mit HyperThreading, also insgesamt acht virtuelle Kerne. Host und Gäste sind aktuelle Debian-Installationen (oder Derivate davon, wie z.B. Ubuntu Server Edition).
Am Anfang hatte meine Maschine erstmal sehr wenig zu tun. Irgendwann bekam sie einen Apachen, der auch noch nicht so viel zu leisten hatte. Über die Zeit lernte er dann irgendwann SSL/TLS, PHP, Perl/CGI, Python/CGI und musste dann auch diverse tracs und Subversion-Repositories über verschlüsselte Kanäle ausliefern. Im Hintergrund lief noch ein fleißiger PostgreSQL-Dienst, sowie Postfix mitsamt Spamabwehr usw., kurz gesagt: für einen Server mit dieser Ausstattung fast nichts zu tun. Irgendwann ließ ich dann einen Gameserver ein paar CPU-Zyklen fressen und schließĺich war die CPU-Auslastung im Schnitt über alle Kerne bei satten 10% (sic!). Das hat ihm das Genick gebrochen.
Im syslog tauchten dann seltsame Zeilen wie Clocksource tsc unstable (delta = 4398042164711 ns) auf, die Systemuhr lag ein paar Stunden daneben und die Zeit selbst schien nicht mehr streng monoton zu laufen:
jan@vm:~$ date Fr 10. Dez 07:13:26 CET 2010 jan@vm:~$ date Fr 10. Dez 07:13:27 CET 2010 jan@vm:~$ date Fr 10. Dez 07:13:28 CET 2010 jan@vm:~$ date Fr 10. Dez 07:13:29 CET 2010 jan@vm:~$ date Fr 10. Dez 07:13:25 CET 2010 jan@vm:~$ date Fr 10. Dez 07:13:28 CET 2010
Zuerst habe ich versucht, das mit regelmäßigen Aufrufen (cron) von ntpdate wieder in den Griff zu bekommen. Dann kam ein Zeitsprung von vier Stunden, den ntpdate nach ein paar Minuten wieder korrigierte. Das hat auch keiner mitbekommen, bis auf Dovecot, dem IMAP-Dämonen. Der hat plötzlich den Dienst verweigert, weil er meinte, dass meine Mails wohl kaum in der Zukunft empfangen worden sein können. Damit hat er ja auch recht. Also, cronjob entfernt und Chrony installiert. Der sollte die Systemzeit immer genau im Auge behalten und bei Bedarf nachkorrigieren. Endlich lief's — bis die Systemlast stieg.
Hin und wieder, wenn ich irgendwas von der Kiste wollte, z.B. im trac arbeiten oder frische SVN-Revisionen hochladen, blieb sie einfach stehen, fast jedenfalls. Ich konnte mich noch via SSH einloggen, aber sobald ich irgendwas wollte, was über „ls” hinausging, rührte sich einfach nichts mehr. Selbst ein reboot war nicht mehr drin. Da blieb nur noch ein Hard Reset mit Ctrl+C auf der Hostmaschine. Symptombekämpfung beiseite, jetzt war Ursachenforschung angesagt.
Syslog? Nichts. auth.log? Nichts. Kein Logfile hat irgendwelche verdächtigen Meldungen ausgespuckt, bis auf "Clocksource tsc unstable", was ich ja schon kannte. Gleich der zweite Treffer bei Google ließ mich hoffen: ein Bug Report auf der VirtualBox-Webseite, der genau mein Problem schildert. Sämtliche Kommentare gelesen, dem Kernel irgendwelche abenteuerlichen Optionen mitgegeben, die die Timer-Interruptfrequenz beeinflussen sollen. Meine längste Optionenkette war „noapic nolapic nolapic_timer notsc divider=10 clocksource=acpi_pm“. Mein System hielt etwas länger durch als sonst, aber der Erfolg war noch fern. Das einzig Erfolg versprechende war, SMP im Gast abzuschalten, d.h. nur noch einen Kern für das System. Aha, höchst interessant, aber die Erleuchtung blieb noch immer aus. Ich habe ich mich auf die VirtualBox-Mailingliste gesetzt und begierig jede Mail studiert, die ein Update ankündigte. Jeder zweite Patch hat irgendwas am Timing geändert, aber nicht mein Problem behoben. Aus Verzweiflung habe ich dann Debian neuinstalliert, sogar meine alten Festplattenimages gelöscht und neu erzeugt, falls da irgendeine Datei korrumpiert war. Schließlich lief es ein paar Wochen, allerdings fast ohne Last. Immerhin war mein Mailverkehr wieder einigermaßen zuverlässig.
Dann fing in der Uni die Prüfungszeit an und, wie es so ist, macht man alles, um nicht lernen zu müssen. Zum Beispiel einen Test der Kühlung im Serverraum des Rechenzentrums von Hetzner. Dazu habe ich die cpuburn-Suite installiert, die Software für jeden Kern einmal gestartet (also acht Instanzen) und laufen lassen und mit htop die Auslastung überwacht. Da kam mir die Eingebung: htop hat, bevor ich die cpuburn-Instanzen gestartet habe, %NaN als CPU-Auslastung angezeigt! Wie kommt sowas? Division durch null oder so. Da wird bestimmt durch die seit n Ticks vergangene Zeit geteilt, oder so ähnlich, jedenfalls scheint die Zeit irgendwie nicht in Ordnung zu sein. Mehrere Bug Reports, deren Webseiten, deren URLs ich leider nicht mehr zur Hand habe, erzählen dann davon, dass die Systemtimer von der CPU-Frequenz abhängen oder zumindest darüber kalibriert werden. Das führte mich zu folgender Überlegung: Jeder der Gäste hat acht Kerne zur Verfügung und der Host selbst besitzt insgesamt acht Kerne, irgendwie muss VirtualBox also einen Scheduler haben, der die Rechenzeit zuteilt. Das impliziert wiederum, dass bei einem Gast auch mal ein Kern „angehalten“ wird, wenn er gerade von einem anderen Gast beansprucht wird. Das weiß der Gast allerdings nicht und wird er auch nie zu wissen bekommen, schließlich denkt er ja dank Virtualisierung, dass er die alleinige Herrschaft über das System besitzt — und dem entsprechend die Timerfrequenz einstellt. Das Ganze macht natürlich die Kalibrierung zunichte.
Das Zauberwort heißt „High Precision Event Timer“. Diesen Timer kennt man möglicherweise aus Multimediasoftware, bei der es wirklich auf's Timing ankommt, wie z.B. MIDI-Sequenzern wie Rosegarden oder Steinbergs populärem Cubase. Dieser Timer tickt unabhängig von der CPU-Frequenz, ist sehr hoch getaktet (auf modernen Systemen >100MHz) und liegt auch hardwaremäßig außerhalb der CPU. VirtualBox ist sogar in der Lage, den HPET an die Gäste weiterzureichen, um ihn so als präzise Zeitquelle des Kernels zu benutzen. Dazu gibt es in der VirtualBox GUI allerdings keine Option, so muss die Kommandozeile auf der Wirtsmaschine her:
jan@vmhost:~$ VBoxManage modifyvm vmname --hpet on
Schließlich gibt man dem Linux-Kernel im Gast noch die Option "clocksource=hpet" mit. Bei (Legacy-)GRUB sucht man in der /boot/grub/menu.lst das Schlüsselwort #kopt und hängt an dessen Ende die oben genannte Option an (nicht das Kommentarzeichen „#“ entfernen!). Bei GRUB 2 hängt man die entsprechende Option an die Variable GRUB_CMDLINE_LINUX_DEFAULT an. Die Änderungen müssen natürlich als root gemacht werden und schließlich führt man als root noch update-grub aus.
Das Ende vom Lied ist (m)ein System, das inzwischen seit mehreren Wochen auch unter Last (cpuburn) stabil arbeitet, und eine verblüffend präzise Uhr hat. Ich konnte sogar auf alle ntp-Derivate auf dem Host und auf dem Gast verzichten! Natürlich ist diese „Anleitung“ mit Vorsicht zu genießen und meine Erklärungen erklären auch nicht alle Symptome, wie z.B. die plötzlichen Vier-Stunden-Sprünge oder warum das Problem nur auf einem der vier Gäste auftrat. Nicht vergessen: vor Systemeingriffen immer schön Backups machen. Es ist nicht meine Schuld, wenn Ihr System hinterher nicht mehr funktioniert. Sagen Sie hinterher nicht, ich hätte Sie nicht gewarnt!