ASP.NET Core'da Cache-Aside Yaklaşımını Nerede Kullanıyorum
Her Get'in önüne Redis koymak bir strateji değil

Cache-aside'ı 'hız katmanı' diye anlatmak işi tersine çeviriyor. Aside bir karar: okuyan, yoksa kaynağa iner, sonra doldurur. Bu kararın bedeli invalidation'dır. Bedeli ödemeyeceksen aside koyma.
Serinin ilk yazısında stampede ve TTL'yi dağıttım. Bu yazı daha sıkıcı bir soru soruyor: aside'ı hangi endpoint'e hiç koymuyorum?
Aside'ın anlaşması
Okuyan kod cache'i bilir, yazan kod bazen bilmez. Bu asimetri hem güç hem risk. Güç: yazma yolunu değiştirmesen de okumayı hızlandırırsın. Risk: yazan sessizce eski değeri bırakır.
public sealed class CategoryReadService(IDistributedCache cache, AppDbContext db)
{
public async Task> ListAsync(CancellationToken ct)
{
const string key = "catalog:categories:v1";
var json = await cache.GetStringAsync(key, ct);
if (json is not null)
return JsonSerializer.Deserialize>(json)!;
var rows = await db.Categories.AsNoTracking()
.OrderBy(c => c.SortOrder)
.Select(c => new CategoryDto(c.Id, c.Name))
.ToListAsync(ct);
await cache.SetStringAsync(key, JsonSerializer.Serialize(rows), new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30)
}, ct);
return rows;
}
}
Kategori listesi aside için iyi aday. Az yazılır, çok okunur, yanlışlık 30 dakika çoğu vitrinde kabul edilir. Admin kaydettiğinde key'i silmek de tek satır. Bunu ürün sepetine kopyalamıyorum.
Koymadığım yerler
- Kullanıcıya özel ve sık değişen okumalar: sepet, oturum, taslak.
- Yazma sonrası hemen okunan akışlar: 'kaydet ve detayı göster'.
- Yetki filtresi istekten istekten değişen listeler.
Sepeti aside'a koymak, 'biraz eski sepet' demektir. Kullanıcı silinen satırı görür. Bunu TTL ile çözmeye çalışmak, invalidation'ı daha da dağıtır. Burada kaynak of truth veritabanı veya özel bir store olmalı; cache varsa write-through veya açık invalidation şart.
IMemoryCache ile aside
Tek instance'da IMemoryCache aside'ı basitleştirir. L1 olarak durabilir. İki instance'da L1 yalan söyler. Bu yüzden L1'i kısa tutuyorum (saniyeler) ve L2'yi Redis'e bırakıyorum. L1'i 'kalıcı çözüm' sanmak, deploy sonrası hayalet değer bırakır.
Karar özeti: aside'ı varsayılan middleware yapmıyorum. Endpoint'in okuma/yazma oranı, kabul edilen gecikme ve silinecek key kümesi netse koyuyorum. Net değilse önce sorguyu düzeltmek daha ucuz.
Yorumlar
Yorumlar (0)
Yorumlar üyelere açık. Üye ol · Giriş yap