Senaryo: "Önbellek koyalım"
Sistem yavaş, biri önbellek öneriyor. Önbellek hızlı bir kısayol gibi görünür ama iki soruna yol açar: yanlış veri ve sorunu örtmek. Salı sabahı pahalı sorguyu önbelleğe alsan okuma düşer, ama hatalı sorgu yerinde durur ve önbellek boşaldığı anda yük geri gelir.
ops_ tabloları hayali bir portal için tohumlu üreteçle kuruldu. Gerçek bir sistemden alınmadı; süre ve okuma değerleri ölçüm değildir. Motor SQLite olduğu için günlükteki SQL Server sorguları çalıştırılmaz, metin olarak incelenir. Tabloları sorgularsın, sistem yönetimi komutlarını yalnız okursun.Karar soruları
| Soru | Önbelleğe uygun | Uygun değil |
|---|---|---|
| Aynı veri tekrar okunuyor mu? | Çok tekrar | Çoğu istek ıskalıyor: kontrol maliyeti kazancı geçer |
| Veri ne sıklıkla değişiyor? | Seyrek | Sık yazılıyor |
| Bayat değerin bedeli ne? | Düşük: ürün kategorisi, şube listesi | Yüksek: hesap bakiyesi, stok, yetki |
| Hassas mı? | Hayır | Güvenlik verisi kaynaktan okunur |
| Asıl sorun çözüldü mü? | Sorgu zaten iyi, yalnız çok sık | Sorgu hatalı: önce onu düzelt |
Son iki satır önemli. Mimari rehberi hassas ve güvenlik verisini önbelleğe almamayı, her zaman birincil kaynaktan okumayı önerir. Çoğu isteğin ıskaladığı durumda da önbellek zarar eder.
Hangi önbellek?
| Katman | Örnek | Kim yönetir | Nerede anlatıldı |
|---|---|---|---|
| Veritabanı belleği | Tampon havuzu, plan önbelleği | Motor, otomatik | Mimari ve Yürütme planı dersleri |
| Hesaplanmış sonuç | Özet tablo, materialized view, indexed view | Sen, yenileme ile | Görünümler ve Toplama dersleri |
| Uygulama önbelleği | Anahtar-değer deposu, süreç içi bellek | Uygulama | Bu ders |
İsabet oranını önceden tahmin et
Önbelleği kurmadan önce günlükten bir tahmin alırsın. Soru: Bir kayıt, kendisinin önceki okumasından en çok N saniye sonra yine okunuyor mu? Öyleyse önbellekten gelebilirdi.
WITH o AS (
SELECT event_at, LAG(event_at) OVER (PARTITION BY record_id ORDER BY event_at, event_id) AS onceki
FROM ops_access_log
WHERE event_type = 'read' AND login_name = 'svc_portal'
)
SELECT COUNT(*) AS okuma,
SUM(CASE WHEN onceki IS NOT NULL AND (julianday(event_at) - julianday(onceki)) * 86400 <= 60 THEN 1 ELSE 0 END) AS isabet_60sn,
SUM(CASE WHEN onceki IS NOT NULL AND (julianday(event_at) - julianday(onceki)) * 86400 <= 300 THEN 1 ELSE 0 END) AS isabet_5dk,
SUM(CASE WHEN onceki IS NOT NULL AND (julianday(event_at) - julianday(onceki)) * 86400 <= 900 THEN 1 ELSE 0 END) AS isabet_15dk
FROM o;
Bu kaba bir tahmindir: Sonsuz kapasite varsayar, önbellekten atılmayı (eviction) hesaba katmaz, süreyi son okumadan sayar (kayan süre). Süreyi uzatmanın ne kazandırdığını görmek için asıl kullanılır: bir noktadan sonra süre uzar, isabet artmaz, yalnız bayat kalma riski büyür.
Bayat veri riski
Yazma olduğunda önbellekteki kopya eskir. Yazmadan sonraki süre içinde gelen okumalar eski değeri görebilir:
SELECT COUNT(*) AS riskli_okuma FROM ops_access_log w JOIN ops_access_log r ON r.record_id = w.record_id AND r.event_type = 'read' AND (julianday(r.event_at) - julianday(w.event_at)) * 86400 BETWEEN 1 AND 300 WHERE w.event_type = 'write';
Bu üst sınırdır: Kayıt yazmadan önce önbellekte olmayabilir. Ölçüm kararı destekler, kararı vermez. Sayı küçük olsa da o veri hesap bakiyesiyse kabul edilemez, ürün açıklamasıysa sorun değildir.
Bayatlığı yönetmek
- Süre (TTL): Çok kısa olursa sürekli yeniden okursun, çok uzun olursa veri bayatlar. Süreyi erişim desenine göre seç.
- Yazınca sil: Önce veritabanına yaz, sonra önbellek anahtarını sil. Sıra ters olursa araya giren okuma eski değeri önbelleğe geri koyar.
- Tutarlılık garantisi yok: Önbelleğe sormadan başka süreç veritabanını değiştirirse önbellek bunu bilmez. Yazmadan sonra tazelik zorunluysa bu desen uygun değildir.
- Boşalma: Önbellek düştüğünde bütün yük veritabanına biner. Veritabanı önbelleksiz yükü taşıyamıyorsa kırılgan bir sistem kurmuşsundur.