Begriff
NUMA (Non-Uniform Memory Access)
Warum wichtig?
Dieser Begriff ist ein Knoten im SengakujiWorks-Wissensnetz. Nutze Level 0 für die erste Einordnung, Level 1 für Praxis, Level 2 für technische Struktur und Level 3 für Grenzen, Fallstricke und Expertenkontext.
Früher (UMP): Alle CPUs griffen auf den gleichen RAM-Riegel zu. Mit 64 Cores wird der Bus zum Stau. Lösung: NUMA. Man teilt den RAM auf. Prozessor 1 bekommt seinen eigenen RAM ("Local Memory"). Prozessor 2 bekommt seinen eigenen RAM. Wenn Prozessor 1 auf seinen RAM zugreift -> Superschnell. Wenn Prozessor 1 auf RAM von Prozessor 2 zugreift ("Remote Memory") -> Langsam (muss über den Interconnect, z. B. QPI/UPI). "Non-Uniform" heißt: Zugriffsdauer ist ungleichmäßig. Als Admin/Entwickler musst du aufpassen: Dein Prozess sollte immer auf dem Core laufen, wo auch seine Daten liegen (CPU Pinning).
Merksatz: Eine Speicherarchitektur für Multiprozessorsysteme, bei der die Zugriffszeit auf den Arbeitsspeicher davon abhängt, wo sich der Speicher relativ zum zugreifenden Prozessor befindet (lokal vs. remote).
- Datenbanken (SQL Server, Oracle): Sind "NUMA-aware". Sie wissen, welche Tabelle in welchem RAM-Stick liegt und nutzen den passenden Core.
- Virtualisierung (VMware): Eine vCPU und ihr RAM sollten immer im gleichen NUMA-Node bleiben. Sonst Performance-Einbruch ("NUMA Trashing").
- Linux:
numactl --show. Zeigt dir die Topologie.numactl --cpunodebind=0 --membind=0 myapp. Zwingt die App auf Node 0.
1. Interconnect (QPI / Infinity Fabric)
Die Verbindung zwischen den Sockets. Wenn alle Cores wild auf fremden Speicher zugreifen, ist dieser Link gesättigt. Das System wird extrem langsam, obwohl CPU-Last niedrig scheint ("Memory Bound").
2. First-Touch Policy
Linux-Standard: Speicher wird dort alloziiert, wo der Thread läuft, der ihn zuerst anfasst (nicht alloziert!).
Problem: Wenn der Initialisierungs-Thread auf Core 0 läuft, landet alles in NUMA 0.
Danach greifen Core 1-63 darauf zu -> Remote Access Hölle.
Lösung: numactl --interleave=all (verteilt Speicher gleichmäßig, Durchschnitts-Performance).
1. NUMA Miss Penalty & Cache Coherence (MESI)
Warum ist ein "Remote Access" so unfassbar langsam? Ein CPU Socket hat seinen integrierten Memory Controller (IMC) für seinen lokalen RAM Bus. Greift Socket0 auf RAM von Socket1 zu, muss das Load-Register-Signal in das QPI/UPI (Intel) oder Infinity Fabric (AMD) Protokoll konvertiert werden. Diese Hop-Penalty addiert leicht 40–80 Nanosekunden Latenz (~100 CPU Zyklen in Warteposition)! Viel schwerwiegender ist der Snoop Traffic auf dem Interconnect. Wegen der Hardware Cache-Coherence (z.B. im MESI-Protokoll) muss Socket0 vor dem Modifizieren der Remote-Speicherstelle (State: Modified) den Socket1 anbrüllen: "Invalidiere diese Cacheline sofort in all deinen eigenen L1/L2 Caches!". Bei False Sharing oder intensiven Mutex-Sperren explodiert dieser "Directory/Snoop Traffic" über den UPI-Link massiv. Der Interconnect-Bus satuiert, bevor die reale Speicherdurchsatzgrenze überhaupt erreicht ist, was hunderte von CPU-Kernen hilflos verhungern lässt.
2. Transparent Huge Pages (THP) vs NUMA Fragmentation
Betriebssysteme allozieren RAM in der Regel in $4\text{ KB}$ Pages. Ein 32 GB Heap im Memory produziert Millionen von Paging Logs (TLB Misses). Die Lösung: Linux pusht "Transparent Huge Pages" (THP) mit $2\text{ MB}$ Brocken in den Page Table Eintrag. Der tödliche Konflikt: THPs erzwingen gigantische fortlaufende physische Speicherblöcke. Wenn der lokale NUMA Node durch Fragmentierung zersplittert ist (viele $4\text{ KB}$ Lücken), findet der Kernel dort keine kontinuierlichen $2\text{ MB}$ Wiesen mehr. Also weicht Linux bei NUMA Systemen panisch auf den Remote Node aus, der zufällig noch $2\text{ MB}$ frei hat ("THP Fallback"). Resultat: Dein Thread bleibt auf Core 0, aber massive Teile deines Java-Rams driften still und heimlich rüber auf Socket 1. Da THPs für Datenbanken oft fatal ins swappen abrutschen, deaktiveren Profis (z.B. bei Redis/Oracle) Transparent Huge Pages vollständig in NUMA-Topologien.
3. SRAT, SLIT und ACPI Bindings im BIOS
Woher weiß das Linux OS auf Kernel-Level ($Ring \ 0$), welche RAM-Riegel zu welchem Core gehören? Es fragt das Motherboard BIOS (bzw UEFI) über die winzigen ACPI (Advanced Configuration and Power Interface) Tabellen.
- SRAT (System Resource Affinity Table): Eine Matrix, die stumpf auflistet "APIC ID 4 (Core) gehört zu NUMA-Domain 0, Memory Area 0x00A gehört zu NUMA-Domain 0".
- SLIT (System Locality Information Table): Definiert die exakte "Distanz" (Latenz-Strafe).
Node 0 zu 0 = 10, Node 0 zu 1 = 21. Ist das BIOS Outdated oder schlecht geflasht (HPC Clustering/Virtualisierung), sendet es kaputte SRAT/SLITs an den Bootloader. Das NUMA Balancing (sched_domainim Kernel) glaubt fatalerweise alles sei UMA (Uniform Memory Access) und wirft Random Scheduler-Threads quer durch den Cluster. Es existieren Server-Crashs in Prod, nur weil die ACPI Tables Memory Hot-Add Zonen fälschlicherweise distant-weighted referenziert haben!
Quick-Check
UMA?
Uniform Memory Access. Der Gegensatz. Alle Speicherzugriffe sind gleich schnell. (Mein Laptop ist UMA. Mein Dual-Socket-Server ist NUMA).vNUMA?
Virtual NUMA. Man spiegelt die physische NUMA-Topologie in die virtuelle Maschine, damit das Gast-OS optimieren kann. Wichtig für riesige VMs (SAP HANA).Threadripper?
Sogar moderne Desktop-CPUs (AMD Threadripper) haben intern NUMA-Strukturen, weil sie aus mehreren Chiplets bestehen.