Daha akıllı bir önbellek katmanı nasıl inşa edilir: yalnızca ihtiyaç duyduğu verileri ve bunu ne zaman alacağını öğrenin.
Veritabanının sürekli olarak aynı verilere yönelik okuma talepleri karşısında zayıf düşmesini izlediyseniz, Cache-Aside pattern (Lazy Loading olarak da bilinir) ile ilgili sorunları zaten deneyimlemişsinizdir. Şimdi bunu inceleyelim.
Temel Fikir
Temel Fikir
Cache-Aside ile uygulamanız önbelleği doğrudan yönetir. Veritabanınızı Redis ile otomatik olarak senkronize eden büyülü bir middleware yoktur. Yapmanız gerekenler basit bir sözleşmeyi takip etmektir:
- Okuma → Önce önbelleği kontrol et. Cache hit? Veriyi döndür. Cache miss? DB’den al, önbelleğe kaydet, ardından veriyi döndür.
- Yazma → Veritabanını güncelle, ardından önbellek girişini geçersiz kıl (veya güncelle).
Hepsi bu. Basit, güçlü ve üretim sistemlerinde yaygın olarak kullanılıyor.
Okuma Akışı
Okuma Akışı
Client → Check Cache
├── HIT → Return cached data ✅
└── MISS → Fetch from DB
→ Write to cache
→ Return data
Kodu Göster
Kodu Göster
Laravel’de, yerleşik Cache facade’ını ve Eloquent ORM’i kullanarak pratik bir örnek:
namespace App\Services;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
class UserService
{
private const CACHE_TTL = 300; // 5 dakika
public function getUserById(int $userId): ?User
{
$cacheKey = "user:{$userId}";
// 1. Cache kontrolü - miss durumunda DB'den al ve otomatik olarak kaydet
return Cache::remember($cacheKey, self::CACHE_TTL, function () use ($userId) {
logger('Cache MISS — DB sorgulaması');
return User::find($userId);
});
}
public function updateUser(int $userId, array $updates): void
{
// 1. Gerçek veriyi güncelle
User::whereId($userId)->update($updates);
// 2. Eski önbellek girişini geçersiz kıl
Cache::forget("user:{$userId}");
}
}
Laravel’ın Cache::remember() yöntemi, kontrol-et-al ve sakla döngüsünü tek bir temiz çağrıda gerçekleştirir. Cache sürücünüzü config/cache.php‘de Redis olarak yapılandırın:
'default' => env('CACHE_STORE', 'redis'),
Ve .env dosyanızda:
CACHE_STORE=redis
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
Temiz, tahmin edilebilir ve tamamen sizin kontrolünüz altında.
Neden Her Şeyi Başlangıçta Önbelleğe Almıyoruz?
Neden Her Şeyi Başlangıçta Önbelleğe Almıyoruz?
Bu yaklaşım Cache-Through veya Write-Through olarak bilinir ve bir yeri vardır — ancak kullanıcı onun için istenip istenmediğine bakmaksızın tüm verileri önbelleğe alır.
Cache-Aside tembel: yalnızca gerçekten istenen verileri önbelleğe alır. Büyük veri setlerine sahip sistemlerde, yalnızca bir kısmı “hot” olan verileri önbelleğe almak bellek verimliliği açısından çok daha iyidir.
Cache-Aside Ne Zaman Parlıyor? ✨
Cache-Aside Ne Zaman Parlıyor? ✨
| Senaryo | Neden Çalışır |
|---|---|
| Okuma-ağırlıklı iş yükleri | Tekrar eden okumalar önbelleği vurur, DB’yi değil |
| Dengesiz erişim örüntüleri | Yalnızca popüler veriler önbelleğe alınır |
| Dayanıklılık gereksinimleri | Önbellek kapansa bile uygulama çalışmaya devam eder |
| Microservices | Her hizmet kendi önbellekleme mantığını sahiplenir |
Takaslarla İlgili Dürüst Ol
Takaslarla İlgili Dürüst Ol
Hiçbir model gümüş kurşun değildir. Cache-Aside’ın gerçek zorlukları vardır:
1. Cache Stampede (Thundering Herd)
1. Cache Stampede (Thundering Herd)
Popüler bir önbellek anahtarı süresi dolduğunda, birden fazla istemci talebi DB’ye aynı anda yüklenebilir.
Çözüm: Laravel’in Cache::lock() yöntemini kullanarak dağıtılmış bir kilit (mutex) kullanın:
public function getUserWithLock(int $userId): ?User
{
$cacheKey = "user:{$userId}";
$lockKey = "lock:user:{$userId}";
$cached = Cache::get($cacheKey);
if ($cached !== null) {
return $cached;
}
// Kısa süreli atomik bir kilit edin
$lock = Cache::lock($lockKey, 5);
if (!$lock->get()) {
// Başka bir işlem veriyi alıyor — kısa bekle ve tekrar dene
usleep(100_000); // 100ms
return $this->getUserWithLock($userId);
}
try {
$user = User::find($userId);
if ($user) {
Cache::put($cacheKey, $user, self::CACHE_TTL);
}
return $user;
} finally {
$lock->release();
}
}
2. Eski Veri
2. Eski Veri
Yazım ile önbellek geçersiz kılma arasında kullanıcıların eski verileri okumalarına neden olabilecek bir süre vardır. Çoğu kullanım durumu için bu kabul edilebilir — ama toleransınızı bilin.
3. Soğuk Başlangıç Cezası
3. Soğuk Başlangıç Cezası
Yeni bir önbellek (bir yeniden başlatma veya ilk dağıtım sonrası), her talep için önbellek miss anlamına gelir. Isınma süresi için plan yapın veya kritik anahtarları önceden doldurun.
4. Önbellek Geçersiz Kılma Karmaşıklığı
4. Önbellek Geçersiz Kılma Karmaşıklığı
Phil Karlton, ünlü bir sözünde şöyle demiştir:
“Bilgisayar Biliminde yalnızca iki zor şey vardır: önbellek geçersiz kılma ve şeyleri adlandırma.”
Cache-Aside ile geçersiz kılma sizin sorumluluğunuz. Yazım sırasında bir geçersiz kılma yolunu atlarsanız, eski veriler kalır.
Cache-Aside vs. Diğer Modeller
Cache-Aside vs. Diğer Modeller
| Model | Önbelleği kim yönetir | Veri ne zaman yüklenir |
|---|---|---|
| Cache-Aside | Uygulama | İlk okumada (tembel) |
| Read-Through | Önbellek katmanı | İlk okumada (tembel) |
| Write-Through | Önbellek katmanı | Her yazımda (istekli) |
| Write-Behind | Önbellek katmanı | Yazımdan sonra asenkron |
Cache-Aside, önbellekleme mantığını uygulamaya yakın bir şekilde tutmak ve sıkı bir şekilde bir önbellek middleware’ine bağımlı kalmaktan kaçınmak istediğinizde size en fazla kontrol ve esneklik sağlar.
Gerçek Dünya Mimarisi
Gerçek Dünya Mimarisi
Bu, tipik bir web hizmetinde nasıl görünür:
┌─────────┐ okuma ┌─────────────┐
│ Client │ ─────────────▶│ API Layer │
└─────────┘ └──────┬──────┘
│
┌────────────▼────────────┐
│ Cache (Redis) │
│ HIT → erken geri döndür│
└────────────┬────────────┘
│ MISS
┌────────────▼────────────┐
│ Database (Postgres) │
│ al + önbelleği doldur │
└─────────────────────────┘
Yazımlarda, API veritabanını günceller ve etkilenen önbellek anahtarlarını siler. Basit ve denetlenebilir.
Ana Noktalar
Ana Noktalar
- Cache-Aside tembel: yalnızca talep edilen veriler önbelleğe alınır.
- Uygulamanız önbelleği yönetir: gizli bir sihir yok, tam şeffaflık.
- Sınır durumlarını yönetin: stampides, soğuk başlangıçlar ve eski okumalar gerçektir — bunlar için plan yapın.
- TTL dostunuzdur: her zaman bir süre bitimi ayarlayın. Önbellekler, asla kalıcı gerçeklik kaynakları olmamalıdır.
- İzleme ile birleştirin: önbellek hit oranınızı takip edin. Okuma-ağırlıklı bir sistemde %80’in altındaysa, inceleme sinyali veriyor demektir.
Sonuç
Sonuç
Cache-Aside pattern, benimsemeniz gereken temel yapı taşlarından biridir. Şeffaf, dayanıklı (önbellek kullanılamaz hale geldiğinde uygulama düzgün bir şekilde çalışır) ve bellek üzerinde neyin bulunacağı üzerinde hassas kontrol sağlar.
Önce basit başlayın: en maliyetli, en tekrarlayan okumalara ekleyin. Değişimi ölçün. Sonra geliştirin.
Bunlar faydalı oldu mu? Bir ❤️ bırakın veya önbellek geçersiz kılma hikayenizi yorumlarda paylaşın — dışarıda bunları nasıl yönettiğinizi duymak isterim.
Kaynak: Orijinal Makale
- Temel Fikir
- Okuma Akışı
- Kodu Göster
- Neden Her Şeyi Başlangıçta Önbelleğe Almıyoruz?
- Cache-Aside Ne Zaman Parlıyor? ✨
- Takaslarla İlgili Dürüst Ol
- 1. Cache Stampede (Thundering Herd)
- 2. Eski Veri
- 3. Soğuk Başlangıç Cezası
- 4. Önbellek Geçersiz Kılma Karmaşıklığı
- Cache-Aside vs. Diğer Modeller
- Gerçek Dünya Mimarisi
- Ana Noktalar
- Sonuç


