Pimp my bhyve

Columbo0815

Kaffeemann
Teammitglied
Moin,

die Dokumentation von bhyve ist leider nicht die allerbeste. Viele Optionen funktionieren, aber wann wähle ich welche und was ist der Vor-/Nachteil? Ohne Hintergrundwissen oder Erfahrungswerte ist es schwer die Dokumentation zu verbessern. Ich würde mit diesem Thread gerne verschiedene Informationen zusammentragen, die dazu führen, dass bhyve noch performanter läuft oder nützliche Optionen genutzt werden. Zum Verständnis: Ich virtualisiere hauptsächlich einen Windows-Gast, der produktiv genutzt wird. Aber Es soll nicht ausschließlich um Windows gehen, kann aber ggfls. von Relevanz sein.

Für den Anfang nehme ich mal 4 Bereiche:

Festplatte:
Es gibt (mindestens) "ahci-hd" und "nvme". Wann macht welche Option Sinn? Ich habe hier ein FreeBSD das auf einer nvme mit zfs installiert ist. Inzwischen habe ich den Windows-Gast auf einem "zvol" installiert. Aktuell nutze ich noch "ahci-hd". Bringt nvme Geschwindigkeit?

Netzwerk:
Worin ist der Unterschied zwischen virtio-net und e1000? Welches Device sollte ich wann nutzen?

Hostbridge:
Es gibt hostbridge und amd_hostbridge. Die manpage sagt, dass die emulation identisch ist aber die "PCI vendor ID" von AMD genutzt wird. Was ist der Hintergrund? Auch wenn ich eine AMD-CPU nutze und "hostbridge" verwende läuft der Gast. Ist das nur, damit der Gast "AMD" anzeigt?

CPU:
Ich kann Sockets, Cores und Threads durchreichen. Wann macht welche Option Sinn? Ich habe zB einen AMD Threadripper mit 32 Threads. Macht es einen Unterschied (von den lizenzrechtlichen Dingen des Gastes mal abgesehen), ob ich 16 Cores oder Threads "durchreiche"?

Freue mich über rege Teilnahme :)
 
Sobald der Gast virtio-Treiberunterstützung hat, gebe ich ihm virtio-blk. Weniger overhead, mehr netto vom brutto. ;)
ahci-hd wird genommen, wenn es ein alter Gast ist/eben kein virtio unterstützt wird.

Hier ebenso mehr netto vom brutto mit virtio-net. e1000 nimmt man 'erstmal', weil damit die Wahrscheinlichkeit sehr hoch ist, dass der Gast bereits einen Treiber hat und direkt online ist. Wenn dein Gast nach der Installation offline ist (wegen mangelndem virtio-net Treiber), kannst du ihn schlecht herunterladen. Henne/Ei ;)

Eine explizite Antwort kenne ich dazu nicht. Ich vermute man hat es eingebaut, weil man es kann und weil es Software (bundled, Lizenzgedöhnse) geben könnte, die sich beim jeweils anderen weigert.

Ganz grob kann man damit Systemressourcen vom Host begrenzen. Wenn der Host schwitzt, leiden die Gäste. Es kommt darauf an, wie deine Software optimiert ist. Wenn du winsoftware einsetzt, die eh nicht mehr als zwei Kerne nutzen kann bringen dir 4 zugewiesene wenig. Vom gut gemeinten Puffer für winupdates im Hintergrund mal abgesehen und was da sonst noch läuft. ;)
Alte Gäste crashen evtl. mit mehr als einem Kern.
Es ist dienlich, wenn du Limits setzen musst, damit deine Lizenz passt.
Mit genauem Blick auf dein CPU-Modell kommt es darauf an, wie und wieviel Cache an den Kernen dranpappt.
Im Zweifel einfach mal benchmarken. Manches performt mit Threads besser, manches mit Kernen. Auch sollte man dabei die Last während dem Run auf dem Host vergleichen. Wenn 50% Gastlast (Zangendeutsch ftw) 400% Last auf dem Host erzeugen ist es doof, da freut sich nur der Energieversorger.

Wie im IRC schon angedeutet, gibts hier viel Info:
https://github.com/churchers/vm-bhyve/blob/master/sample-templates/config.sample
 
Sobald der Gast virtio-Treiberunterstützung hat, gebe ich ihm virtio-blk. Weniger overhead, mehr netto vom brutto. ;)
ahci-hd wird genommen, wenn es ein alter Gast ist/eben kein virtio unterstützt wird.
Interessant. Und virtio-blk ist nvme auch vorzuziehen?

Hier ebenso mehr netto vom brutto mit virtio-net. e1000 nimmt man 'erstmal', weil damit die Wahrscheinlichkeit sehr hoch ist, dass der Gast bereits einen Treiber hat und direkt online ist. Wenn dein Gast nach der Installation offline ist (wegen mangelndem virtio-net Treiber), kannst du ihn schlecht herunterladen. Henne/Ei ;)
Ok, was ist der Grund dafür, dass virtio-net (oder -blk) mehr Overhead hat? Hier benutze ich tatsächlich virtio-net. Damit ich das nutzen kann, habe ich ein ISO eingebunden, das den Treiber enthält.

Mit genauem Blick auf dein CPU-Modell kommt es darauf an, wie und wieviel Cache an den Kernen dranpappt.
Reiche ich denn tatsächlich echte Cores oder Threads in den Gast oder "sieht er das nur als eben solche" und bekommt eigentlich nur Rechenzeit zugewiesen?
 
Ok, was ist der Grund dafür, dass virtio-net (oder -blk) mehr Overhead hat?

Weniger Overhead, nicht mehr. :) Sie sind effizienter. Virtio ist virtuelle Hardware, die darauf ausgelegt ist, in virtualisierten Gastsystemen genutzt zu werden. Daher lässt sie sich sehr effizient in Software implementieren. Während echte Hardware meist Kompromisse bedeutet, wenn sie in Software emuliert wird. Wodurch sie langsamer ist.
 
Und virtio-blk ist nvme auch vorzuziehen?
Da sag' ich mal nein. Mit nvme kenne ich mich nicht aus, habe solche HW noch nicht im Einsatz. Ich vermute, dass man damit die ganze nvme samt ihren Funktionen dem Gast hinstellt und vor dem Host verbirgt.

"sieht er das nur als eben solche" und bekommt eigentlich nur Rechenzeit zugewiesen?
Eher jenes. Wobei ich jetzt nicht weiß, ob es schon möglich ist ganze Sockel zu paravirtualisieren.
Der Klassiker dazu ist HW im Ganzen durchzureichen, dh. die HW 'verschwindet' vom Host und steht nur dem Gast explizit zur Verfügung. Das geht sehr gut mit Intel NICs, sogar gezielt einzelne Slots und nicht zwanghaft die ganze quadnic. Da nutzt man dann native im Gast den Treiber zur HW und das ist dann nochmal schneller, ergo noch weniger overhead.
 
Weniger Overhead, nicht mehr. :)
Sowas kommt raus, wenn man den Satz ursprünglich anders schreiben wollte. Danke für die Klarstellung, eigentlich hatte ich das so gemeint. :)

Da sag' ich mal nein. Mit nvme kenne ich mich nicht aus, habe solche HW noch nicht im Einsatz. Ich vermute, dass man damit die ganze nvme samt ihren Funktionen dem Gast hinstellt und vor dem Host verbirgt.
Das wäre PCI-Passthru. Ich hab' kürzlich ein zvol erstellt und das zvol als Festplatte mit nvme genutzt. Das zvol lag zwar auf einer nvme, aber durchgereicht habe ich eben nur das zvol. Ich glaube ich frage das mal in #bhyve. Interessant finde ich das schon.
 
Ja, frag mal. Und schmatz auch gleich die Sache mit der hostbridge mal ab. :p

Ich habe auch schon einen LSI2308 durchgereicht, könnte daher auch mit den Slots vom AHCI-Controller klappen, wenn PCI-passthrough nicht zu 100% auf PCI/PCI-E limitiert ist. ;)

Ich weiß auch gar nicht, als was das System diesen nvme-Slot anzeigt.
 
Das grundsätzliche Problem sind Wechsel zwischen Host und Gast. Das sind bei Hardwarevirtualisierung mit Intel VT-x und AMD SVM (zwei völlig unterschiedliche Implementierungen) hauptsächlich zwei Operationen:
  • VM Entry, die CPU räumt den Kontext des Hosts komplett ab und lädt den Kontext des Gast.
  • VM Exit, genau umgekehrt. Die CPU räumt den Kontext des Gasts komplett ab und lädt den Kontext des Host.
Diese Kontextwechsel sind extrem teuer, da moderne CPUs und die zugehörige Peripherie wie beispielsweise die MMU riesige Mengen State haben. Der persistente Teil des States des aktuellen Kontext muss extrahiert und im RAM gesichert, der flüchtige Teil des State zurückgesetzt werden. Anschließend kann man den persistenten Teil des States des neuen Kontext laden. Das alleine dauert hundertausende bis Millionen CPU-Zyklen. Dazu kommt, dass nach so einem Kontextwechsel die Pipelines und die internen Buffer leer sind. Oft werden auch der TLP und die Caches teilweise zurückgesetzt. Daher muss die CPU sich sozusagen erst wieder warmlaufen, was große Mengen weiterer Zyklen kostet.

Die Hardwarehersteller haben daher extrem viel Aufwand getrieben, Kontextwechsel zwischen Host und Gast günstiger zu machen. Als ich das TLP Shadowing implementiert habe, konnte ich die Fortschritte gut sehen. Auf dem Thinkpad X200 mit Sandy Bridge CPU, auf dem ich hauptsächlich getestet habe, maß ich pro Kontextwechsel zwischen 2 und 3 Millionen Zyklen. Auf meinem Skylake Desktop waren es unter einer Million. Und die Entwickler der Hypervisoren haben jede Menge Hirnschmalz darein gesteckt, mit möglichst wenig Kontextwechsel auskommen und wenn sie notwendig sind, den zu sichernden und wiederherzustellenden State gering zu halten.

Leider ist Bhyve ein kleines Projekt und daher in seinen Möglichkeiten begrenzt. Was nicht heißt, dass Bhyve ein schlechter Hypervisor ist. Beispielsweise kennt Bhyve keine Hypercalls (es gibt da ein Projekt, aber ob sich das jemals materialisiert ist fraglich) oder einen ähnlichen Mechanismus, also im weiteren Sinne kontextwechselfreie Kommunikation zwischen Gast und Host. Auch ist die virtuelle / emulierte Hardware nicht unbedingt optimal hinsichtlich der Vermeidung von Kontextwechseln implementiert. Das ist alles kein Beinbruch, führt aber dazu, dass Bhyve je nach Einsatzszenario mal mehr und mal weniger gegenüber den großen und über wesentlich mehr Manpower verfügenden Konkurrenten wie qemu + KVM oder sogar VMware ESXi zurückliegt. Wobei man durchaus durch Konfiguration einiges an Boden gut machen kann.

Generell ist es eine sehr gute Idee kein Overcommitting zu betreiben. Also insgesamt nicht mehr virtuelle Kerne zu vergeben, als der Host physische Kerne hat. Idealerweise pinnt man die virtuellen Kerne noch auf physische Kerne und lässt einen, besser gleich zwei Kerne für den Host frei. Damit verhindert man, dass der Host und die VMs Ping Pong spielen. Der Host benötigt einen Kern und schmeißt einen Gast von einem Kern -> Bhyve legt den Gast wieder auf den Kern -> Ein anderer Gast braucht den Kern, also Gast 1 runter und Gast 2 -> Und so weiter. Dabei migrieren die virtuellen Gast-CPUs noch wunderbar über die physischen Kerne der Host-CPU, es wird also nicht nur State gesichert und geladen, sondern auch noch hin und her kopiert. Das ist die Option -p. Bei CPUs oder Multisockelsystemen, die nicht uniform aufgebaut sind, sollte man außerdem drauf achten, dass möglichst alle Kerne eines Gasts in einer Domäne der Host-CPU liegen. Da kommt die Topologie mit -c ins Spiel. Hat ein Gast beispielsweose virtuelle Kerne, die auf zwei physische Sockel verteilt sind, kann man es mit der Topologie kommunizieren.

In Sachen virtueller Hardware sind paravirtuelle Geräte - also konkret virtio-blk, noch etwas besser aber schwer anzuwenden virtio-scsi und virtio-net - immer zu bevorzugen. Diese Geräte sind so gebaut, dass sie mit möglichst wenig Kontextwechseln zwischen Gast und Host auskommen. Konkreter:
  • Bhyves e1000 Emulation ist bröselig, ich hatte damit immer Probleme wie verlorene Pakete oder sogar hängen gebliebenes Netzwerk. Und davon abgesehen ist sie deutlich langsamer als virtio-net. Man kann sie eigentlich nur benutzen, wenn man einen Gast mit integriertem e1000-Treiber hat und erst einmal einen virtio-net Treiber reinkopieren muss. Also vor allem um ein Windows aufzusetzen.
  • AHCI ist insgesamt ein ziemlicher Murks. Es ist ein Wunder, dass der Kram weit ins SSD-Zeitalter überlebt hat. Und Bhyves AHCI-Emulation ist noch mal besonders langsam. Das fällt vor allem unter Windows, was wenig cached, auf. Das einzige Argument für AHCI war, dass es gute Treiberunterstützung durch Gastsysteme hat und TRIM durchreichen kann. Inzwischen gilt beides auch für NVMe, damit sollte man es vermeiden.
  • NVMe ist für Virtualisierung durchaus gut geeignet und Bhyves Emulation ist inzwischen auch gut. Da der virtio-blk Treiber für Windows eher lala ist, war meinen Messungen im Sommer zufolge NVMe unter Windows-Gästen leicht schneller. Unter Linux- und FreeBSD-Gästen hingegen virtio-blk. Das bewegte sich aber im Bereich +/- 10%, also kein Grund vorhandene Gäste umzubauen.
  • Bhyves virtio-blk könnte schneller sein, vor allem im Vergleich mit qemu + KVM ist eher eher langsam. Aber im Großen und Ganzen ist es schnell genug, im durchschnittlichen Workload wird man die Grenzen nicht erreichen. virtio-scsi wäre schneller, ist aber kompliziert zu nutzen und daher eigentlich nur bei einem sowieso genutztem, zentralem Storage per ISCSI-Anbindung sinnvoll.
 
Eine kurze Zwischenmeldung, da ich ein wenig getestet habe:

Ich habe je einen neu installierten Windows 10-Gast auf einer nvme mit zvol (zfs) und

  1. ahci-hd
  2. virtio-blk
  3. nvme
installiert. Die Unterschiede waren marginal und schwankten zwischen 1200MB/sec (ahci-hd) und 1600MB/sec (virtio-blk). nvme hatte ebenfalls um die 1500MB/sec. Sehr auffallend finde ich, dass meine Produktivmaschine (mit ahci-hd) nur 600 MB/sec schafft, obwohl auch ahci-hd trim unterstützen soll.

Weitere Tests folgen.
 
trim unterstützen soll.
trim ist ja sowieso nur interessant bei Schreiboperationen. Und trim als solches macht ja auch erst mal nix. Es teilt der SSD ja lediglich mit, das ein bestimmter Block frei ist. Das führt dann dazu, das die SSD-eigene GarbageCollection die entsprechenden Flashzellen dann irgendwann auch physisch löscht, so das bei einem Schreibzugriff dieser Block dann quasi sofort zur Verfügung steht.
Das führt dazu, das trim nicht sofort sichtbar wird, sondern eher einen Langzeiteffekt hat. Hat man kein trim-Support merkt man das nicht sofort, sondern erst später, wenn alle freien/unbeschriebenen Blöcke aufgebraucht sind, das dann die Schreibrate in den Keller geht.

Übrigens: Seit FreeBSD 12.2 hat auch virtio-blk trim-Support. Siehe dazu auch:
https://svnweb.freebsd.org/base/releng/12.2/usr.sbin/bhyve/pci_virtio_block.c?view=log
 
Hat man kein trim-Support merkt man das nicht sofort, sondern erst später, wenn alle freien/unbeschriebenen Blöcke aufgebraucht sind, das dann die Schreibrate in den Keller geht.
Deswegen meine Äußerung in Bezug auf die Produktivmaschine. Die läuft ja schon eine ganze Weile. Aber zutreffend ist natürlich, dass man dies nur bei Schreiboperationen bemerkt. Getestet habe ich tatsächlich nur Lesegeschwindigkeit. :)

Übrigens: Seit FreeBSD 12.2 hat auch virtio-blk trim-Support. Siehe dazu auch:
https://svnweb.freebsd.org/base/releng/12.2/usr.sbin/bhyve/pci_virtio_block.c?view=log
Ja, das hatte ich noch in Erinnerung. Das ist mit ein Grund für meine Tests.
 
Es könnte auf deiner Produktivinstallation theoretisch noch ein Problem mit Block-Alignement und Block-Größen sein. Denn in Standardeinstellung nutzt Bhyve auf ZFS Volumes eher untypische 8k Blöcke. Dafür fehlt mir aber wirklich das Detailwissen über Windows-Interna. Ich weiß nur, dass Windows schon seit sehr langer Zeit (Win 7 auf jeden Fall, vielleicht schon davor) Partitionen auf 2 Megabyte ausrichtet, was für wirklich jedes auch nur halbwegs gängige Blockgröße passen sollte. Keine Ahnung was NTFS treibt und woher es die Informationen bekommt.
 
Zurück
Oben