DevOps & Cloud
Redis Cache-Verwaltung: .NET Core & Leistungsoptimierung
Redis ist ein leistungsstarker In-Memory-Datenstrukturspeicher, der fuer Distributed Cache, Session-Verwaltung, Nachrichtenwarteschlangen und Echtzeitanwendungen unverzichtbar ist. Im .NET-Oekosystem laesst sich Redis nahtlos ueber die IDistributedCache-Schnittstelle integrieren und dient als SignalR-Backplane fuer die Echtzeitkommunikation ueber mehrere Serverinstanzen hinweg.
Redis .NET-Integration
Grundlegende Verwendung mit IDistributedCache
Die IDistributedCache-Schnittstelle von .NET bietet eine anbieterunabhaengige Abstraktion. Der Wechsel zu Redis erfordert nur eine Registrierungsaenderung.
// Program.cs - Redis Cache Registrierung
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = builder.Configuration.GetConnectionString("Redis");
options.InstanceName = "MyApp:";
});
// Cache-Verwendung in der Serviceschicht
public class ProductService
{
private readonly IDistributedCache _cache;
private readonly ApplicationDbContext _context;
private static readonly DistributedCacheEntryOptions CacheOptions = new()
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(30),
SlidingExpiration = TimeSpan.FromMinutes(10)
};
public ProductService(IDistributedCache cache, ApplicationDbContext context)
{
_cache = cache;
_context = context;
}
public async Task<ProductDto?> GetProductAsync(int id, CancellationToken ct)
{
var cacheKey = $"product:{id}";
// Aus dem Cache lesen
var cached = await _cache.GetStringAsync(cacheKey, ct);
if (cached is not null)
return JsonSerializer.Deserialize<ProductDto>(cached);
// Aus der Datenbank abrufen und in den Cache schreiben
var product = await _context.Products
.Where(p => p.Id == id)
.Select(p => new ProductDto(p.Id, p.Name, p.Price))
.FirstOrDefaultAsync(ct);
if (product is not null)
{
var json = JsonSerializer.Serialize(product);
await _cache.SetStringAsync(cacheKey, json, CacheOptions, ct);
}
return product;
}
}Erweiterte Operationen mit StackExchange.Redis
Fuer die volle Nutzung der Redis-Funktionalitaet koennen Sie die StackExchange.Redis-Bibliothek direkt verwenden:
// Redis Connection Multiplexer Registrierung
builder.Services.AddSingleton<IConnectionMultiplexer>(sp =>
{
var config = ConfigurationOptions.Parse(
builder.Configuration.GetConnectionString("Redis")!);
config.AbortOnConnectFail = false;
config.ConnectRetry = 3;
config.ConnectTimeout = 5000;
return ConnectionMultiplexer.Connect(config);
});
// Erweiterte Redis-Operationen
public class RedisCacheService
{
private readonly IDatabase _db;
public RedisCacheService(IConnectionMultiplexer redis)
{
_db = redis.GetDatabase();
}
// Sorted Set fuer Rangliste
public async Task UpdateLeaderboardAsync(string userId, double score)
{
await _db.SortedSetAddAsync("leaderboard", userId, score);
}
// Distributed Lock
public async Task<bool> AcquireLockAsync(string resource, TimeSpan expiry)
{
return await _db.StringSetAsync(
$"lock:{resource}", Environment.MachineName, expiry, When.NotExists);
}
}SignalR Redis Backplane
Wenn Ihre Anwendung auf mehreren Servern laeuft, muessen SignalR-Nachrichten an alle Server uebermittelt werden. Das Redis-Backplane loest dieses Problem.
// Program.cs - SignalR Redis Backplane Konfiguration
builder.Services.AddSignalR()
.AddStackExchangeRedis(builder.Configuration.GetConnectionString("Redis")!, options =>
{
options.Configuration.ChannelPrefix = RedisChannel.Literal("MyApp");
});Cache-Strategien und Invalidierung
Cache-Invalidierung ist eines der schwierigsten Probleme in verteilten Systemen. Eine falsche Invalidierung fuehrt zu veralteten Daten oder unnoetigen Cache-Misses:
- Cache-Aside: Daten werden zuerst aus dem Cache gelesen; falls nicht vorhanden, aus der Quelle abgerufen
- Write-Through: Datenbank und Cache werden gleichzeitig aktualisiert
- TTL-basiert: Automatische Ablaufzeit fuer einfache Invalidierung
- Event-basiert: Aktives Loeschen des Caches bei Datenaenderungen
- Pattern-basiert: Massenhaftes Loeschen basierend auf Key-Mustern
// Pattern-basierte Cache-Invalidierung
public class CacheInvalidationService
{
private readonly IConnectionMultiplexer _redis;
public CacheInvalidationService(IConnectionMultiplexer redis)
{
_redis = redis;
}
// Cache fuer alle Produkte einer Kategorie invalidieren
public async Task InvalidateCategoryProductsAsync(int categoryId)
{
var server = _redis.GetServer(_redis.GetEndPoints().First());
var db = _redis.GetDatabase();
var keys = server.Keys(pattern: $"MyApp:product:category:{categoryId}:*");
foreach (var key in keys)
{
await db.KeyDeleteAsync(key);
}
}
}Redis Streams fuer Event-Driven Architektur
Redis Streams ermoeglicht den Aufbau eines Kafka-aehnlichen Nachrichtensystems auf Redis. Mit Consumer Groups koennen Nachrichten auf mehrere Verbraucher verteilt werden:
// Nachrichten mit Redis Streams veroeffentlichen
public async Task PublishOrderEventAsync(OrderEvent orderEvent)
{
var db = _redis.GetDatabase();
var entries = new NameValueEntry[]
{
new("type", orderEvent.Type),
new("orderId", orderEvent.OrderId.ToString()),
new("data", JsonSerializer.Serialize(orderEvent))
};
await db.StreamAddAsync("order-events", entries, maxLength: 10000);
}Redis-Ueberwachung und Leistungsanalyse
Monitoring mit redis-cli
In Produktionsumgebungen ist redis-cli ein leistungsstarkes Werkzeug zur Ueberwachung:
# Redis-Serverstatistiken
redis-cli INFO stats
# Speichernutzungsdetails
redis-cli INFO memory
# Langsame Abfragen protokollieren (langsamer als 10ms)
redis-cli CONFIG SET slowlog-log-slower-than 10000
redis-cli SLOWLOG GET 10
# Key-Anzahl und Groessenanalyse
redis-cli DBSIZE
redis-cli --bigkeysSpeicheroptimierung
- maxmemory-policy:
allkeys-lruist die haeufigste Wahl und loescht die am wenigsten genutzten Keys - Key-Ablaufzeit: Fuer jeden Key eine angemessene TTL festlegen
- Datenkompression: Grosse JSON-Werte mit LZ4 oder Gzip komprimieren
- Hash vs String: Fuer kleine Objekte mit wenigen Feldern ist die Hash-Datenstruktur speichereffizienter
- Key-Benennung: Kurze aber aussagekraeftige Key-Namen verwenden
Praktische Tipps
- Cache-Key-Design: Konsistente und aussagekraeftige Benennung verwenden
- TTL-Strategie: Angemessene Ablaufzeiten fuer jeden Datentyp definieren
- Monitoring: Leistung mit Redis INFO und RedisInsight ueberwachen
- Speicherverwaltung: maxmemory nicht ueber 70% des Server-RAMs setzen
- Serialisierung: System.Text.Json fuer schnelle Serialisierung verwenden
Redis kann die Leistung Ihrer Anwendung bei korrekter Verwendung vervielfachen. Der Schluessel liegt in der Wahl der richtigen Datenstruktur und Cache-Strategie fuer jedes Szenario.
Verwandte Artikel
Caching-Strategien in .NET: In-Memory, Distributed und Redis
Implementieren Sie effektive Caching-Strategien in .NET. In-Memory, Distributed und Redis.
.NET Performance-Optimierung: Profiling und Best Practices
Optimieren Sie die Performance von .NET-Anwendungen. Profiling, Memory Management und Async-Patterns.
Echtzeit-Anwendungen mit SignalR in .NET
Entwickeln Sie Echtzeit-Webanwendungen mit SignalR. Hub-Architektur, Gruppenverwaltung, Redis-Backplane und Skalierung.
Haben Sie ein Flutter-Projekt?
Ich entwickle hochleistungsfähige Flutter-Anwendungen für iOS, Android und Web.
Kontakt aufnehmen