HybridCache Nedir?
HybridCache, bir uygulamanın birden fazla önbellek katmanını aynı anda kullanmasına olanak tanıyan bir caching stratejisidir. Genellikle, iki katmanlı cache mimarisi benimsenir: birinci katman hızlı ancak daha küçük boyutlu (örneğin, MemoryCache), ikinci katman ise daha yavaş ama daha geniş kapasiteye sahip (örneğin, Redis gibi bir uzak sunucu bazlı cache). Bu sayede, uygulama hem performansı artırırken hem de geniş veri setlerini önbellekte tutabilir.
- Performans İyileştirmesi: Veri ilk olarak daha hızlı olan bellekte aranır. Bulunamazsa, daha büyük ve yavaş bir önbellek sisteminden getirilir.
- Ölçeklenebilirlik: İki katmanlı yapı, daha geniş veri kümelerini destekleyerek uygulamanın ölçeklenebilirliğini artırır.
- Esneklik: Farklı cache türlerini bir arada kullanarak esneklik sağlar. Hem hızlı erişim gerektiren hem de büyük veriyi kapsayan ihtiyaçları karşılar.
- Düşük Maliyet: Uzun süreli saklanması gereken büyük veriler için daha ucuz bir uzak cache (Redis gibi) kullanılırken, kısa süreli ve hızlı erişim gereken veriler bellek üzerinde tutulabilir.
C#’ta HybridCache uygulamak için farklı stratejiler kullanabilirsiniz. Aşağıda, MemoryCache ve RedisCache kullanarak bir HybridCache implementasyonu yapılmıştır.
İlk adım olarak, Redis için gerekli NuGet paketlerini yüklemeniz gerekiyor.
Install-Package Microsoft.Extensions.Caching.Memory
Install-Package Microsoft.Extensions.Caching.StackExchangeRedis
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
public class HybridCache
{
private readonly IMemoryCache _memoryCache;
private readonly IDistributedCache _distributedCache;
public HybridCache(IMemoryCache memoryCache, IDistributedCache distributedCache)
{
_memoryCache = memoryCache;
_distributedCache = distributedCache;
}
public void Set<T>(string key, T value, TimeSpan cacheTime)
{
// MemoryCache'e kaydet
_memoryCache.Set(key, value, cacheTime);
// RedisCache'e kaydet
var redisValue = JsonConvert.SerializeObject(value);
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = cacheTime
};
_distributedCache.SetString(key, redisValue, options);
}
public T Get<T>(string key)
{
// MemoryCache'den al
if (_memoryCache.TryGetValue(key, out T value))
{
return value;
}
// RedisCache'den al
var redisValue = _distributedCache.GetString(key);
if (redisValue != null)
{
value = JsonConvert.DeserializeObject<T>(redisValue);
// Redis'ten gelen veriyi MemoryCache'e yaz
_memoryCache.Set(key, value, TimeSpan.FromMinutes(5)); // Default süre 5 dakika
return value;
}
return default;
}
public void Remove(string key)
{
// MemoryCache ve RedisCache'den veriyi sil
_memoryCache.Remove(key);
_distributedCache.Remove(key);
}
}
var memoryCache = new MemoryCache(new MemoryCacheOptions());
var distributedCache = new RedisCache(new RedisCacheOptions
{
Configuration = "localhost", // Redis sunucu bağlantısı
InstanceName = "SampleInstance"
});
var hybridCache = new HybridCache(memoryCache, distributedCache);
// Veriyi cache'e ekle
hybridCache.Set("user_firat", new { Name = "Fırat", Age = 40}, TimeSpan.FromMinutes(30));
// Veriyi cache'den oku
var user = hybridCache.Get<dynamic>("user_firat");
Console.WriteLine(user.Name); // Output: Fırat
// Cache'den veriyi sil
hybridCache.Remove("user_firat");
HybridCache, çeşitli kullanım senaryolarına göre özelleştirilebilir. Örneğin:
- Sliding Expiration: Verinin ömrünü her erişimle birlikte uzatmak isteyebilirsiniz.
- Priority Level: Belirli verilerin öncelikli olarak bellekte tutulmasını sağlayabilirsiniz.
- Fallback Mekanizması: Uzak cache sunucusunun (Redis) kullanılamaz hale gelmesi durumunda alternatif bir mekanizma tasarlanabilir.
HybridCache, C# uygulamalarında hem hızlı hem de büyük ölçekli caching ihtiyaçlarını karşılamak için ideal bir çözümdür. Bu strateji, performans ve ölçeklenebilirliği dengelerken esneklik de sağlar. Özellikle, anlık veri erişimi ve büyük veri setlerinin aynı anda yönetilmesi gerektiği projelerde MemoryCache ve RedisCache gibi farklı cache teknolojilerini bir araya getirmek oldukça etkilidir.
Bu makalede, C# dilinde HybridCache yapısının nasıl uygulanabileceğini ve hangi avantajları sunduğunu inceledik. Cache stratejileri hakkında daha fazla bilgi edinmek, uygulama performansını artırmak için önemli bir adımdır.
Redis Channel, Redis'in pub-sub (yayınla-abone ol) mekanizmasını kullanarak birden fazla istemciye olay bazlı mesajlar iletmesini sağlar. Bir istemci belirli bir kanala abone olurken, diğer istemci bu kanala mesaj (publish) gönderir. Örneğin, Redis üzerinde bir veri silindiğinde, bu bilgiyi diğer tüm uygulamalara iletmek için bir kanal (channel) oluşturulabilir. Bu kanal sayesinde, her uygulama MemoryCache'lerinde de aynı anahtarı silerek veri bütünlüğünü koruyabilir.
Redis Channel'ı kullanmak için StackExchange.Redis kütüphanesi gerekmektedir. Bu kütüphane Redis ile etkileşime geçmemize olanak tanır.
Install-Package StackExchange.Redis
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Caching.Distributed;
using Newtonsoft.Json;
using StackExchange.Redis;
using System;
public class HybridCache
{
private readonly IMemoryCache _memoryCache;
private readonly IDistributedCache _distributedCache;
private readonly ISubscriber _redisSubscriber;
public HybridCache(IMemoryCache memoryCache, IDistributedCache distributedCache, ConnectionMultiplexer redisConnection)
{
_memoryCache = memoryCache;
_distributedCache = distributedCache;
_redisSubscriber = redisConnection.GetSubscriber();
// Redis Channel'a abone ol
_redisSubscriber.Subscribe("cache_invalidation_channel", (channel, key) =>
{
// Redis'ten gelen silme mesajıyla MemoryCache'deki veriyi sil
_memoryCache.Remove(key);
});
}
public void Set<T>(string key, T value, TimeSpan cacheTime)
{
// MemoryCache'e kaydet
_memoryCache.Set(key, value, cacheTime);
// RedisCache'e kaydet
var redisValue = JsonConvert.SerializeObject(value);
var options = new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = cacheTime
};
_distributedCache.SetString(key, redisValue, options);
}
public T Get<T>(string key)
{
// MemoryCache'den al
if (_memoryCache.TryGetValue(key, out T value))
{
return value;
}
// RedisCache'den al
var redisValue = _distributedCache.GetString(key);
if (redisValue != null)
{
value = JsonConvert.DeserializeObject<T>(redisValue);
// Redis'ten gelen veriyi MemoryCache'e yaz
_memoryCache.Set(key, value, TimeSpan.FromMinutes(5)); // Default süre 5 dakika
return value;
}
return default;
}
public void Remove(string key)
{
// MemoryCache'den ve RedisCache'den veriyi sil
_memoryCache.Remove(key);
_distributedCache.Remove(key);
// Redis Channel'a silme mesajı gönder
_redisSubscriber.Publish("cache_invalidation_channel", key);
}
}
// Redis bağlantısı
var redisConnection = ConnectionMultiplexer.Connect("localhost");
// MemoryCache ve RedisCache'i oluştur
var memoryCache = new MemoryCache(new MemoryCacheOptions());
var distributedCache = new RedisCache(new RedisCacheOptions
{
Configuration = "localhost", // Redis sunucu bağlantısı
InstanceName = "SampleInstance"
});
// HybridCache oluşturuluyor
var hybridCache = new HybridCache(memoryCache, distributedCache, redisConnection);
// Veriyi cache'e ekle
hybridCache.Set("user_firat", new { Name = "Firat", Age = 40}, TimeSpan.FromMinutes(30));
// Veriyi cache'den oku
var user = hybridCache.Get<dynamic>("user_firat");
Console.WriteLine(user.Name); // Output: Firat
// Cache'den veriyi sil
hybridCache.Remove("user_1"); // Bu işlem MemoryCache ve Redis'ten siler ve diğer uygulamalarda MemoryCache'leri günceller.
Bu yapı ile, uygulamalar arasındaki cache silme işlemleri senkronize edilmiştir. Bir uygulama RedisCache'deki veriyi sildiğinde, bu olay Redis Channel üzerinden diğer uygulamalara iletilir. Böylece, her bir uygulama kendi MemoryCache'inde bulunan veriyi de temizleyerek veri bütünlüğünü korumuş olur.
- cache_invalidation_channel adlı Redis kanalı, silme olaylarını diğer abonelere yayar.
- Her bir uygulama bu kanala abone olarak, gelen anahtara göre kendi MemoryCache'lerini temizler.
Bu makalede, HybridCache yapısına Redis'in pub-sub mekanizmasını entegre ederek MemoryCache'lerin senkronize olmasını sağladık. Böylece, Redis üzerinde bir anahtar silindiğinde, aynı anahtarın tüm uygulamalardaki MemoryCache'lerden de otomatik olarak kaldırılması sağlandı. Bu yöntem, birden fazla sunucu üzerinde çalışan dağıtık sistemlerde, cache’in veri tutarlılığını ve güvenilirliğini artıran önemli bir tekniktir.
Bu yapının avantajları:
- Veri Tutarlılığı: Tüm uygulamalar arasında cache verilerinin tutarlılığı sağlanır.
- Otomasyon: Redis Channel ile otomatik veri temizleme işlemi gerçekleşir.
- Performans: Gereksiz sorguları önleyerek performans artışı sağlanır.
Redis Channel ile uygulamalar arası senkronizasyon, büyük ve dağıtık sistemlerde cache yönetimini daha efektif hale getirir ve uygulamanın ölçeklenebilirliğini artırır.
Örnek Proje: https://github.com/firatoltulu/HybridCacheWithChannel