Türkiye'de ilk Mobil & PC Aynı Anda Metin2 Oyna. Triarchonline kalıcı ve uzun ömürlü yapısı ile 24 Temmuz'da açılıyor. | 1-99 Mobil Metin2 Triarch HEMEN TIKLA!
[NODE JS] Redis ile Cache Mekanizması Kurma
Cache mekanizması, bir uygulamanın performansını iyileştirmek için en etkili yöntemlerden biridir. İlk büyük projemde veritabanı sorguları sayfanın yüklenmesini 3-4 saniye geciktiriyordu. Redis cache ekledikten sonra aynı sayfalar 200 milisaniyenin altında yüklenmeye başladı. Bu deneyim bana caching stratejisinin ne kadar kritik olduğunu gösterdi.
Cache mekanizmasının temel mantığı basittir: sık erişilen ve nadiren değişen verileri hızlı bir depolama katmanında tutmak. Redis bu iş için biçilmiş kaftandır çünkü bellekte çalışır ve mikrosaniye seviyesinde okuma yapabilir. Ancak "her şeyi cache'le" yaklaşımı doğru değildir. Hangi verilerin cache'lenmesi gerektiğini, ne kadar süreyle tutulacağını ve ne zaman geçersiz kılınacağını planlamanız gerekir.
Cache stratejileri arasında en yaygın olanı "Cache-Aside" (Lazy Loading) pattern'idir. Bu yaklaşımda önce cache kontrol edilir, veri varsa direkt döndürülür, yoksa veritabanından çekilip cache'e yazılır ve sonra döndürülür. Bu basit ama etkili bir yöntemdir. Dezavantajı ise ilk istekte her zaman cache miss yaşanmasıdır.
Bir diğer strateji "Write-Through" pattern'idir. Bu yaklaşımda veri her yazıldığında hem veritabanına hem de cache'e aynı anda yazılır. Bu şekilde cache her zaman güncel kalır ve okuma sırasında miss yaşanmaz. Ancak yazma işlemleri biraz daha yavaşlar çünkü iki yere yazılması gerekir.
TTL (Time To Live) ayarı, cache yönetiminin en kritik parametresidir. Çok kısa TTL cache'in faydalarını azaltırken, çok uzun TTL eski verilerin sunulmasına neden olabilir. Veri tipine göre TTL'i ayarlamanız gerekir. Örneğin, ürün listesi için 5 dakika uygunken, kullanıcı profili için 1 saat daha mantıklı olabilir. Anlık değişen veriler (stok miktarı gibi) için ise çok kısa TTL veya hiç cache kullanmamak gerekebilir.
Cache invalidation, bilgisayar biliminin en zor problemlerinden biri olarak kabul edilir. Veri güncellendiğinde ilgili cache girişlerini doğru zamanda temizlemek kritik öneme sahiptir. Yanlış invalidation stratejisi, kullanıcılara eski veri gösterilmesine veya gereksiz cache temizlemelerine yol açar. Ben projelerimde genellikle event-driven invalidation kullanıyorum: veri değiştiğinde bir olay tetikleniyor ve ilgili cache anahtarları siliniyor.
Bir production ortamında cache hit rate'inizi mutlaka izlemelisiniz. Eğer hit rate düşükse, ya TTL'leriniz çok kısa ya da cache anahtarlarınız çok spesifik demektir. İdeal bir cache sistemi yüzde 80-90 üzeri hit rate'e sahip olmalıdır. Bu oran ne kadar yüksekse, veritabanınız o kadar az yük altında kalır.
JavaScript:
// Redis ile Cache Mekanizması - Kapsamlı Örnek
const Redis = require('ioredis');
const express = require('express');
const app = express();
const redis = new Redis({
host: '127.0.0.1',
port: 6379,
password: 'guclu_sifre_123'
});
// ==========================================
// Cache Yardımcı Sınıfı
// ==========================================
class CacheYonetici {
constructor(redisIstemci, varsayilanTTL = 300) {
this.redis = redisIstemci;
this.varsayilanTTL = varsayilanTTL; // saniye cinsinden
this.onEk = 'cache:';
}
// Cache anahtarı oluşturma
anahtarOlustur(kategori, kimlik) {
return this.onEk + kategori + ':' + kimlik;
}
// Cache'den veri okuma
async oku(anahtar) {
const veri = await this.redis.get(anahtar);
if (veri) {
console.log('Cache HIT:', anahtar);
return JSON.parse(veri);
}
console.log('Cache MISS:', anahtar);
return null;
}
// Cache'e veri yazma
async yaz(anahtar, deger, ttl) {
const sureSaniye = ttl || this.varsayilanTTL;
await this.redis.set(anahtar, JSON.stringify(deger), 'EX', sureSaniye);
console.log('Cache yazıldı:', anahtar, '- TTL:', sureSaniye, 'saniye');
}
// Cache'den veri silme
async sil(anahtar) {
await this.redis.del(anahtar);
console.log('Cache silindi:', anahtar);
}
// Belirli bir desene uyan tüm anahtarları silme
async desenileSil(desen) {
const anahtarlar = await this.redis.keys(this.onEk + desen);
if (anahtarlar.length > 0) {
await this.redis.del(...anahtarlar);
console.log('Silinen cache sayısı:', anahtarlar.length);
}
}
// Cache-Aside Pattern
async cacheBenimle(anahtar, veriGetirFn, ttl) {
// Önce cache'e bak
const cacheDeger = await this.oku(anahtar);
if (cacheDeger !== null) {
return cacheDeger;
}
// Cache'de yoksa veriyi getir
const tazeDeger = await veriGetirFn();
// Cache'e yaz
if (tazeDeger !== null && tazeDeger !== undefined) {
await this.yaz(anahtar, tazeDeger, ttl);
}
return tazeDeger;
}
// Cache istatistikleri
async istatistikler() {
const bilgi = await this.redis.info('stats');
const satirlar = bilgi.split('
');
const sonuc = {};
satirlar.forEach(satir => {
if (satir.includes('keyspace_hits')) {
sonuc.isabet = parseInt(satir.split(':')[1]);
}
if (satir.includes('keyspace_misses')) {
sonuc.kacirma = parseInt(satir.split(':')[1]);
}
});
if (sonuc.isabet !== undefined && sonuc.kacirma !== undefined) {
const toplam = sonuc.isabet + sonuc.kacirma;
sonuc.isabetOrani = toplam > 0
? ((sonuc.isabet / toplam) * 100).toFixed(2) + '%'
: '0%';
}
return sonuc;
}
}
// Cache yöneticisi örneği
const cache = new CacheYonetici(redis, 300);
// ==========================================
// Sahte Veritabanı Sorguları (simülasyon)
// ==========================================
function veritabanindenUrunGetir(urunId) {
return new Promise((resolve) => {
// Veritabanı gecikmesini simüle ediyoruz
setTimeout(() => {
resolve({
id: urunId,
isim: 'Kablosuz Kulaklık',
fiyat: 899.99,
stok: 45,
kategori: 'Elektronik',
aciklama: 'Yüksek kaliteli kablosuz kulaklık',
guncellenmeTarihi: new Date().toISOString()
});
}, 200); // 200ms veritabanı gecikmesi
});
}
function veritabanindenUrunleriListele(kategori) {
return new Promise((resolve) => {
setTimeout(() => {
resolve([
{ id: 1, isim: 'Laptop', fiyat: 25000, kategori: kategori },
{ id: 2, isim: 'Telefon', fiyat: 15000, kategori: kategori },
{ id: 3, isim: 'Tablet', fiyat: 12000, kategori: kategori },
{ id: 4, isim: 'Kulaklık', fiyat: 899, kategori: kategori },
{ id: 5, isim: 'Şarj Cihazı', fiyat: 350, kategori: kategori }
]);
}, 300);
});
}
// ==========================================
// Express Middleware - Cache Katmanı
// ==========================================
function cacheMiddleware(ttlSaniye) {
return async (req, res, next) => {
const cacheAnahtari = 'cache:sayfa:' + req.originalUrl;
try {
const cacheSonuc = await redis.get(cacheAnahtari);
if (cacheSonuc) {
console.log('Sayfa cache'den sunuluyor:', req.originalUrl);
return res.json(JSON.parse(cacheSonuc));
}
} catch (hata) {
console.error('Cache okuma hatası:', hata.message);
}
// Orijinal res.json'ı yakala ve cache'e yaz
const orijinalJson = res.json.bind(res);
res.json = async (veri) => {
try {
await redis.set(cacheAnahtari, JSON.stringify(veri), 'EX', ttlSaniye);
console.log('Sayfa yanıtı cache'e yazıldı:', req.originalUrl);
} catch (hata) {
console.error('Cache yazma hatası:', hata.message);
}
return orijinalJson(veri);
};
next();
};
}
// ==========================================
// API Rotaları
// ==========================================
// Ürün detay - Cache-Aside pattern
app.get('/api/urunler/:id', async (req, res) => {
const urunId = req.params.id;
const cacheAnahtari = cache.anahtarOlustur('urun', urunId);
const urun = await cache.cacheBenimle(
cacheAnahtari,
() => veritabanindenUrunGetir(urunId),
600 // 10 dakika TTL
);
res.json({ basarili: true, veri: urun });
});
// Ürün listesi - Middleware ile cache
app.get('/api/urunler', cacheMiddleware(300), async (req, res) => {
const kategori = req.query.kategori || 'Elektronik';
const urunler = await veritabanindenUrunleriListele(kategori);
res.json({ basarili: true, veri: urunler, toplam: urunler.length });
});
// Ürün güncelleme - Cache invalidation
app.put('/api/urunler/:id', express.json(), async (req, res) => {
const urunId = req.params.id;
// Veritabanını güncelle (simülasyon)
console.log('Ürün güncelleniyor:', urunId);
// İlgili cache'leri temizle
const urunCacheAnahtari = cache.anahtarOlustur('urun', urunId);
await cache.sil(urunCacheAnahtari);
await cache.desenileSil('sayfa:*urunler*');
res.json({ basarili: true, mesaj: 'Ürün güncellendi ve cache temizlendi' });
});
// Cache istatistikleri
app.get('/api/cache/istatistikler', async (req, res) => {
const istatistik = await cache.istatistikler();
res.json({ basarili: true, veri: istatistik });
});
app.listen(3000, () => {
console.log('Sunucu 3000 portunda çalışıyor');
});
Cache mekanizması doğru uygulandığında uygulamanızın performansını dramatik şekilde artırır. Ancak unutmayın ki cache her derde deva değildir. Veri tutarlılığı, bellek yönetimi ve invalidation stratejisi gibi konuları iyi planlamadan cache eklemek, çözdüğünden daha fazla sorun yaratabilir. Her zaman ölçün, izleyin ve gerektiğinde stratejinizi güncelleyin.
Emeğiniz ve katkınız için teşekkür ederiz!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 0
- Görüntüleme
- 52
- Cevaplar
- 9
- Görüntüleme
- 474
Altın Konu
Next.js'de API Oluşturma Ve Kullanma
- Cevaplar
- 12
- Görüntüleme
- 1K
- Cevaplar
- 0
- Görüntüleme
- 999
