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.
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.
Linux oferă două implementări distincte cu filozofii diferite.
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 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.
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.
Î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
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ă.
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
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.
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"
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.
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
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
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.
Huge Pages aduc beneficii clare în scenarii specifice și pot fi contraproductive în altele.
Beneficii clare:
Fără beneficii sau contraproductive:
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ță.