...

NUMA Balancing in Linux: deaktivieren oder aktiv lassen?

NUMA Balancing in Linux entscheidet, ob der Kernel Speicherzugriffe automatisch lokalisiert oder ob ich die Platzierung gezielt selbst steuere. In diesem Leitfaden zeige ich, wann ich numa balancing aktiv lasse und wann ich es für Latenz-Sicherheit abschalte.

Zentrale Punkte

  • Automatik hilft bei gemischten Workloads ohne NUMA-Tuning.
  • Deaktivieren bei Pinning, statischen Policies oder harter Latenz.
  • Overhead entsteht durch Scans, Faults und Migrationen.
  • Konfiguration per Sysctl oder Boot-Parameter steuern.
  • Testen und messen statt raten, dann entscheiden.

NUMA kurz erklärt: Latenzen und Lokalität

In NUMA-Systemen ordnet die Hardware Speicher in mehrere Nodes, die einzelnen CPUs räumlich nahe stehen. Lokale Zugriffe kosten weniger Zeit als entfernte, was ich sofort an Latenz und Bandbreite spüre. Läuft ein Prozess auf einem Node, doch die Daten liegen auf einem anderen, verliere ich wertvolle Mikrosekunden pro Zugriff. Genau an dieser Stelle wirkt der Kernel und optimiert die Lokalität von Seiten. Wer die Grundidee versteht, erkennt schnell: Nähe zwischen Rechenkernen und Daten ist der direkte Weg zu konstanter Performance.

Wie automatisches NUMA Balancing arbeitet

Der Kernel beobachtet, von welchen Kernen ein Prozess Seiten berührt, und löst gezielt Hint-Faults aus. So erkennt er, welcher Node dominante Zugriffe sieht, und verschiebt anschließend passende Seiten dorthin. Diese Migrationen reduzieren entfernte Zugriffe und erhöhen die lokale Trefferquote. Ich sehe die Wirkung besonders bei dynamischen Workloads, bei denen Threads wandern und Speicher sich bewegt. Wer tiefer einsteigen will, kann die Zusammenhänge zwischen CPU- und Speicher-Nähe über CPU-/Memory-Affinity praktisch nachvollziehen.

Wann aktiv lassen: typische Workloads

Ich lasse die Funktion aktiv, wenn Anwendungen keine eigene NUMA-Logik besitzen und Prozesse häufig wechseln. Klassische Kandidaten sind Application-Server, Datenbanken mit variabler Last und Hosts mit vielen Containern. In solchen Setups bringt die Automatik Seiten und Threads näher zusammen, ohne dass ich manuell pinnen muss. Besonders auf Multi-Socket-Hosts steigt der Anteil lokaler Zugriffe spürbar. Für Administrierende mit heterogenen Diensten liefert das einen guten Kompromiss aus Tempo und Aufwand.

Wann deaktivieren: klare Kriterien

Ich schalte die Automatik ab, sobald ich bewusst pinne oder klare Policies setze. Nutze ich numactl, cgroups oder MPOL_BIND/MPOL_PREFERRED, existiert bereits eine feste Entscheidung über Speicherpfade. Dann erzeugen Hint-Faults und Migrationen unnötigen Overhead. Dasselbe gilt für Echtzeit- oder HFT-Szenarien, in denen jede Mikrosekunde zählt und Vorhersagbarkeit Priorität hat. Wer tiefer in die Wahl der Platzierungsregeln einsteigt, profitiert von einem Blick auf passende Memory-Policies.

Overhead verstehen und messen

Automatisches Balancing verursacht Arbeit: Scans, Faults und Seitenmigrationen binden CPU-Zeit. Das fällt kaum auf, wenn entfernte Zugriffe stark sinken, lohnt sich aber kaum bei bereits lokalem Layout. Ich prüfe daher immer die tatsächliche Wirkung mit numastat, perf und aussagekräftigen Benchmarks. Interessant ist der Verlauf über Minuten, nicht nur ein kurzer Peak. Erst wenn Messwerte konsistent zeigen, dass lokale Zugriffe steigen und Latenzen fallen, behalte ich den Modus bei.

Konfiguration: Sysctl und Boot-Parameter

Den Status prüfe ich über /proc oder Sysctl und stelle ihn bei Bedarf sofort um, ohne einen Neustart. Für Tests reichen einfache Befehle wie unten, die ich auf der Konsole ausführe. Dauerhaft setze ich den Wert in einer Sysctl-Datei, damit er nach einem Reboot erhalten bleibt. Wer schon beim Booten entscheidet, nutzt den Kernel-Parameter numa_balancing=enable oder disable. Ich dokumentiere jede Änderung und notiere, mit welcher Workload-Phase ich sie vorgenommen habe.

cat /proc/sys/kernel/numa_balancing
echo 0 > /proc/sys/kernel/numa_balancing
sysctl -w kernel.numa_balancing=1
# /etc/sysctl.d/90-numa.conf
# kernel.numa_balancing = 0

Container- und Virtualisierungsszenarien

Auf Hosts mit vielen VMs und Containern spielt die automatische Lokalisierung oft ihre Stärken aus. Prozesse starten und enden, Cgroups verschieben Last, und der Kernel hält Speicher näher an den aktiven Kernen. Ich beobachte das vor allem auf großen Multi-Socket-Servern mit mehreren Nodes. Spezialfälle mit striktem Pinning einzelner Instanzen trenne ich klar ab und deaktiviere dort gezielt die Automatik. Für eine weitergehende Einordnung hilft ein Blick auf praktische NUMA-Optimierung im Host-Betrieb.

Entscheidungstabelle für die Praxis

Die folgende Übersicht verdichtet typische Szenarien, die erwartete Wirkung und meine klare Empfehlung. Ich nutze sie als Startpunkt, ersetze sie aber nie durch Messwerte auf dem echten System. Jede Umgebung zeigt Eigenheiten, und ich lege Entscheidungen erst nach reproduzierbaren Ergebnissen fest. Wer systematisch vorgeht, spart später Zeit bei Fehlersuche und Tuning. Kleine Testläufe vor einem Rollout zahlen sich fast immer in Konstanz und Planbarkeit aus.

Szenario Typische Wirkung Meine Empfehlung
Standard-Workloads ohne NUMA-Tuning Mehr lokale Zugriffe, weniger entfernte Reads Aktiv lassen
Datenbanken mit wechselnder Last Dynamische Seitenlokalisierung, moderate Scans Aktiv lassen, testen
Harte Echtzeit oder HFT Hint-Fault-Latenz stört Jitter-Ziele Deaktivieren, manuell pinnen
Manuelles Pinning via numactl/cgroups Automatik kollidiert mit festen Policies Deaktivieren
Statische Memory-Policies (MPOL_BIND, etc.) Migrationen bringen keinen echten Vorteil Deaktivieren
Test-/Analyse-Umgebung Gute Sicht auf Lokalität und Effekte Aktiv lassen, Varianten prüfen

Leitfaden für Tests und Validierung

Ich starte mit aktiviertem Balancer und protokolliere lokale versus entfernte Zugriffe über numastat. Danach deaktiviere ich die Funktion und wiederhole die Messungen identisch. Unterschiede bewerte ich nicht nur in Durchschnittswerten, sondern auch in Perzentilen. Regressions-Checks mit Lastprofilen aus der Produktion liefern die verlässlichsten Aussagen. Erst dann treffe ich die dauerhafte Entscheidung für Host, VM oder bestimmten Service.

Häufige Stolpersteine und Mythen

Ein verbreiteter Irrtum lautet, die Automatik ersetze jedes Pinning. Das stimmt nicht, denn starre Latenzbudgets vertragen kaum zusätzliche Faults. Ebenso falsch ist die Annahme, dass Migrationen immer kostenlos passieren. Gerade bei ohnehin lokalen Layouts wirkt der Overhead häufiger negativ als positiv. Wer Mythen vermeidet und sauber misst, trifft Entscheidungen mit deutlich höherer Treffsicherheit.

Grenzen der Automatik und Interaktionen

AutoNUMA wirkt stark auf anonyme Seiten, die ein Prozess selbst allokiert. Nicht alles lässt sich aber sinnvoll migrieren. Pinned Pages (mlock), DMA-/Gerätespeicher, DAX oder RDMA-registrierte Bereiche bleiben, wo sie sind. Auch gemeinsam genutzte Seiten (z. B. stark geteilte Bibliotheken oder Page Cache) liefern nur begrenzten Nutzen durch Migration, weil mehrere Prozesse konkurrierende Zugriffsmuster erzeugen. Ich berücksichtige außerdem die Kosten von Transparent Huge Pages (THP): deren Migration ist teurer als bei 4-KiB-Seiten und kann Lastspitzen verursachen. Wer harte Latenzziele verfolgt, kombiniert häufig THP=never oder madvise mit deaktiviertem Balancing und sauberem Pinning, um Überraschungen auszuschließen.

Ein weiterer Aspekt ist die Interaktion mit dem CPU-Scheduler. Der Scheduler versucht, Threads dort zu platzieren, wo ihre Daten liegen – und der Balancer verschiebt Daten dorthin, wo Threads laufen. Beides ergänzt sich, kann aber bei unsteter Last kurzzeitig zu Oszillationen führen. In der Praxis dämpfen die Scan-Intervalle diese Effekte; wer extrem unruhige Lastprofile sieht, entspannt die Lage über längere Scan-Perioden oder durch stabileres Thread-Pinning.

Feintuning der Scan-Parameter

Neben dem globalen Schalter existieren Kernel-Parameter, mit denen ich die Aggressivität der Automatik fein justiere. Die genauen Namen können je nach Kernelstand leicht variieren, der Zweck bleibt gleich:

  • kernel.numa_balancing_scan_delay_ms: Wartezeit nach Start, fork oder exec, bis der erste Scan beginnt.
  • kernel.numa_balancing_scan_period_min_ms / _max_ms: Unter- und Obergrenze der Scan-Kadenz pro Prozessadressebereich.
  • kernel.numa_balancing_rate_limit_mb: Obergrenze pro Zeitfenster für Seitenmigrationen, um Speicherbandbreite zu schonen.
  • kernel.numa_balancing_scan_size_mb: Menge an Speicher, die pro Scan-Pass markiert wird (wenn verfügbar).

Konservativ erhöhe ich in latenzkritischen Setups die Minimal- und Maximalperioden und senke die Rate-Limits, statt die Automatik sofort auszuschalten. Das liefert oft einen guten Mittelweg: weniger Hint-Faults, weniger Migrationen, aber noch genug Reaktion auf echte Fehlplatzierungen.

# Beispiele (temporär, bis zum Reboot)
sysctl -w kernel.numa_balancing_scan_period_min_ms=60000
sysctl -w kernel.numa_balancing_scan_period_max_ms=240000
sysctl -w kernel.numa_balancing_rate_limit_mb=64

Metriken und Diagnose in der Tiefe

Für belastbare Entscheidungen lese ich Metriken, die direkt den Mechanismus sichtbar machen. Drei Quellen nutze ich regelmäßig:

  • numastat: Verhältnis lokaler/entfernter Zugriffe systemweit und pro Prozess.
  • /proc/<pid>/numa_maps: Verteilung der Speicherseiten eines Prozesses über Nodes, inklusive Flags wie active, file, anon.
  • /proc/vmstat: Zähler wie numa_hint_faults, numa_hint_faults_local und numa_pages_migrated zeigen, ob der Balancer arbeitet und ob er Erfolg hat.
# Überblick pro Prozess
numastat -p <PID>

# Detailansicht: welche Bereiche liegen wo?
grep -E 'anon|file' /proc/<PID>/numa_maps | head

# Kernelweite Sicht auf AutoNUMA-Aktivität
grep -E 'numa_(hint_faults|pages_migrated)' /proc/vmstat

In den Ergebnissen suche ich nach Trends: Steigt der Anteil lokaler Zugriffe stabil an? Gehen gleichzeitig die Hint-Faults zurück? Dann setzt sich ein gutes Layout durch. Bleibt der lokale Anteil trotz vieler Migrationen flach, verbrenne ich eher Zyklen. Für Latenzziele prüfe ich zusätzlich die 95./99.-Perzentile der Antwortzeiten; kleine Mittelwertgewinne können durch Jitter überdeckt werden.

Workload-Profile: was typischerweise funktioniert

Aus der Praxis haben sich Muster ergeben, wann AutoNUMA meist hilft und wann nicht:

  • JVM-Services und Application-Server: Häufig profitieren sie, solange keine harte Thread-Pinning-Strategie und keine aggressiv eigene NUMA-Logik aktiv ist. Einige Laufzeiten bieten NUMA-Optionen; wenn ich diese streng nutze, reduziere ich die Automatik oder schalte sie ab.
  • Relationale Datenbanken: Bei variabler Last mit gemischten Caches funktioniert die Automatik oft gut. Setze ich jedoch dediziertes Pinning (Worker-to-Node, Shared Buffers strikt verteilt), deaktiviere ich das Balancing für saubere Reproduzierbarkeit.
  • In-Memory-Stores und Caches: Ein großer, heißer Arbeitssatz profitiert von lokaler Platzierung. Arbeitet die Instanz single-threaded oder streng gepinnt, verhindere ich unnötige Migrationen durch Abschalten.
  • HPC/MPI und wissenschaftliche Codes: Meist existieren klare Platzierungs- und Bindungsregeln (OpenMP/numactl). Hier ist Vorhersagbarkeit wichtiger als Automatik – ich lasse NUMA Balancing aus.

Virtualisierung: vNUMA, Pinning und Live-Migration

Im Zusammenspiel von Host und Gast berücksichtige ich beide Ebenen:

  • Stimmt die vNUMA-Topologie im Gast mit der physischen NUMA-Topologie des Hosts überein, kann der Gastbalancer sinnvolle Entscheidungen treffen. Weiche ich davon ab, entstehen „falsche Nachbarschaften“, die AutoNUMA nur begrenzt kompensiert.
  • Pinne ich vCPUs fest auf Host-CPUs und binde den Gastspeicher an bestimmte Nodes, ist das eine explizite Policy – ich reduziere oder deaktiviere auf dieser VM-Ebene AutoNUMA, um doppelte Migrationen zu vermeiden.
  • Nach Live-Migrationen beobachte ich eine Aufwärmphase: Hint-Faults steigen an, bis sich ein neues Gleichgewicht eingestellt hat. In dieser Zeit plane ich Puffer für Latenz-Spitzen ein.

Auf dichten Virtualisierungshosts, wo Instanzen starten/stoppen und Cgroups die Last verschieben, bleibt die Automatik am Host häufig ein Nettovorteil. Für dedizierte „Noisy-Neighbor“-sensitive VMs kapsle ich Ressourcen sauber und setze die Regeln statisch.

Pragmatische Zielwerte und Akzeptanzkriterien

Ich definiere vorab, was „gut“ bedeutet, damit ich nicht endlos feintune:

  • Allgemeine Services: 70–85% lokale Zugriffe sind oft ausreichend, wenn die Varianz gering bleibt.
  • Latenz-SLAs: Ziel >90% lokal, klare Obergrenzen für Hint-Fault-Rate und stabile 99.-Perzentile.
  • Bandbreitenlastig: Migrationen dürfen die Speicherkanäle nicht sättigen – Rate-Limits und Perioden entsprechend anpassen.

Ich dokumentiere diese Schwellen und werte A/B-Läufe über mehrere Lastphasen aus. Eine Entscheidung treffe ich erst, wenn die Ergebnisse wiederholbar sind.

Troubleshooting-Checkliste

  • Plötzliche Latenzspitzen: Prüfen, ob THP-Migrationen oder Peaks in numa_hint_faults korrelieren. Gegenmaßnahme: Scan-Perioden erhöhen, THP auf madvise/never stellen, notfalls Balance aus.
  • Kaum Effekt trotz Aktivierung: Sind die Threads stark gepinnt oder existieren feste Memory-Policies? Dann kollidiert die Automatik mit den Vorgaben.
  • Hohes Migrationstempo, trotzdem viele Remote-Zugriffe: Rate-Limit prüfen und erhöhen; alternativ den Arbeitssatz stabilisieren (Thread-Pinning, Caches wärmestabil halten).
  • Unklare Messwerte: Per-Prozess-Sicht mit numastat -p und /proc/<pid>/numa_maps nutzen, nicht nur Systemgesamtwerte.

Häufig übersehene Details

  • Page-Cache-lastige Workloads: AutoNUMA wirkt vor allem auf anonyme Seiten. Wer primär I/O-gebunden arbeitet, sollte keine Wunder durch Balancing erwarten.
  • Cgroups und cpusets: cpuset.mems begrenzt, auf welche Nodes eine Gruppe zugreifen darf. Das ist ein harter Rahmen, innerhalb dessen die Automatik agiert.
  • Memory-Hotplug/Node-Offlining: Dynamische Topologien verändern Distanzen; nach Änderungen lohnt ein erneuter Testlauf und ggf. eine Anpassung der Scan-Parameter.

Kurz zusammengefasst

Für allgemeine Server-Workloads lasse ich die Automatik an, weil sie ohne Handarbeit nahe Daten zu aktiven Kernen bringt. Bei Echtzeit, HFT, manuellem Pinning oder festen Policies schalte ich sie ab, um Overhead und Jitter zu vermeiden. In Testphasen arbeite ich iterativ: messen, entscheiden, erneut validieren. Konfiguration halte ich einfach, dokumentiere jede Änderung und kontrolliere die Wirkung mit verlässlichen Kennzahlen. So nutze ich die Stärken von NUMA-Hardware aus, ohne unnötige Risiken einzugehen.

Aktuelle Artikel

NUMA Balancing auf moderner Linux Server Hardware im Rechenzentrum
Server und virtuelle Maschinen

NUMA Balancing in Linux: deaktivieren oder aktiv lassen?

Erfahre, wie NUMA Balancing die Linux Performance auf moderner Server Hardware beeinflusst und wann du das Feature deaktivieren oder aktiv lassen solltest. Fokus: numa balancing.

Serverrack mit hervorgehobenen RAM-Modulen zur Darstellung des ZFS ARC Cache in einem Rechenzentrum
Server und virtuelle Maschinen

ZFS ARC Cache: Speicherverbrauch richtig verstehen

Lerne, wie der ZFS ARC Cache funktioniert, warum hoher RAM-Verbrauch normal ist und wie du den Speicherverbrauch richtig einstellst, um die zfs performance zu verbessern.