Yüksek trafikli bir web sitesini yönetirken en sık karşılaştığın sorunlardan biri aniden artan ziyaretçi sayısıyla sunucunun dizlerinin bükülmesidir. İşte tam bu noktada micro caching devreye girer. Nginx’in sunduğu bu strateji, dinamik içerikleri bile birkaç saniyeliğine önbelleğe alarak sunucu yükünü dramatik biçimde düşürür. Bugün bu konuyu hem teorik hem de pratik açıdan ele alacağız.
Micro Caching Nedir ve Neden İhtiyaç Duyarsın?
Geleneksel önbellekleme mantığında statik dosyalar saatlerce, bazen günlerce önbellekte tutulur. Peki ya her saniye değişebilecek dinamik sayfalar? WordPress blogun, haber siteniz ya da e-ticaret platformunuzun ana sayfası bunların başında gelir.
Micro caching, içerikleri yalnızca 1-10 saniye gibi kısa sürelerle önbelleğe alma stratejisidir. İlk bakışta “bu ne işe yarar ki?” diye düşünebilirsin. Ama şöyle hesapla: Saniyede 500 istek alan bir sayfada 1 saniyelik önbellek, 499 isteğin PHP veya uygulamana hiç ulaşmadan karşılanması anlamına gelir. Bu, backend yükünü neredeyse sıfıra indirger.
Micro caching’in öne çıktığı durumlar şunlardır:
- WordPress siteleri: Her sayfa görüntülenmesinde veritabanı sorgusu çalışır, micro caching bunu engeller
- Haber portalları: Anlık trafik artışlarında (breaking news) sunucu çökmesini önler
- API gateway’ler: Aynı parametreli istekler için tekrar tekrar işlem yapılmasının önüne geçer
- Flash sale senaryoları: E-ticarette kampanya başlangıcında oluşan trafik patlamalarını absorbe eder
Temel Nginx Yapılandırması
Nginx’te micro caching için fastcgi_cache veya proxy_cache direktiflerini kullanırsın. Önce temel yapıyı kuralım.
FastCGI Cache Kurulumu
PHP-FPM kullanan uygulamalar için FastCGI cache en yaygın tercih edilendir. Ana Nginx yapılandırma dosyasında önce cache zone tanımlaman gerekir:
# /etc/nginx/nginx.conf içindeki http bloğuna ekle
http {
# Cache zone tanımı
fastcgi_cache_path /var/cache/nginx/fastcgi
levels=1:2
keys_zone=MICROCACHE:100m
inactive=10m
max_size=1g;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
fastcgi_cache_use_stale error timeout invalid_header updating
http_500 http_503;
fastcgi_ignore_headers Cache-Control Expires Set-Cookie;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Buradaki parametreleri açıklayayım:
- levels=1:2: Dosya sistemi hiyerarşisini tanımlar, flat dizin yerine alt klasörler kullanır, büyük önbelleklerde performansı artırır
- keys_zone=MICROCACHE:100m: Zone adı ve metadata için ayrılan RAM miktarı (100MB yaklaşık 800.000 key tutar)
- inactive=10m: Bu süre boyunca erişilmeyen cache dosyaları silinir
- max_size=1g: Disk üzerinde maksimum cache boyutu
- fastcgi_cache_use_stale: Backend hata verdiğinde bile eski cache’i sunmaya devam et
Cache Dizinini Oluştur
# Cache dizinini oluştur ve izinleri ayarla
sudo mkdir -p /var/cache/nginx/fastcgi
sudo chown -R www-data:www-data /var/cache/nginx/
sudo chmod 700 /var/cache/nginx/fastcgi
# Nginx servisini yeniden başlat
sudo systemctl reload nginx
Virtual Host Yapılandırması
Şimdi asıl siteye ait yapılandırmaya micro caching direktiflerini ekleyelim:
# /etc/nginx/sites-available/orneksite.com
server {
listen 80;
server_name orneksite.com www.orneksite.com;
root /var/www/orneksite;
index index.php;
# Cache bypass değişkeni
set $skip_cache 0;
# POST isteklerini asla cache'leme
if ($request_method = POST) {
set $skip_cache 1;
}
# Query string içeren URL'leri bypass et
if ($query_string != "") {
set $skip_cache 1;
}
# Admin paneli ve oturum sayfalarını cache'leme
if ($request_uri ~* "(/wp-admin/|/xmlrpc.php|wp-.*.php|/feed/|index.php|sitemap(_index)?.xml)") {
set $skip_cache 1;
}
# Giriş yapmış kullanıcıları cache'leme (WordPress cookie kontrolü)
if ($http_cookie ~* "comment_author|wordpress_[a-f0-9]+|wp-postpass|wordpress_no_cache|wordpress_logged_in") {
set $skip_cache 1;
}
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ .php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Micro cache direktifleri
fastcgi_cache MICROCACHE;
fastcgi_cache_valid 200 301 302 1s;
fastcgi_cache_min_uses 1;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
# Cache durum header'ı ekle (debug için çok kullanışlı)
add_header X-Cache-Status $upstream_cache_status;
}
# Statik dosyalar için uzun cache süresi
location ~* .(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
}
Dikkat etmeni istediğim satır fastcgi_cache_valid 200 301 302 1s; kısmıdır. Burada 1s yani 1 saniye cache süresi kullandım. Bunu ihtiyacına göre 2s, 5s veya 10s yapabilirsin. Başlangıç için 1 saniye oldukça güvenli bir değerdir.
Proxy Cache ile Reverse Proxy Senaryosu
Eğer Nginx’i Node.js, Python veya başka bir uygulama sunucusunun önünde reverse proxy olarak kullanıyorsan, proxy_cache direktifini tercih edersin:
# /etc/nginx/nginx.conf - http bloğu içine
http {
proxy_cache_path /var/cache/nginx/proxy
levels=1:2
keys_zone=PROXYCACHE:50m
inactive=5m
max_size=512m;
proxy_cache_key "$scheme$request_method$host$request_uri";
proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
proxy_cache_background_update on;
proxy_cache_lock on;
include /etc/nginx/conf.d/*.conf;
}
proxy_cache_background_update on direktifi oldukça önemlidir. Cache süresi dolduğunda, eski içeriği sunmaya devam ederken arka planda yeni içeriği günceller. Kullanıcı hiç gecikme yaşamaz.
proxy_cache_lock on ise cache stampede problemini çözer. Aynı anda gelen 100 istek için yalnızca bir tanesi backend’e gider, diğerleri cache dolana kadar bekler.
# /etc/nginx/sites-available/nodejs-app.conf
server {
listen 80;
server_name api.orneksite.com;
set $skip_cache 0;
if ($request_method != GET) {
set $skip_cache 1;
}
if ($http_authorization != "") {
set $skip_cache 1;
}
location / {
proxy_pass http://127.0.0.1:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_cache_bypass $http_upgrade;
# Micro proxy cache
proxy_cache PROXYCACHE;
proxy_cache_valid 200 2s;
proxy_cache_bypass $skip_cache;
proxy_no_cache $skip_cache;
add_header X-Cache-Status $upstream_cache_status;
add_header X-Cache-Time $upstream_response_time;
}
}
Cache Durumunu İzlemek ve Debug Etmek
X-Cache-Status header’ını eklediğin için artık cache durumunu gerçek zamanlı olarak görebilirsin. Olası değerler şunlardır:
- HIT: İstek önbellekten karşılandı, mükemmel
- MISS: Cache’te yoktu, backend’e gitti
- BYPASS:
$skip_cachedeğişkeni devreye girdi, kasıtlı olarak atlandı - EXPIRED: Cache süresi dolmuş, backend’e gidiliyor
- STALE: Cache süresi dolmuş ama backend hata verdi, eski içerik sunuldu
- UPDATING: Background update devam ediyor, eski içerik sunuluyor
- REVALIDATED: Conditional request ile doğrulandı
Cache durumunu terminalden test etmek için:
# Cache durumunu kontrol et
curl -I http://orneksite.com/
# Belirli bir sayfayı test et ve header'ları gör
curl -sv http://orneksite.com/blog/makale/ 2>&1 | grep -E "X-Cache|HTTP/"
# Birkaç kez istek atarak HIT oluşmasını gözlemle
for i in {1..5}; do
curl -s -o /dev/null -w "Status: %{http_code} | Cache: " http://orneksite.com/
curl -sI http://orneksite.com/ | grep X-Cache-Status
sleep 0.5
done
Cache Temizleme (Purge) Stratejisi
Micro caching’in güzel yanı 1-5 saniyelik sürelerde içeriğin zaten çok hızlı yenilenmesi. Ancak bazı durumlarda anında temizlik gerekebilir. Nginx’in açık kaynak sürümünde purge modülü yoktur, ama şu yöntemle elle temizleyebilirsin:
# Tüm cache'i temizle
sudo find /var/cache/nginx/fastcgi -type f -delete
# Belirli bir URL pattern'ine ait cache'i temizle
sudo find /var/cache/nginx/fastcgi -type f |
xargs grep -rl "orneksite.com/blog/" |
xargs rm -f
# Cache boyutunu kontrol et
du -sh /var/cache/nginx/fastcgi/
du -sh /var/cache/nginx/proxy/
# Cache dosya sayısını öğren
find /var/cache/nginx/fastcgi -type f | wc -l
Nginx Plus kullanıyorsan veya ngx_cache_purge modülünü derlediysen şu endpoint’i ekleyebilirsin:
# ngx_cache_purge modülü ile (Nginx Plus veya özel derleme gerektirir)
location ~ /purge(/.*) {
allow 127.0.0.1;
allow 10.0.0.0/8;
deny all;
fastcgi_cache_purge MICROCACHE "$scheme$request_method$host$1";
}
Gerçek Dünya Senaryosu: WordPress Flash Sale
Bir müşterimin e-ticaret sitesinde yaşadığım durumu anlatayım. Sitede büyük bir indirim kampanyası duyurusu geldiğinde ana sayfa saniyede 800-1000 istek almaya başladı. PHP-FPM worker’lar doldu, veritabanı bağlantıları tükendi ve site yanıt vermez hale geldi.
Micro caching yapılandırması şöyleydi:
# WordPress için özelleştirilmiş micro cache yapılandırması
# /etc/nginx/sites-available/eticaret.com
fastcgi_cache_path /var/cache/nginx/wpcache
levels=1:2
keys_zone=WPCACHE:200m
inactive=30s
max_size=2g;
server {
listen 443 ssl http2;
server_name eticaret.com www.eticaret.com;
root /var/www/eticaret;
set $skip_cache 0;
# POST, admin ve oturum kontrolü
if ($request_method = POST) { set $skip_cache 1; }
if ($request_uri ~* "wp-admin|wp-login|cart|checkout|my-account|addons") {
set $skip_cache 1;
}
if ($http_cookie ~* "woocommerce_items_in_cart|woocommerce_cart_hash|wordpress_logged_in") {
set $skip_cache 1;
}
location ~ .php$ {
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_cache WPCACHE;
fastcgi_cache_valid 200 3s;
fastcgi_cache_bypass $skip_cache;
fastcgi_no_cache $skip_cache;
fastcgi_cache_use_stale error timeout updating http_500 http_503;
fastcgi_cache_background_update on;
fastcgi_cache_lock on;
fastcgi_cache_lock_timeout 5s;
add_header X-Cache-Status $upstream_cache_status always;
}
}
Bu yapılandırmayla PHP-FPM’e ulaşan istek sayısı 800’den yaklaşık 15-20’ye düştü. Saniyede sadece bir ya da iki istek backend’e gidiyordu, geri kalanı önbellekten karşılanıyordu. Kampanya süresince site hiç tökezlemedi.
Cache Performansını İzleme
Üretim ortamında cache etkinliğini sürekli izlemen önemlidir. Bunun için şu araçları kullanabilirsin:
# Nginx log formatını cache bilgisiyle zenginleştir
# /etc/nginx/nginx.conf - http bloğuna ekle
log_format cache_log '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'cache=$upstream_cache_status '
'rt=$request_time uct=$upstream_connect_time '
'urt=$upstream_response_time';
access_log /var/log/nginx/cache_access.log cache_log;
# Cache hit oranını hesapla
# Son 1000 istek içinde HIT yüzdesi
tail -1000 /var/log/nginx/cache_access.log |
awk '{for(i=1;i<=NF;i++) if($i~/^cache=/) print $i}' |
sort | uniq -c | sort -rn
# Gerçek zamanlı cache durumunu izle
tail -f /var/log/nginx/cache_access.log |
grep --line-buffered "cache=" |
awk '{for(i=1;i<=NF;i++) if($i~/^cache=/) printf $i" "; print ""}'
Cache hit oranın yüzde 90’ın altındaysa yapılandırmanda bir sorun var demektir. Hangi URL’lerin MISS veya BYPASS aldığını incelemelisin.
Sık Yapılan Hatalar ve Çözümleri
Micro caching uygularken en çok karşılaştığım hatalar şunlardır:
- Set-Cookie header’larını görmezden gelmemek:
fastcgi_ignore_headers Set-Cookie;eklemezsen oturum içeren response’lar cache’lenmez. Ancak dikkatli ol, oturum açık kullanıcılara yanlış içerik gösterilmemesi için$skip_cachemantığın sağlam olmalı.
- Cache key’i yanlış tanımlamak:
$request_uriyerine$urikullanmak query string’lerin görmezden gelinmesine yol açar.?page=2ile?page=3aynı içeriği gösterir.
- HTTP cache header’larını karıştırmak:
Cache-Control: no-cachegönderen uygulamaların Nginx tarafından önbelleğe alınabilmesi içinfastcgi_ignore_headers Cache-Control;direktifi şarttır. Aksi halde uygulama her şeyi bypass eder.
- Cache zone RAM’ini küçük tutmak:
keys_zone=MICROCACHE:10mgibi küçük değerler binlerce URL’li sitelerde metadata overflow’a yol açar. 100m ile başla.
- HTTPS ve HTTP için ayrı cache key kullanmamak: Cache key’ine
$schemeeklemezsen HTTP üzerinden önbelleğe alınan içerik HTTPS isteklerine de sunulabilir.
Sonuç
Micro caching, web sunucusu yönetimindeki en güçlü ama aynı zamanda en az takdir edilen tekniklerden biridir. Implementasyonu 30 dakikayı geçmez, ancak sunucunuzun kaldırabileceği trafik miktarını kolayca 10-50 kat artırabilir.
Başlangıç için şu adımları takip et:
- Önce geliştirme ortamında test et,
X-Cache-Statusheader’ını ekleyerek her şeyin doğru çalıştığını doğrula - Cache süresini 1 saniye ile başlat, ardından uygulamana özel ideal değeri bul
$skip_cachemantığını dikkatlice kur, yönetici paneli ve oturum sayfaları asla önbelleğe alınmamalı- Log formatına cache bilgisi ekle ve hit oranını düzenli takip et
- Cache dizini disk kullanımını izlemeye al,
max_sizeparametresini gerçekçi tut
Micro caching sihirli bir çözüm değildir ama doğru uygulandığında trafik patlamaları karşısında sitenin ayakta kalmasını sağlayan en pratik araçlardan biridir. Özellikle yüksek trafik öngörülen etkinlikler, kampanyalar veya viral içerik yayınlarından önce bu yapılandırmayı mutlaka devreye almalısın.