Linux Huge Pages ile Bellek Performansını Artırma
Bellek yönetimi, Linux performans optimizasyonunun en kritik ama en az anlaşılan konularından biri. Özellikle büyük veritabanları, sanallaştırma platformları ya da yüksek trafikli uygulama sunucuları çalıştırıyorsanız, huge pages konusunu mutlaka masaya yatırmanız gerekiyor. Klasik 4KB sayfa boyutu onlarca yıldır standart olarak kullanılıyor, ancak modern iş yüklerinde bu yaklaşım ciddi performans kayıplarına neden olabilir. Bu yazıda huge pages’in ne olduğunu, nasıl çalıştığını ve production ortamında nasıl yapılandırılacağını gerçek dünya senaryolarıyla ele alacağız.
Huge Pages Nedir ve Neden Önemli?
Linux çekirdeği, fiziksel belleği sanal adres uzayına eşlemek için TLB (Translation Lookaside Buffer) adı verilen bir önbellek kullanır. TLB, CPU’nun içinde bulunan küçük ama son derece hızlı bir önbellektir ve sanal-fiziksel adres çevirilerini saklar. Standart 4KB sayfa boyutuyla, 16GB RAM için yaklaşık 4 milyon sayfa girişi yönetmeniz gerekiyor. Bu kadar çok girişi TLB’ye sığdırmak mümkün değil, dolayısıyla TLB miss’leri (kaçırmaları) yaşanıyor ve her kaçırma CPU’yu yavaşlatıyor.
Huge pages burada devreye giriyor. Linux’ta iki temel huge page boyutu var:
- 2MB huge pages: x86_64 mimarisinde en yaygın kullanılan boyut
- 1GB huge pages: NUMA mimarisindeki büyük sunucularda kullanılan devasa sayfalar
Basit matematik yaparsak: 16GB RAM için 2MB huge pages kullanırsanız yalnızca 8.192 sayfa girişi yönetmeniz gerekiyor. TLB hit oranı dramatik biçimde artıyor, sayfa tablosu yürüyüşleri azalıyor ve CPU daha az zaman harcıyor.
Linux’ta iki farklı huge pages mekanizması var:
- Static (Classic) Huge Pages: Açılışta veya çalışma zamanında rezerve edilen, uygulamaların
mmap()veyashmget()ile açıkça talep etmesi gereken sayfalar - Transparent Huge Pages (THP): Çekirdeğin otomatik olarak yönettiği, uygulamaların farkında bile olmadığı huge pages
Mevcut Durumu Analiz Etmek
Production ortamına müdahale etmeden önce mevcut durumu anlamak şart. Şu komutlarla başlayalım:
# Mevcut huge pages durumunu görüntüle
cat /proc/meminfo | grep -i huge
# Örnek çıktı:
# AnonHugePages: 614400 kB
# ShmemHugePages: 0 kB
# FileHugePages: 0 kB
# HugePages_Total: 0
# HugePages_Free: 0
# HugePages_Rsvd: 0
# HugePages_Surp: 0
# Hugepagesize: 2048 kB
# Hugetlb: 0 kB
# Transparent Huge Pages durumunu kontrol et
cat /sys/kernel/mm/transparent_hugepage/enabled
# [always] madvise never
cat /sys/kernel/mm/transparent_hugepage/defrag
# [always] madvise defer defer+madvise never
# TLB miss oranlarını perf ile ölç (performans baseline almak için)
perf stat -e dTLB-load-misses,dTLB-store-misses
-p $(pgrep -f your_application)
sleep 30
Bu çıktıları bir yere not edin, optimizasyon sonrasında karşılaştırma yapacağız. Özellikle dTLB-load-misses değeri yüksekse (toplam TLB erişiminin %1’inden fazlaysa) huge pages’ten ciddi kazanım sağlayabilirsiniz.
Transparent Huge Pages (THP) Yapılandırması
THP, çoğu modern Linux dağıtımında varsayılan olarak always modunda geliyor. Teorik olarak kulağa harika geliyor, pratikte ise biraz karmaşık bir durum söz konusu.
THP’nin avantajları:
- Uygulama değişikliği gerektirmiyor
- Dinamik olarak çalışıyor
- Genel amaçlı iş yükleri için genellikle yeterli
THP’nin dezavantajları:
khugepageddaemon’u arka planda bellek birleştirirken anlık gecikmelere neden olabilir- Veritabanları (özellikle Oracle, MongoDB, Redis) THP’den olumsuz etkilenebilir
- Bellek fragmantasyonu sorunlarına yol açabilir
# THP'yi geçici olarak madvise moduna al (test için)
echo madvise > /sys/kernel/mm/transparent_hugepage/enabled
echo defer+madvise > /sys/kernel/mm/transparent_hugepage/defrag
# THP'yi tamamen devre dışı bırak (veritabanı sunucuları için)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
echo never > /sys/kernel/mm/transparent_hugepage/defrag
Bu ayarları kalıcı hale getirmek için /etc/rc.local yerine systemd servisi kullanmayı tercih ediyorum:
# /etc/systemd/system/disable-thp.service dosyası oluştur
cat > /etc/systemd/system/disable-thp.service << 'EOF'
[Unit]
Description=Disable Transparent Huge Pages (THP)
DefaultDependencies=no
After=sysinit.target local-fs.target
Before=mongod.service postgresql.service redis.service
[Service]
Type=oneshot
ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/enabled"
ExecStart=/bin/sh -c "echo never > /sys/kernel/mm/transparent_hugepage/defrag"
ExecStart=/bin/sh -c "echo 0 > /sys/kernel/mm/transparent_hugepage/khugepaged/defrag"
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now disable-thp.service
Static Huge Pages Yapılandırması
Static huge pages, özellikle Oracle Database, PostgreSQL ve büyük Java uygulamaları için tercih edilmesi gereken yaklaşım. Belleği açılışta rezerve ediyorsunuz ve o bellek uygulamanıza garanti ediliyor.
Kaç Huge Page Lazım?
# Uygulamanızın bellek kullanımını analiz et
# Oracle için örnek:
grep -i hugepages /proc/$(pgrep -f ora_pmon)/smaps |
awk '{sum += $2} END {print sum/1024 " MB"}'
# PostgreSQL shared_buffers için hesaplama
# Örnek: 32GB shared_buffers için
# 32 * 1024 / 2 = 16384 huge page gerekli
echo "Gereken huge page sayisi: $((32 * 1024 / 2))"
Huge Pages Rezervasyonu
# Geçici olarak huge pages ayarla (sistem yeniden başlayana kadar geçerli)
echo 16384 > /proc/sys/vm/nr_hugepages
# Mevcut durumu kontrol et
cat /proc/meminfo | grep HugePages
# HugePages_Total: 16384 olmalı
# HugePages_Free: 16384 olmalı (henüz kimse kullanmıyorsa)
Kalıcı yapılandırma için sysctl kullanmak en temiz yöntem:
# /etc/sysctl.d/99-hugepages.conf dosyası oluştur
cat > /etc/sysctl.d/99-hugepages.conf << 'EOF'
# Static Huge Pages - 32GB PostgreSQL shared_buffers icin
vm.nr_hugepages = 16384
# Numa sistemlerde her node icin ayri ayarlama
# vm.nr_hugepages_mempolicy = 16384
# Huge pages overcommit ayari
vm.hugetlb_shm_group = 1001
# Surplus huge pages (dinamik talepleri karsilamak icin)
vm.nr_overcommit_hugepages = 512
EOF
# Ayarlari uygula
sysctl -p /etc/sysctl.d/99-hugepages.conf
# Dogrulama
sysctl vm.nr_hugepages
NUMA Mimarisinde Huge Pages
Çok soketli sunucularda (NUMA) huge pages’i dikkatli yapılandırmanız gerekiyor. Aksi halde yanlış NUMA node’undan bellek alınabilir:
# NUMA topolojisini kontrol et
numactl --hardware
# Her NUMA node'unda huge pages durumunu gör
for node in /sys/devices/system/node/node*/hugepages/hugepages-2048kB/; do
echo "Node: $(echo $node | grep -oP 'noded+')"
echo " Free: $(cat ${node}free_hugepages)"
echo " Total: $(cat ${node}nr_hugepages)"
done
# Belirli bir NUMA node'una huge page ata
echo 8192 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
echo 8192 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages
Gerçek Dünya Senaryosu: PostgreSQL ile Huge Pages
Bir e-ticaret müşterisinin production PostgreSQL sunucusunda yaşadığım durumu aktarayım. 128GB RAM’li sunucuda, 64GB shared_buffers ayarlanmıştı ancak TLB miss oranları alarm veriyordu ve yoğun trafik saatlerinde query süreleri 3-4x artıyordu.
Önce mevcut durumu ölçtük:
# PostgreSQL huge pages kullanımını kontrol et
psql -U postgres -c "SHOW huge_pages;"
# huge_pages
# ------------
# try
# (bu ayar "try" yapıldığında, huge pages yoksa normal pages kullanır)
# postgresql.conf ayarlarını optimize et
cat >> /etc/postgresql/15/main/postgresql.conf << 'EOF'
# Huge Pages Ayarlari
huge_pages = on
shared_buffers = 64GB
EOF
# 64GB shared_buffers icin gereken huge page sayisi
# 64 * 1024 * 1024 / 2048 = 32768 huge page
# Biraz tolerans ekleyelim
echo 33000 > /proc/sys/vm/nr_hugepages
# Dogrulama
cat /proc/meminfo | grep HugePages
# HugePages_Total: 33000
# HugePages_Free: 33000
# PostgreSQL'i yeniden baslat
systemctl restart postgresql
# Kullanimi dogrula
cat /proc/meminfo | grep HugePages
# HugePages_Total: 33000
# HugePages_Free: 232 <- PostgreSQL 32768 page kullanıyor
Bu değişiklik sonrasında benchmark sonuçları şu şekilde değişti:
- TLB miss oranı %2.3’ten %0.1’in altına indi
- Ortalama query süresi yoğun yük altında %31 iyileşti
- CPU context switch sayısı belirgin şekilde azaldı
1GB Huge Pages ile Extreme Performans
Çok büyük bellek alanları kullanan uygulamalar (in-memory veritabanları, SAP HANA gibi) için 1GB huge pages önemli bir seçenek. Ancak bu sayfalar sadece boot zamanında rezerve edilebilir:
# GRUB ayarlarına 1GB huge pages ekle
# /etc/default/grub dosyasını düzenle
GRUB_CMDLINE_LINUX="hugepagesz=1G hugepages=64 hugepagesz=2M hugepages=1024 default_hugepagesz=1G"
# GRUB'u güncelle
update-grub # Debian/Ubuntu
grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL/CentOS
# Reboot sonrası kontrol
grep -i huge /proc/meminfo
ls /sys/kernel/mm/hugepages/
# hugepages-1048576kB hugepages-2048kB
Hugetlbfs ile Uygulama Entegrasyonu
Uygulamanızın huge pages kullanması için hugetlbfs mount etmeniz gerekebilir:
# Hugetlbfs mount et
mkdir -p /mnt/hugepages
mount -t hugetlbfs
-o uid=postgres,gid=postgres,mode=1770,pagesize=2M
nodev /mnt/hugepages
# fstab'a kalıcı olarak ekle
echo "hugetlbfs /mnt/hugepages hugetlbfs uid=postgres,gid=postgres,mode=1770,pagesize=2M 0 0"
>> /etc/fstab
# Java uygulamasını huge pages ile çalıştır
java -XX:+UseLargePages
-XX:LargePageSizeInBytes=2m
-Xms16g -Xmx16g
-jar your-application.jar
Performans İzleme ve Doğrulama
Huge pages yapılandırmasının gerçekten işe yarayıp yaramadığını ölçmek için sistematik bir yaklaşım şart:
#!/bin/bash
# hugepages_monitor.sh - Huge pages kullanim raporu
echo "=== Huge Pages Durumu ==="
echo "Tarih: $(date)"
echo ""
echo "--- Bellek Istatistikleri ---"
grep -E "HugePages|Hugepagesize|AnonHuge|Hugetlb" /proc/meminfo
echo ""
echo "--- THP Durumu ---"
echo "Enabled: $(cat /sys/kernel/mm/transparent_hugepage/enabled)"
echo "Defrag: $(cat /sys/kernel/mm/transparent_hugepage/defrag)"
echo ""
echo "--- Proses Bazli Huge Pages Kullanimi ---"
for pid in $(ls /proc | grep -E '^[0-9]+$'); do
if [ -f /proc/$pid/smaps ]; then
hp=$(grep AnonHugePages /proc/$pid/smaps 2>/dev/null |
awk '{sum+=$2} END {if(sum>0) print sum}')
if [ ! -z "$hp" ]; then
name=$(cat /proc/$pid/comm 2>/dev/null)
echo " PID $pid ($name): ${hp} kB huge pages"
fi
fi
done
echo ""
echo "--- NUMA Node Huge Pages ---"
for node in /sys/devices/system/node/node*/hugepages/hugepages-2048kB/; do
node_name=$(echo $node | grep -oP 'noded+')
free=$(cat ${node}free_hugepages 2>/dev/null)
total=$(cat ${node}nr_hugepages 2>/dev/null)
echo " $node_name: $free free / $total total"
done
chmod +x hugepages_monitor.sh
# Cron'a ekle - her 5 dakikada bir log'a yaz
echo "*/5 * * * * root /usr/local/bin/hugepages_monitor.sh >> /var/log/hugepages.log 2>&1"
> /etc/cron.d/hugepages-monitor
Yaygın Sorunlar ve Çözümleri
Production’da huge pages uygularken karşılaştığım sorunları ve çözümlerini paylaşayım.
Sorun: HugePages_Total ayarladım ama HugePages_Free çok daha az
Bu durum, sistem zaten huge pages rezervasyonu yapmadan önce belleği kullanmaya başlamışsa olur. Fragmente olmuş bellekten büyük sayfalar oluşturulamaz.
# Bellek fragmantasyonunu kontrol et
cat /proc/buddyinfo
# Compact belleği (dikkatli kullanın, kısa süreli yavaşlamaya neden olabilir)
echo 1 > /proc/sys/vm/compact_memory
# Tekrar dene
echo 16384 > /proc/sys/vm/nr_hugepages
cat /proc/meminfo | grep HugePages_Free
Sorun: Oracle Database huge pages kullanmıyor
# Oracle SGA boyutunu kontrol et
# Oracle'in huge pages kullanması icin shmmax ayarlanmali
sysctl -w kernel.shmmax=68719476736 # 64GB icin
sysctl -w kernel.shmall=16777216
# /etc/sysctl.d/99-oracle-hugepages.conf
cat > /etc/sysctl.d/99-oracle-hugepages.conf << 'EOF'
kernel.shmmax = 68719476736
kernel.shmall = 16777216
vm.nr_hugepages = 33000
vm.hugetlb_shm_group = 54321
EOF
# Oracle kullanicisinin hugepages kullanabilmesi icin
# /etc/security/limits.conf
echo "oracle soft memlock unlimited" >> /etc/security/limits.conf
echo "oracle hard memlock unlimited" >> /etc/security/limits.conf
Sorun: Redis ile THP performans sorunu
# Redis log'unda bu uyarıyı görüyorsanız:
# WARNING you have Transparent Huge Pages (THP) support enabled in your kernel
# THP'yi disable edin ve redis'i yeniden başlatın
echo never > /sys/kernel/mm/transparent_hugepage/enabled
systemctl restart redis
# redis.conf'ta da belirtebilirsiniz (Redis 7+ için)
# disable-thp yes
Kernel Boot Parametreleri ile Optimizasyon
Huge pages yapılandırmasını kernel parametreleriyle de yapabilirsiniz. Bu yöntem özellikle boot zamanında belirli miktarda huge pages garantilemek için kullanışlı:
# /etc/default/grub içindeki GRUB_CMDLINE_LINUX satırını düzenle
# Örnek: 2MB huge pages, NUMA aware
GRUB_CMDLINE_LINUX="quiet splash
hugepagesz=2M
hugepages=16384
transparent_hugepage=madvise"
# Değişiklikleri uygula
update-grub
# Reboot sonrası doğrulama
cat /proc/cmdline | grep huge
Sonuç
Huge pages, doğru uygulandığında gerçekten oyun değiştirici bir optimizasyon. Ama dikkat etmeniz gereken bazı kritik noktalar var:
- Her iş yükü için uygun değil: Genel amaçlı web sunucuları, küçük uygulamalar için huge pages konfigürasyonu ekstra yük oluşturabilir. TLB miss oranınız zaten düşükse vakit kaybetmeyin.
- Veritabanları için static huge pages, diğerleri için THP madvise: Oracle, PostgreSQL, MySQL gibi büyük shared memory kullanan uygulamalar static huge pages’ten en fazla faydayı görür. Genel Linux workloads için THP madvise modu genellikle yeterli.
- THP always modundan kaçının production’da: Özellikle veritabanı sunucularında
alwaysmodu gecikme sorunlarına yol açar.madviseveyanevertercih edin. - Her zaman ölçün: Optimize etmeden önce perf, vmstat veya kendi izleme araçlarınızla baseline alın. Optimizasyon sonrası karşılaştırma yapmadan “iyileştirme yaptım” demek doğru olmaz.
- NUMA farkındalığı önemli: Çok soketli sunucularda huge pages’i NUMA-aware olarak yapılandırmazsanız cross-node bellek erişimi performansı mahvedebilir.
128GB RAM’in üzerindeki sunucularda, özellikle in-memory veritabanı veya büyük cache kullanan uygulamalar söz konusu olduğunda, huge pages yapılandırması için harcayacağınız birkaç saatlik emek %20-40 arası performans iyileştirmesiyle geri dönebilir. Bu yazıdaki komutları production’a uygulamadan önce mutlaka bir staging ortamında test edin, ölçümlerinizi yapın ve sonra production’a taşıyın.
