| Metrik | Önce | Sonra |
|---|---|---|
| İlk bayt süresi (TTFB) | ~1.8s | ~180ms |
| Sayfa yükleme (giriş yapmış) | ~16s | ~3.2s |
| Cache hit oranı | ~%40 | ~%94 |
1. Neden Redis ve BigPipe birlikte?
Drupal'ın varsayılan cache sistemi disk tabanlı çalışır. Yüksek trafikli sitelerde bu yaklaşım ölçeklenmez: her istek için dosya kilitleme, seri/deserializasyon yükü ve yavaş I/O darboğaz yaratır. Redis, bu sorunu bellek üzerinde çalışarak çözer; ancak Redis tek başına yetmez.
BigPipe ise tamamen farklı bir problemi çözer: giriş yapmış kullanıcılar için sayfa render süresini. Kimlik doğrulama, sepet, bildirim gibi kişiselleştirilmiş bloklar sayfayı "cache'lenemez" hale getirir. BigPipe bu blokları placeholder ile erteler; statik içeriği anında gönderir, kişisel içeriği paralel akışla doldurur.
Temel ilke: Redis önbelleği hızlandırır; BigPipe kişiselleştirilmiş içeriği cache sınırlamalarının dışına taşır. İkisi farklı katmanlarda çalışır ve birbirini tamamlar — çakışmaz.
Redis'in katkısı: Cache okuma/yazma işlemlerini bellekte yapar. Disk I/O ortadan kalkar. Cache tag invalidation mikrosaniyeler içinde gerçekleşir.
BigPipe'ın katkısı: Sayfa render'ını bölümlere ayırır. Cache'lenemez parçalar asenkron akışla gelir, kullanıcı boş sayfa görmez.
2. Kurulum
Redis modülü ve bağlantı kurulumu
Drupal 11 ile Redis entegrasyonu için drupal/redis modülü ve PHP Redis extension'ı gerekir. PhpRedis extension'ı Predis PHP kütüphanesine göre yaklaşık 3-4× daha hızlıdır; üretim ortamında her zaman PhpRedis tercih edilmeli.
# Composer ile Redis modülünü yükle
composer require drupal/redis
# PhpRedis extension (Debian/Ubuntu)
apt install php8.3-redis
# Modülü aktifleştir (BigPipe zaten core'da)
drush en redis bigpipe -y
drush cr
settings.php yapılandırması
Redis bağlantısı ve chainedfast backend'i settings.php içinde tanımlanır. chainedfast, statik PHP önbelleğini Redis ile birleştirir; aynı istek içinde tekrar erişilen veriler Redis'e bile gitmez.
// Redis bağlantı bilgileri
$settings['redis.connection']['interface'] = 'PhpRedis';
$settings['redis.connection']['host'] = '127.0.0.1';
$settings['redis.connection']['port'] = 6379;
$settings['redis.connection']['password'] = 'gizli_sifre';
$settings['redis.connection']['database'] = 0;
// chainedfast: statik PHP cache + Redis
$settings['cache']['default'] = 'cache.backend.chainedfast';
// Render cache Redis'te, bootstrap hızlı PHP'de
$settings['cache']['bins']['render'] = 'cache.backend.redis';
$settings['cache']['bins']['bootstrap'] = 'cache.backend.chainedfast';
$settings['cache']['bins']['config'] = 'cache.backend.chainedfast';
$settings['cache']['bins']['discovery'] = 'cache.backend.chainedfast';
// Prefix: birden fazla Drupal sitesi aynı Redis'i kullanıyorsa
$settings['cache_prefix'] = 'novebo_';
Dikkat:cache.backend.chainedfastbackend'i PHP'nin statik önbelleğini kullandığından, CLI (drush) isteklerinde bu önbellek çalışmaz.drush crsonrası web isteği atarak cache'in doğru dolduğunu kontrol edin.
3. BigPipe nasıl çalışır?
Geleneksel Drupal render akışında, sayfadaki en yavaş "cache'lenemez" blok tüm sayfanın TTFB'sini belirler. BigPipe bu engeli ortadan kaldırır: sunucu önce cacheable içeriği gönderir, tarayıcı bunu render ederken kişiselleştirilmiş bloklar için placeholder'lar doldurulur.
- İstek gelir
- Statik HTML anında gönderilir
- Placeholder'lar akışla doldurulur
- Sayfa tamam, bağlantı kapanır
Modül aktivasyonu yeterli mi?
BigPipe modülünü etkinleştirmek genellikle yeterlidir; ancak maksimum fayda için blokların render cache ve lazy_builder ayarları doğru kurulmalıdır. Cache'lenemez blokların #lazy_builder kullandığından emin olun.
// Yanlış: tüm sayfa cache'lenemez hale gelir
function my_block_build() {
return [
'#markup' => t('Merhaba @user', ['@user' => \Drupal::currentUser()->getDisplayName()]),
'#cache' => ['max-age' => 0],
];
}
// Doğru: BigPipe placeholder olarak render edilir
function my_block_build() {
return [
'#lazy_builder' => ['my_module.lazy:buildUserGreeting', []],
'#create_placeholder' => TRUE,
];
}
| BigPipe olmadan | BigPipe ile | |
|---|---|---|
| Yavaş blok | Tüm sayfayı bloklar | Yalnızca kendini etkiler |
| TTFB | En yavaş bileşen kadar | Cacheable render süresi |
| Kullanıcı deneyimi | Boş beyaz ekran | Sayfa kademeli dolar |
| Giriş yapmış kullanıcı | Cache yok | Kişisel içerik paralel gelir |
4. Redis sunucu optimizasyonu
Redis performansı sadece PHP tarafındaki yapılandırmayla sınırlı değil; redis.conf ayarları ve bellek politikası da kritik rol oynar. Drupal cache için allkeys-lru politikası idealdir: bellek dolduğunda en az kullanılan anahtarlar otomatik silinir.
# /etc/redis/redis.conf
# Maksimum bellek (sunucu RAM'ine göre ayarla)
maxmemory 512mb
maxmemory-policy allkeys-lru
# Kalıcılık gerekmez, performans için kapat
save ""
appendonly no
# TCP bağlantı kuyruğu (yüksek eşzamanlılık için)
tcp-backlog 511
tcp-keepalive 300
# Lazy freeing: büyük anahtarları arka planda sil
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
# Unix socket (aynı sunucuda Nginx+PHP varsa daha hızlı)
unixsocket /var/run/redis/redis.sock
unixsocketperm 770
Unix socket ile bağlantı
PHP ve Redis aynı sunucudaysa TCP yerine Unix socket kullanmak küçük ama ölçülebilir bir iyileşme sağlar. Gecikmeler mikrosaniye seviyesine iner.
// settings.php — Unix socket bağlantısı
$settings['redis.connection']['interface'] = 'PhpRedis';
$settings['redis.connection']['host'] = '/var/run/redis/redis.sock';
$settings['redis.connection']['port'] = 0; // socket için 0
Hetzner VPS notu: CX22/CX32'de Redis için 256–512 MB bellek yeterlidir. Orta ölçekli sitelerde toplam cache boyutu genellikle 50–150 MB arasında kalır. redis-cli info memory ile gerçek kullanımı kontrol edin.
5. Akıllı cache invalidation
Redis hızı sağlar; ancak cache'in ne zaman geçersiz kılınacağını belirleyen mekanizma cache tag'larıdır. Drupal 11'de cache tag invalidation varsayılan olarak veritabanı üzerinden çalışır. Redis modülü bunu Redis'e taşır ve tag invalidation dramatik biçimde hızlanır.
// node:42 güncellenince bu blok otomatik geçersiz olur
function mymodule_build_node_block($nid) {
$node = Node::load($nid);
return [
'#theme' => 'my_node_card',
'#node' => $node,
'#cache' => [
'keys' => ['my_node_card', $nid],
'tags' => $node->getCacheTags(), // ['node:42']
'contexts' => ['languages'],
'max-age' => Cache::PERMANENT,
],
];
}
// Node kaydedilince tüm ilgili cache'leri temizle
function mymodule_node_update(NodeInterface $node) {
Cache::invalidateTags($node->getCacheTags());
}
Cache context seçimi
Cache context ne kadar geniş tutulursa, aynı içerik için o kadar çok varyant oluşur ve cache verimliliği düşer. user context yerine user.roles tercih edin; bu, her kullanıcı için ayrı cache yerine rol bazlı ortak cache sağlar.
// Kötü: her kullanıcı için ayrı cache — Redis şişer
'contexts' => ['user']
// İyi: rol bazlı — 4-5 varyant yeterli
'contexts' => ['user.roles']
// Çok iyi: sadece anonim/giriş yapmış ayrımı
'contexts' => ['user.roles:authenticated']
// Dil + rol kombinasyonu (çok dilli siteler)
'contexts' => ['languages:language_interface', 'user.roles']
6. Performansı izlemek ve debug etmek
# Genel istatistikler (hit/miss oranı kritik)
redis-cli info stats | grep -E "hits|misses|ops_per_sec"
# Anlık komut akışı (geliştirme ortamında)
redis-cli monitor | grep -v PING
# Anahtar sayısı ve bellek kullanımı
redis-cli info keyspace
redis-cli info memory | grep -E "used_memory_human|maxmemory_human"
# En büyük anahtarlar (bellek sızıntısı tespiti)
redis-cli --bigkeys
# Site prefix'li anahtarları say
redis-cli keys "novebo_*" | wc -l
# Cache bin'lerinin hangi backend'i kullandığını kontrol et
drush php-eval "
\$bins = ['render','bootstrap','config','discovery','default'];
foreach (\$bins as \$bin) {
\$cache = \Drupal::cache(\$bin);
echo \$bin . ': ' . get_class(\$cache) . PHP_EOL;
}
"
# BigPipe çalışıyor mu?
drush pm:list --status=enabled | grep bigpipe
# Cache temizle ve ilk yanıt süresini ölç
drush cr && curl -s -o /dev/null -w "%{time_total}" https://novebo.com/
Hedef metrikler: Redis hit oranı %85'in altındaysa cache key tasarımını gözden geçirin. Anonim kullanıcılarda TTFB 200ms altında, giriş yapmış kullanıcılarda 800ms altında olmalıdır (BigPipe placeholder'lar hariç).
7. Canlıya almadan önce kontrol listesi
- PhpRedis extension yüklü ve etkin:
php -m | grep redis - Redis şifresi
settings.php'de tanımlı;requirepassredis.conf'ta da açık maxmemory-policyallkeys-lruolarak ayarlı (yoksa Redis bellek dolarsa hata verir)- BigPipe modülü aktif;
page_cachevedynamic_page_cachemodülleri de açık - Cache prefix tanımlı; birden fazla site aynı Redis instance'ı paylaşıyorsa zorunlu
- Render cache context'leri minimumda:
useryerineuser.roleskullanılıyor - Redis kalıcılığı (RDB/AOF) devre dışı; yalnızca cache için kullanılıyorsa disk yazımı gereksiz yük
- Nginx FastCGI cache ile Redis çakışmıyor: Nginx microcache anonim kullanıcı için Drupal'ı devreye sokmamalı
8. Mimari özet
Anonim kullanıcı akışı: Nginx FastCGI microcache → cache hit ise PHP'ye uğramaz. Miss ise Drupal + Redis render cache → yanıt + Nginx'e yazar.
Giriş yapmış kullanıcı akışı: Nginx microcache bypass → Drupal + Redis (cacheable bloklar) + BigPipe (kişisel bloklar) → kademeli sayfa render.
Cache invalidation: Node/config kaydedilir → Cache tag'lar Redis'te geçersiz olur → Sonraki istek yeni render üretir → Redis'e yazar.
Bellek hiyerarşisi: PHP statik cache (en hızlı, istek ömrü) → Redis chainedfast (hızlı, process ömrü) → MySQL (yavaş, son çare).
İlgili modüller: drupal/redis, bigpipe (core), dynamic_page_cache (core), page_cache (core)