RRedis Handbook

TEMEL

String İşlemleri

Temel key-value. Counter, cache, session, flag depolama.

Kod örneği görünümü Bu sayfadaki eşleşen örnekleri seçilen istemciye göre gösterir.
# Temel CRUD
SET user:1:name "Erdem"
GET user:1:name                     # "Erdem"
DEL user:1:name

# TTL ile
SET session:abc "data" EX 3600      # 1 saat
TTL session:abc                     # kalan saniye
PERSIST session:abc                 # TTL kaldır

# Conditional
SET lock:resource "owner" NX EX 30  # sadece yoksa set et
SET counter 100 XX                  # sadece varsa set et

# Batch
MSET user:1:name "Erdem" user:1:email "a@b.com"
MGET user:1:name user:1:email

# Atomik sayaç
INCR pageviews:home
INCRBY user:1:score 50
DECRBY stock:product:1 1
public class StringOperationsService
{
    private readonly IDatabase _redis;

    public StringOperationsService(IConnectionMultiplexer mux)
        => _redis = mux.GetDatabase();

    // Temel CRUD
    public async Task BasicCrudAsync()
    {
        await _redis.StringSetAsync("user:1:name", "Erdem");
        string? name = await _redis.StringGetAsync("user:1:name");
        await _redis.KeyDeleteAsync("user:1:name");
    }

    // TTL ile cache
    public async Task SetWithTtlAsync(string key, string value, TimeSpan expiry)
    {
        await _redis.StringSetAsync(key, value, expiry);
    }

    // Conditional set (distributed lock temeli)
    public async Task<bool> TryAcquireLockAsync(string resource, string owner, TimeSpan expiry)
    {
        return await _redis.StringSetAsync(
            $"lock:{resource}", owner, expiry, When.NotExists);
    }

    // Batch (roundtrip azaltır)
    public async Task BatchSetAsync(Dictionary<string, string> pairs)
    {
        var entries = pairs.Select(p =>
            new KeyValuePair<RedisKey, RedisValue>(p.Key, p.Value)).ToArray();
        await _redis.StringSetAsync(entries);
    }

    // Atomik sayaç
    public async Task<long> IncrementAsync(string key, long amount = 1)
    {
        return await _redis.StringIncrementAsync(key, amount);
    }

    // JSON serialize ile obje cache
    public async Task<T?> GetOrSetAsync<T>(string key, Func<Task<T>> factory, TimeSpan ttl)
    {
        var cached = await _redis.StringGetAsync(key);
        if (cached.HasValue)
        {
            try
            {
                return JsonSerializer.Deserialize<T>(cached!);
            }
            catch (JsonException)
            {
                // Corrupt/incompatible data — sil ve yeniden üret
                await _redis.KeyDeleteAsync(key);
            }
        }

        var value = await factory();
        if (value is not null)
            await _redis.StringSetAsync(key,
                JsonSerializer.Serialize(value), ttl);
        return value;
    }
}

StringSet vs IDistributedCache: StackExchange.Redis doğrudan kullanımda her Redis komutuna erişirsin. IDistributedCache ise sadece Get/Set/Remove sunar — başka provider'a geçiş kolaylığı sağlar ama Redis'in gücünü kısıtlar.

Cache Stampede: Yukarıdaki GetOrSetAsync basit implementasyondur. Yoğun trafikte aynı key için eşzamanlı N request gelirse hepsi cache miss yaşar → N kez DB'ye gider. Çözüm: lock-based double-check pattern (Caching Patterns bölümündeki GetWithStampedeProtectionAsync örneğine bak).