Skip to content

Instantly share code, notes, and snippets.

@firatoltulu
Last active September 16, 2024 12:27
Show Gist options
  • Save firatoltulu/b491203d5f911e06981ebb622f6ca782 to your computer and use it in GitHub Desktop.
Save firatoltulu/b491203d5f911e06981ebb622f6ca782 to your computer and use it in GitHub Desktop.
HybridCache üzerine

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.

HybridCache Yapısının Avantajları

  1. Performans İyileştirmesi: Veri ilk olarak daha hızlı olan bellekte aranır. Bulunamazsa, daha büyük ve yavaş bir önbellek sisteminden getirilir.
  2. Ölçeklenebilirlik: İki katmanlı yapı, daha geniş veri kümelerini destekleyerek uygulamanın ölçeklenebilirliğini artırır.
  3. 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.
  4. 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.

HybridCache Nasıl İmplement Edilir?

C#’ta HybridCache uygulamak için farklı stratejiler kullanabilirsiniz. Aşağıda, MemoryCache ve RedisCache kullanarak bir HybridCache implementasyonu yapılmıştır.

1. Gerekli Paketlerin Yüklenmesi

İ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

2. HybridCache Sınıfı Oluşturulması

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);
    }
}

3. Kullanım Örneği

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’in Özelleştirilmesi

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.

Sonuç

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.

Ek Kaynaklar

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.

Yatay Sunucu konfigürasyonlarında, MemoryCache'lerin Senkronizasyonu

Redis Channel ve Pub-Sub Nedir?

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.

HybridCache’e Redis Channel Desteği Ekleme

1. Redis Pub-Sub İçin Gerekli Paketler

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

2. HybridCache Sınıfını Güncelleme

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);
    }
}

3. Kullanım Örneği

// 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.

Redis Channel ile MemoryCache Senkronizasyonu

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.

Sonuç

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ı:

  1. Veri Tutarlılığı: Tüm uygulamalar arasında cache verilerinin tutarlılığı sağlanır.
  2. Otomasyon: Redis Channel ile otomatik veri temizleme işlemi gerçekleşir.
  3. 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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment