Proxmox 9 | Kernel 6.14 Performance Probleme Windows VM

Es ist "nur" ein IIS, aber die Applikationen die darauf laufen sind komplex. Dauert mal eben einen Tag das neu aufzusetzen. Optimistisch gerechnet.
Und auf dem anderen Node läuft es ja aktuell. Ein und dieselbe Maschine, ich habe sie vorhin testweise einmal umgezogen, Proxmox 8.4 mit Kernel 5.15.116.
 
Die CPU des Hosts ist ja nur eine 12Core CPU und du hast 24 Cores der VM zugewiesen.
Was passiert denn, wenn du der VM nur 12 Cores gibst?
Lastet die VM denn die CPU so sehr aus, dass die tatsächlich 24 Cores benötigt?

Ich weiß, dass der CPU Scheduler von KVM beim 6er Kernel etwas überarbeitet wurde, was da geändert wurde, weiß ich nicht, aber das wäre so mein Ansatz, das weiter einzugrenzen.
 
  • Like
Reactions: Sebi-S
Die Host CPU hat 24 vCores, (12 physische Cores, klar), aktuell habe ich also 48 vCores.
Ich hatte die Maschine auch schon auf 10 vCores reduziert von einem Socket.
Und aktuell läuft die Maschine auch mit 20 vCores auf einem Socket.

Und ja: die VM lastet die CPUs entsprechend aus, 40-60% CPU-Last ist normal. Das haben andere Webserver mit den gleichen Aufgaben in dem Konstrukt auch. Es liegt ja generell nicht an der einen VM, die läuft Ansich prima. Das Problem entsteht, wenn eine bestimmte Art von Workload auf die Kombination mit dem Kernel trifft.
 
Ab Kernel 6.14 wurde der Intel-Scheduler umgebaut (wie @Falk R. schon erwähnte). Bei Dual Xeon führt das zu:
  • Falscher Zuordnung von Threads zu L3-Domains
  • Häufiger Migration zwischen NUMA-Nodes
  • Unnötig viele „wakeups“ auf entfernten Nodes
  • Memory Access über QPI/UPI
Der Kernel macht dann falsches NUMA-Balancing, sobald der Workload viel L3 + viel Websocket/HTTP/Worker-wechselseitigen Traffic erzeugt, was bei Deinem IIS dann der Fall ist. Dieser nutzt Web Core Thread Pools, Request Queues, HTTP.sys Kernel Mode Driver & Worker Processes, welche alle sehr NUMA-"sensitiv" sind. Ebenso abähngig von der L3-Cache-Lokalisierung und zudem anfällig, wenn Threads auf andere NUMA-Nodes migrieren. Wenn der 6.14er falsch balanced, dann führt das zu hoher CPU-Auslastung, vielen L3-Misses, Latenzproblemen, Einbrüche beim Web-Traffic und instabiler Performance. IIS nutzt zudem den "NUMA Node Affinity"-Mechanismus (siehe MS-Link HIER), was normalerweise dafür sorgt, dass jeder Worker-Prozess an einen NUMA-Node gebunden wird und die Verarbeitung der Requests lokal bleibt. Innerhalb der VM funktioniert das nur dann korrekt, wenn der Hypervisor die NUMA-Topo sauber "präsentiert", was wiederum beim 6.14er genau das Gegenteil ist. Dann "denkt" der IIS: "Ich habe 2 NUMA-Nodes!", aber die Zugriffe sind nicht lokal.

Ob NUMA wirklich sauber präsentiert wird, kannst Du mit

Code:
Get-WmiObject Win32_NumaNode

abfragen. Der korrekte Output müsste so aussehen:

Code:
NodeID  MemoryBlockSize  AvailableMemory
------  ----------------  ---------------
0       0                XXXXXXXX
1       0                XXXXXXXX

Bei Dir aber wahrscheinlich so:

Code:
NodeID  MemoryBlockSize  AvailableMemory
------  ----------------  ---------------
0       0                XXXXXXXX
1       0                0

Oder aber auch mehr Nodes, als die VM eigentlich haben dürfte.

Wenn bspw. dieser Befel

Code:
wmic cpu get NumberOfCores, NumberOfLogicalProcessors, DeviceID, NodeNumber

sowas ausgibt:

Code:
DeviceID  NodeNumber  NumberOfCores  NumberOfLogicalProcessors
--------  ----------  -------------  --------------------------
CPU0      0           12             12
CPU1      0           12             12
CPU2      1           0              0
CPU3      1           0              0

ist es offensichtlich. Dann hat NODE1 gar keine CPUs, aber Windows "denkt", sie seien vorhanden.

Ohne WMIC kannst Du das auch mit PS prüfen:

Code:
Write-Host "=== NUMA Topology Diagnosis ===" -ForegroundColor Cyan

# CPU-Infos abrufen
$cpus = Get-WmiObject Win32_Processor | Select-Object DeviceID, NumberOfCores, NumberOfLogicalProcessors, NodeNumber
$numaNodes = Get-WmiObject Win32_NumaNode | Select-Object NodeID, AvailableMemory

Write-Host "`nDetected NUMA Nodes:`n"
$numaNodes | Format-Table

Write-Host "`nDetected CPUs:`n"
$cpus | Format-Table

$errors = @()

# 1. Prüfen: Gibt es mehr als 2 NUMA Nodes?
if ($numaNodes.Count -gt 2) {
    $errors += "Mehr als 2 NUMA-Nodes gefunden – VM-Topologie inkonsistent."
}

# 2. Prüfen: Haben alle Nodes Speicher?
foreach ($node in $numaNodes) {
    if ($node.AvailableMemory -eq 0) {
        $errors += "NUMA Node $($node.NodeID) hat 0 Bytes RAM – fehlerhafte Topologie."
    }
}

# 3. Prüfen: Haben alle Nodes CPUs zugeordnet?
$nodesWithCpus = $cpus | Group-Object NodeNumber | ForEach-Object { $_.Name }
foreach ($node in $numaNodes) {
    if (-not ($nodesWithCpus -contains $node.NodeID)) {
        $errors += "NUMA Node $($node.NodeID) hat keine CPUs – inkonsistent."
    }
}

# 4. Prüfen: Gibt es CPUs, die keinem NUMA-Node zugeordnet sind?
foreach ($cpu in $cpus) {
    if ($cpu.NodeNumber -lt 0 -or $cpu.NodeNumber -ge $numaNodes.Count) {
        $errors += "CPU $($cpu.DeviceID) hat ungültigen NodeNumber-Wert: $($cpu.NodeNumber)."
    }
}

# Ergebnis ausgeben
Write-Host "`n=== Ergebnis ===" -ForegroundColor Cyan
if ($errors.Count -eq 0) {
    Write-Host "NUMA-Topologie ist sauber und konsistent." -ForegroundColor Green
} else {
    Write-Host "FEHLER GEFUNDEN:" -ForegroundColor Red
    $errors | ForEach-Object { Write-Host "- $_" -ForegroundColor Red }
}

Write-Host "`nAnalyse abgeschlossen."

Workarounds für den 6.14 er wären jetzt:

  1. VM auf EINEN Socket setzen (dafür mit allen gewünschten vCores)
  2. Numa: 0 - deaktiviert NUMA in der VM
  3. Die CPU Affinity exakt deklarieren:


  4. Code:
    numa: 1
    sockets: 2
    cores: X
    numa0: cpus=0-11,mem=0
    numa1: cpus=12-23,mem=1
 
Last edited:
Danke für die ausführliche Antwort.
Leider funktionieren die Kommandos nicht/nicht mehr/noch nicht unter Windows Server 2022.

Die Konfiguration der VM sieht jetzt wie folgt aus.
qm config 100 | egrep 'cpu:|sockets:|cores:|numa:|affinity|numa0'
Code:
affinity: 0-11,24-35
cores: 24
cpu: host
numa: 1
numa0: hostnodes=0,cpus=0-23,memory=64512,policy=bind
sockets: 1

wmic path Win32_PerfFormattedData_PerfOS_NUMANodeMemory get Name,AvailableMBytes
zeigt mir folgendes:

Code:
AvailableMBytes  Name
61417            0
61417            _Total

Update:
Nach einigem Testen kann ich bereits sagen, dass es sehr viel besser aussieht als alles was ich bisher in der Konstellation mit dem Kernel 6.14 gesehen habe. Über die nächsten Tage folgt jetzt eine Menge Traffic, sodass ich gut testen kann. Ausdrückliches Dankeschön @cwt !
 
Last edited:
  • Like
Reactions: Falk R. and cwt
Danke für die ausführliche Antwort.
Leider funktionieren die Kommandos nicht/nicht mehr/noch nicht unter Windows Server 2022.

Die Konfiguration der VM sieht jetzt wie folgt aus.
qm config 100 | egrep 'cpu:|sockets:|cores:|numa:|affinity|numa0'
Code:
affinity: 0-11,24-35
cores: 24
cpu: host
numa: 1
numa0: hostnodes=0,cpus=0-23,memory=64512,policy=bind
sockets: 1

wmic path Win32_PerfFormattedData_PerfOS_NUMANodeMemory get Name,AvailableMBytes
zeigt mir folgendes:

Code:
AvailableMBytes  Name
61417            0
61417            _Total

Update:
Nach einigem Testen kann ich bereits sagen, dass es sehr viel besser aussieht als alles was ich bisher in der Konstellation mit dem Kernel 6.14 gesehen habe. Über die nächsten Tage folgt jetzt eine Menge Traffic, sodass ich gut testen kann. Ausdrückliches Dankeschön @cwt !
Ich würde die conf abändern, das ist etwas durcheinander.

Variante A (Hyperthreading, phys. 12 cores & 12 HTs):

sockets: 1
cores: 12
affinity: 0-11,24-35
numa: 1
numa0: hostnodes=0,cpus=0-11,24-35,memory=64512,policy=bind
cpu: host

Variante B (ohne SMT, niedrigere Latenz):

sockets: 1
cores: 12
affinity: 0-11
numa: 1
numa0: hostnodes=0,cpus=0-11,memory=64512,policy=bind

Variante C (für mehr als 12 Kerne):

sockets: 2
cores: 12
numa: 1
affinity: 0-11,24-35,12-23,36-47
numa0: hostnodes=0,cpus=0-11,24-35,memory=X
numa1: hostnodes=1,cpus=12-23,36-47,memory=Y

Bei Variante C gibt es den Nachteil, dass IIS/ASP pro CPU group arbeitet und bei nur einem Socket schneller arbeitet.
 
Hallo, ich habe jetzt ein Ticket eröffnet, weil die Thematik etwas drängt.
Vielen Dank an die Beteiligten, ich halte euch gerne auf dem Laufenden.
 
Ich würde die conf abändern, das ist etwas durcheinander.

Variante A (Hyperthreading, phys. 12 cores & 12 HTs):

sockets: 1
cores: 12
affinity: 0-11,24-35
numa: 1
numa0: hostnodes=0,cpus=0-11,24-35,memory=64512,policy=bind
cpu: host

Variante B (ohne SMT, niedrigere Latenz):

sockets: 1
cores: 12
affinity: 0-11
numa: 1
numa0: hostnodes=0,cpus=0-11,memory=64512,policy=bind

Variante C (für mehr als 12 Kerne):

sockets: 2
cores: 12
numa: 1
affinity: 0-11,24-35,12-23,36-47
numa0: hostnodes=0,cpus=0-11,24-35,memory=X
numa1: hostnodes=1,cpus=12-23,36-47,memory=Y

Bei Variante C gibt es den Nachteil, dass IIS/ASP pro CPU group arbeitet und bei nur einem Socket schneller arbeitet.
Ich bin auch ganz bei deiner Empfehlung - das scheint mir plausibel.

Man könnte vorher noch die HIT/MISS Ratio ausgeben lassen: Wie auf Seite 1 von mir schon aufgelistet:

Bash:
sudo cat /sys/devices/system/node/node*/numastat

#Rückgabe ca.:
numa_hit      78.241.641.635
numa_miss      1.890.589.744
local_node    78.222.007.305
other_node     1.907.224.552
numa_hit     112.555.745.569
numa_miss      1.528.138.604
local_node   112.543.588.851
other_node    1.536.557.688

Ich hab ein Verhältnis von: > 40 zu 1
  • numa_hit / numa_miss
    = 78.241.641.635 / 1.890.589.744 ≈ 41,4
  • local_node / other_node
    = 78.222.007.305 / 1.907.224.552 ≈ 41,0
  • numa_hit / numa_miss
    = 112.555.745.569 / 1.528.138.604 ≈ 73,7
  • local_node / other_node
    = 112.543.588.851 / 1.536.557.688 ≈ 73,2
Sprich auf jeden Miss hab ich >40 Hits

Je näher sich die Werte von local_node zu den other_node nähern - um so schlechter.

Ganz wichtig ist auch: Wenn man HT hat 12 Cores physisch + 12 Cores HT, sollte man NICHT 24 Cores belegen, da einige Komponenten ( z.B. FPU etc.) nur einmalig vorhanden sind und hier ein Rückstau entsteht.
 
Hat sich da bei Dir noch was ergeben?
Stellt sich heraus, dass die Thematik etwas komplexer war und ist.
Vollständig behoben ist das Thema noch nicht.

Durch ein BIOS Upgrade des Servers konnte ein Microcode-Update des Prozessors durchgeführt werden, es stellte sich heraus, dass der Prozessor auf einem alten Stand war.
Außerdem gab es physische Probleme bei der NIC, die vor Allem dann zu tragen kamen wenn es viel Traffic gab. Das ist inzwischen behoben.
Dazu haben wir den Virtio Treiber auf Version 271 gesetzt und die Maschine einmal neu installiert.

Trotzdem ist die Performance noch nicht auf dem zufriedenstellenden Niveau und sorgt für Abbrüche/Fehler beim Loadbalancer der das Monitoring betreibt.