Huge Pages
Pe un sistem modern cu 16GB RAM și pagini de 4KB, kernelul gestionează peste 4 milioane de pagini. Fiecare pagină are o intrare în page table, iar procesorul menține un cache de traduceri recente în TLB. Când o aplicație accesează date răspândite pe mii de pagini - cum fac bazele de date mari - TLB-ul se umple rapid și procesorul pierde timp traducând adrese în loc să proceseze date. Huge Pages rezolvă această problemă oferind pagini de dimensiuni mult mai mari: 2MB sau chiar 1GB în loc de 4KB standard.
De ce contează dimensiunea paginii
TLB-ul (Translation Lookaside Buffer) este un cache hardware mic și extrem de rapid - de obicei între 64 și 1024 intrări pe arhitecturile moderne. Fiecare intrare acoperă o pagină de memorie. Cu pagini de 4KB, 1024 intrări în TLB acoperă doar 4MB de memorie. Cu pagini de 2MB, aceleași 1024 intrări acoperă 2GB.
Când un proces accesează o adresă care nu e în TLB, procesorul trebuie să parcurgă page table-ul în RAM - operație numită TLB miss sau page table walk - care costă zeci până la sute de cicluri de procesor. Pe o aplicație care face milioane de accese de memorie pe secundă, TLB miss-urile frecvente se adună și devin un bottleneck vizibil.
Bazele de date sunt cel mai bun exemplu: PostgreSQL, MariaDB, MySQL sau Oracle accesează constant zone mari de memorie pentru buffer pool, sort buffers și index scans. Trecerea la Huge Pages reduce dramatic numărul de TLB miss-uri și poate îmbunătăți performanța cu 10-30% în scenarii intensive.
Tipuri de Huge Pages pe Linux
Linux oferă două implementări distincte cu filozofii diferite.
Static Huge Pages
Huge Pages statice sunt rezervate la pornirea sistemului (sau manual) și rămân alocate permanent, indiferent dacă sunt folosite sau nu. Avantajul este performanța maximă - paginile sunt contigue în RAM și garantat disponibile. Dezavantajul este inflexibilitatea - memoria rezervată nu poate fi folosită pentru altceva, chiar dacă aplicația care le folosește nu rulează.
Dimensiunile disponibile depind de arhitectură: pe x86_64 sunt disponibile pagini de 2MB (cel mai comun) și 1GB (necesită suport explicit în kernel și CPU).
Transparent Huge Pages (THP)
Transparent Huge Pages este un mecanism automat prin care kernelul încearcă să folosească pagini mari fără intervenție manuală. Kernelul monitorizează alocările de memorie și, când detectează că un proces folosește zone contigue mari de memorie cu pagini de 4KB, le combină automat în pagini de 2MB.
Avantajul evident este că funcționează fără configurare și fără modificări în aplicații. Dezavantajul este că procesul de combinare (compaction) și desfacere (splitting) a paginilor provoacă uneori latențe imprevizibile - procesul se poate bloca câteva milisecunde în timp ce kernelul reorganizează memoria. Din acest motiv, unele aplicații (Redis, MongoDB, multe baze de date) recomandă explicit dezactivarea THP.
Verificarea stării Huge Pages
Verifici câte Huge Pages statice sunt configurate și câte sunt folosite:
cat /proc/meminfo | grep -i huge
Rezultatul arată ceva de genul:
AnonHugePages: 614400 kB ShmemHugePages: 0 kB HugePages_Total: 128 HugePages_Free: 96 HugePages_Rsvd: 32 HugePages_Surp: 0 Hugepagesize: 2048 kB Hugetlb: 262144 kB
HugePages_Total - numărul total de pagini de 2MB rezervate, HugePages_Free - câte sunt disponibile, HugePages_Rsvd - câte sunt rezervate dar nu încă folosite efectiv, AnonHugePages - memoria folosită de THP.
Verifici starea THP:
cat /sys/kernel/mm/transparent_hugepage/enabled
Valoarea între paranteze drepte este cea activă: always, madvise sau never.
Configurarea Huge Pages statice
Calculul necesarului
Înainte de a configura Huge Pages pentru o bază de date, trebuie să știi câtă memorie alocă aplicația pentru structurile care beneficiază de pe urma lor. Pentru PostgreSQL, valoarea relevantă este shared_buffers. Pentru MariaDB/MySQL este innodb_buffer_pool_size.
Formula pentru numărul de pagini necesare:
număr_pagini = (dimensiune_în_bytes / 2097152) + rezervă_10%
Exemplu pentru PostgreSQL cu shared_buffers = 4GB:
4GB = 4294967296 bytes 4294967296 / 2097152 = 2048 pagini + 10% rezervă = ~2250 pagini
Rezervarea paginilor
Rezervi Huge Pages temporar (se pierde la repornire):
sysctl vm.nr_hugepages=2250
Permanent, în /etc/sysctl.conf sau /etc/sysctl.d/99-hugepages.conf:
vm.nr_hugepages=2250
Aplici fără repornire:
sysctl -p
Verifici că au fost alocate:
grep HugePages /proc/meminfo
Dacă HugePages_Free e mai mic decât ai cerut, kernelul nu a putut găsi suficientă memorie contiguă. În acest caz, fie reduci numărul, fie repornești sistemul și configurezi Huge Pages devreme în procesul de boot, înainte ca memoria să fie fragmentată.
Rezervarea la boot
Pentru a garanta alocarea paginilor contigue înainte de fragmentarea memoriei, adaugi parametrul direct în linia de boot a kernelului. În /etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash hugepages=2250"
Actualizezi GRUB:
# Ubuntu/Debian update-grub # Fedora/RHEL grub2-mkconfig -o /boot/grub2/grub.cfg # Arch Linux grub-mkconfig -o /boot/grub/grub.cfg
Hugepages de 1GB
Paginile de 1GB sunt disponibile doar dacă CPU-ul suportă extensia pdpe1gb (verifici cu grep pdpe1gb /proc/cpuinfo) și trebuie configurate exclusiv la boot - nu pot fi alocate dinamic după pornirea sistemului:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash hugepages=4 default_hugepagesz=1G hugepagesz=1G"
Paginile de 1GB sunt utile doar pentru aplicații cu structuri de memorie foarte mari (zeci de GB) unde chiar și paginile de 2MB generează prea multe intrări în page table.
Configurarea THP
Modurile disponibile
THP are trei moduri de funcționare:
always - kernelul încearcă agresiv să folosească pagini mari pentru orice alocare anonimă. Poate provoca latențe din cauza compaction-ului.
madvise - THP este folosit doar pentru zonele de memorie unde aplicația a cerut explicit prin apelul madvise(MADV_HUGEPAGE). Oferă control fin fără latențele din modul always.
never - THP dezactivat complet.
Schimbi modul temporar:
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
Permanent, prin parametru de kernel în /etc/default/grub:
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash transparent_hugepage=madvise"
Dezactivarea THP pentru aplicații specifice
Unele aplicații - Redis, MongoDB, Cassandra - recomandă dezactivarea THP pentru că latențele de compaction interferează cu timpii de răspuns. Dacă nu vrei să dezactivezi THP global, poți dezactiva pentru un singur proces după pornire:
# Dezactivezi THP pentru un proces cu PID cunoscut echo madvise > /proc/PID/numa_maps # nu funcționează direct astfel
O abordare mai practică este să folosești systemd pentru a seta mediul procesului. Adaugi în fișierul de serviciu:
[Service] ExecStartPost=/bin/sh -c 'echo madvise > /sys/kernel/mm/transparent_hugepage/enabled'
Sau mai elegant, prin numactl sau wrapper scripts specifice aplicației - Redis de exemplu are în documentație o secțiune dedicată acestui subiect.
Configurarea PostgreSQL pentru Huge Pages
PostgreSQL suportă Huge Pages nativ din versiunea 9.4. Configurezi în postgresql.conf:
huge_pages = on # on, off, sau try shared_buffers = 4GB
Cu huge_pages = try, PostgreSQL încearcă să folosească Huge Pages și continuă cu pagini normale dacă nu sunt disponibile - util în medii unde Huge Pages pot lipsi. Cu on, serverul refuză să pornească dacă nu găsește Huge Pages suficiente.
PostgreSQL are nevoie și de permisiuni pentru a accesa Huge Pages. Verifici și setezi limita pentru utilizatorul postgres:
# Verifici limita curentă grep -i hugepages /etc/security/limits.conf # Adaugi dacă lipsește echo "postgres soft memlock unlimited" >> /etc/security/limits.conf echo "postgres hard memlock unlimited" >> /etc/security/limits.conf
Configurarea MariaDB/MySQL pentru Huge Pages
MariaDB și MySQL suportă Huge Pages prin parametrul large-pages în fișierul de configurare:
[mysqld] large-pages innodb_buffer_pool_size = 4G
La fel ca PostgreSQL, procesul mysqld trebuie să aibă permisiuni memlock. Pe sisteme cu systemd, adaugi în fișierul de serviciu:
[Service] LimitMEMLOCK=infinity
Monitorizarea utilizării Huge Pages
Urmărești utilizarea în timp real:
watch -n 2 'grep -E "HugePages|AnonHuge" /proc/meminfo'
Pentru a vedea care procese folosesc Huge Pages:
grep -l "AnonHugePages" /proc/[0-9]*/smaps | while read f; do pid=$(echo $f | cut -d/ -f3) size=$(grep AnonHugePages $f | awk '{sum+=$2} END {print sum}') name=$(cat /proc/$pid/comm 2>/dev/null) [ "$size" -gt "0" ] 2>/dev/null && echo "$size kB - $pid ($name)" done | sort -rn
Statisticile THP sunt disponibile în:
cat /sys/kernel/mm/transparent_hugepage/khugepaged/pages_collapsed cat /sys/kernel/mm/transparent_hugepage/khugepaged/full_scans
pages_collapsed arată câte pagini de 4KB au fost combinate în pagini mari - o valoare mare indică THP activ. full_scans arată de câte ori khugepaged (daemonul kernel care face compaction) a scanat memoria.
Când să folosești Huge Pages
Huge Pages aduc beneficii clare în scenarii specifice și pot fi contraproductive în altele.
Beneficii clare:
- Baze de date cu buffer pool mare (PostgreSQL, MariaDB, Oracle)
- Aplicații de calcul intensiv cu structuri de date mari (simulări, machine learning)
- Servere cu mulți GB de RAM și câteva procese mari
Fără beneficii sau contraproductive:
- Sisteme desktop cu multe aplicații mici
- Servere cu zeci de procese mici
- Aplicații cu acces aleatoriu la zone mici de memorie
- Sisteme cu RAM limitat - Huge Pages rezervă memorie permanent
Pe un VPS mic cu 4GB RAM care rulează multe servicii, Huge Pages pot face mai mult rău decât bine prin blocarea memoriei. Pe un server dedicat cu 64GB RAM și PostgreSQL ca serviciu principal, pot aduce îmbunătățiri semnificative de performanță.
Resurse suplimentare
- Cum funcționează memoria virtuală pe Linux - conceptele de bază despre pagini și page tables
- Swap pe Linux - gestionarea memoriei virtuale pe disc
- Monitorizarea memoriei pe Linux - unelte de diagnosticare și analiză