Schlechte NUMA-Konfigurierbarkeit für KVM-Gäste.

GhostTyper

New Member
Mar 10, 2025
5
0
1
Germany
Hallo Forum.

Die NUMA-Konfigurierbarkeit für KVM-Gäste ist entweder schlecht oder ich bin zu blöd. Wie dem auch sei, wir finden sicher zusammen heraus, was davon zutrifft. :D Ich bin noch auf 8.4.14, glaube aber, dass sich in dem Bereich nicht viel getan hat.

Wir haben 5 Server mit jeweils 2xEPYC 9375F, also 2 NUMA-Nodes pro Server, wenn wir die einzelnen CCDs ignorieren.

Relevante Konfigurationsparameter sind: affinity, numa und numa0. Wenn ich also eine VM habe, die in eine NUMA-Node (RAM sowie weniger als NUMA-Node CPU Kerne -2 oder so) passt ist das an für sich kein Problem. Ich setze affinity auf die Cores der ersten NUMA-Node, setze numa auf 1 und in numa0 hostnodes auf 0, memory auf den RAM der VM und policy auf bind und Zack läuft die VM (je nach Last) c.A. 35% schneller im Vergleich dazu, wenn ich das nicht tun würde.

Wenn ich nun aber eine VM habe, die zwei NUMA-Nodes braucht, weil die Anwendung mehr Ressourcen benötigt als eine NUMA-Node (also eine CPU und/oder der RAM der an ihr angebunden ist) zur Verfügung stellen kann habe ich ein Problem. affinity setzt nämlich die Zugehörigkeit für alle Threads des KVM-Prozesses, was bedeutet, dass ich dem Linux-Scheduling gnadenlos ausgeliefert bin und ich im Prinzip wieder die oben gewonnen ~35% Performance verliere, da die vCPU Threads von KVM auf beiden Host-CPUs umherscheduled werden.

Vielleicht eine kurze Zwischenfrage: Übersehe ich hier etwas oder kann man das tatsächlich nicht besser konfigurieren?

Follow-Up: Ich möchte VMs gerne lastabhängig ähnlich zu drs bei VMware (nur natürlich viel primitiver) verschieben. Dazu habe ich ein Script geschrieben, welches aus CPU%, Netzwerk und Disk I/O einen Score bildet und dann Server+NUMA-Nodes versucht "gleich" (sodass der kumulierte Score nachher möglichst gleich über alle NUMA-Nodes des Clusters ist) aufzufüllen und zwar mit so wenig wie möglich verschiebe Operationen.

Dabei gibt es folgende Herausforderungen:
  1. Ich kann über einen API-Key, der alles darf keine affinity setzen. Ich muss dazu einen root-Login machen und kann mit dem Ticket diese Einstellung ändern. (An für sich kein Problem, nur eine Umständlichkeit.)
  2. Wenn ich die Konfiguration ändere gehen die Einstellungen in [PENDING]. Das ist in dem Fall schlecht, denn ich möchte diese Einstellung wenn es auch nicht gleich geht spätestens nach einer Migration übernommen wissen. Also dachte ich, dass ich mich mit dem Script per SSH einlogge und die Datei direkt auf der Disk ändere und dann die Migration anstoße. Das funktioniert auch gut, solange vorher numa schon auf 1 war und anschließend migriert wird.
Ich hoffe ich habe genug Kontext für die folgenden Fragen geliefert:
  1. Gibt es ohne hookscript eine Möglichkeit die physischen logischen CPUs vCPUs zuzuordnen, sodass ich Konfigurationen bei denen eine VM mindestens 2 NUMA-Nodes abdecken muss effizient konfiguriert werden können?
  2. Über sehe ich etwas? Kann ich über die API eine Konfiguration auch ohne [PENDING] übernehmen - zur Not reicht es diese in die Config-Datei zu schreiben?
  3. Gibt es eine Roadmap auf der evtl. bessere NUMA-Konfigurierbarkeit oder zumindest das Live-Setzen der affinity und bisherigen NUMA-Konfiguration steht?
  4. Gibt es schon Community-Lösungen für diese Aufgabe (drs), welche das auch gut bei großen VMs die mehrere NUMA-Nodes überdecken nachrüstet?
Danke.

PS: Ja, ich brauche wirklich eine so große VM und ja die Software in dieser ist NUMA aware.
PPS: numa_balancing ändert da nicht viel und ist keine Lösung.
 
Ich glaube du machst das alles zu kompliziert.
Bei vSphere DRS hast du auch keine Cores angepinnt sondern das dem Scheduler überlassen.
Mach das doch bei KVM genauso.
Alle normalen VMs werden wenn möglich immer je von einer CPU bedient.
Hast du eine ganz große VM dann aktivierst du vNUMA und gibst der VM 2 Sockets.
Deine NUMA Aware Anwendung erkennt dann die beiden CPUs und wählt dann die richtige aus.
Übrigens gibts da schon was fertiges fürs Balancing. proxLB macht das was DRS bis vSphere7 getan hat.
Mit vSphere8 hat sich DRS geändert und man hat einen Score der die Latenz der VM beurteilt und nicht die Auslastung des Hosts.
Das gibts bisher nur aus dem Hause VMware.
 
  • Like
Reactions: Johannes S
Hey Falk,

danke für den Tipp zu proxLB, ich werde mir das angucken.

Allerdings kann ich "Alle normalen VMs werden wenn möglich immer je von einer CPU bedient" nicht bestätigen.

Ich untermauer' das mal mit Benchmarks für Speicherzugriff (leerer Host, getestet mit likwid-bench, VM mit 8 vCPUs und 64GiB RAM):

Gedankennuma_balancingaffinitynumahostnodesload (MB/s)stream_mem (MB/s)
Die Worst-Case-Baseline (Memory und CPUs auf unterschiedlichen NUMA-Nodes.)00-3111108798.89129484.39
10-3111108874.16129727.41
0-11132030.29198979.65
1-11223454.97237322.70
Nur NUMA zu aktivieren scheint schlechter zu sein als es nicht zu aktivieren, bei sonst fehlender Konfiguration.0-1-267856.26380375.15
1-1-232157.76287570.17
Das ist die "gar nichts konfiguriert" Situation.0-0-239944.94304983.40
1-0-304077.70360406.59
Ab hier sehen wir im Prinzip gleich gute Ergebnisse weil ungebundener Speicher normalerweise first touch allokiert wird, hier also Speicher immer bei den in affinity festgelegten CPUs liegt.00-3110359336.63407190.39
10-3110359264.93406696.50
00-311-359149.97404689.63
10-311-361463.18408233.35
00-310-358511.18406472.15
10-310-363356.08409195.52

Was die Geschwindigkeit also signifikant verbessert ist es die affinity auf die passende NUMA-Node (also hier Socket) zu setzen - dann geht durch Strategien wie first touch Allokation eigentlich alles automatisch und wir können im Gast sogar den NUMA-Overhead vermeiden. (Solange die VM in eine NUMA-Node passt.)

Wenn man Proxmox einfach machen lässt ist Speicherzugriff (in meinem Fall) mindestens 10% schlechter, je nach Konfiguration des Hosts (numa_balancing) sogar noch mehr.

Für VMs die über 2 NUMA-Nodes gehen müssen sehen wir im Prinzip ähnliche Verhältnisse bei den Zahlen, nur dass man hier halt keine Chance mehr mit affinity hat, weil diese nicht pro nodeX festlegbar ist. Es fällt also alles mit "höchstem" Durchsatz weg.
 
Also die gar nichts konfigurieren Situation ist eher der Normalzustand und reicht für 95% der Fälle aus.
Wenn man einzelne kritische VMs hat, kann man natürlich Tuning betreiben.
Ich empfehle seit jahren nur noch Single Socket Server zu nutzen und die Anzahl der Cores reicht bei AMD eh immer aus. Da spart man sich viel Stress mit NUMA.
Wenn du zwei 128Core CPUs benötigst, weil die 256 Core CPU zu wenig Taktrate hat, dann ist das eher ein Einzelfall und da darf man auch mal ins Tuning investieren. Das jetzt für alle VMs zu machen, finde ich persönlich etwas drüber.
 
Hey Falk,

ich stimme Dir da ganz generell zu. Vor allem weil die Performance nachher keine 10+% schlechter ist, sondern nur der Speicherzugriff und wahrscheinlich ist es auch nicht wirtschaftlich, wenn ich mich weiter damit beschäftige.

Aber Wirtschaftlichkeit ist nicht das einzige Kriterium, sondern auch einfach der Ansporn dieses Verhalten so Automatisch es geht zu verbessern. Für kleine VMs geht das gut, für große VMs gibt es halt technisch (außer wahrscheinlich hook-scripts) keine Möglichkeit das gut zu machen. (Oder ich kenne sie nicht.)

Schade ist halt, dass VMware ESXi das seit vielen Jahren (nach meinen Tests) selbst unter schwierigen Bedingungen automatisch besser macht.

Du bist übrigens nicht die einzige Person, die von NUMA-Systemen in Verbindung mit Proxmox abrät und ich verstehe jetzt auch warum. Aber es gibt Gründe für NUMA-Systeme abseits der Taktrate, nämlich z.B. doppelte Speicherbandbreite, doppelten Cache, die bei der Nischen-Anwendung dieser großen VMs nützlich sein können.