Fortgeschrittenes Caching in C#: Redis, Memcached und integrierte Lösungen

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Einleitung: Warum fortgeschrittenes Caching alles verändert

\n

In der modernen hochbelasteten Architektur sind Antwortgeschwindigkeit und Reduzierung der Datenbanklast zentrale Aufgaben. Caching in C# (.NET) ist nicht mehr nur das einfache Merken eines Ergebnisses: Es ist ein komplexes System zur Verwaltung von Zustand, Lebensdauer und Datenkonsistenz. Auf fortgeschrittenem Niveau muss der Entwickler je nach Szenario zwischen Redis, Memcached und integrierten Lösungen wählen.

\n

In diesem Artikel analysieren wir drei grundlegende Ansätze zum Caching im .NET-Ökosystem, vergleichen ihre Leistung, Implementierungskomplexität und typische Fehler. Sie erfahren, wie Sie einen verteilten Cache mit Redis einrichten, Memcached für hohe Lasten optimieren und wann der integrierte IMemoryCache die beste Lösung ist.

\n\n

Integriertes Caching in .NET: IMemoryCache und IDistributedCache

\n

IMemoryCache – schneller lokaler Cache

\n

Der integrierte Cache IMemoryCache aus dem Namespace Microsoft.Extensions.Caching.Memory ist die ideale Lösung für eine einzelne Anwendungsinstanz. Er speichert Daten im Arbeitsspeicher des Prozesses und gewährleistet so minimale Latenz.

\n
// Registrierung in Startup.cs oder Program.cs\nbuilder.Services.AddMemoryCache();\n\n// Verwendung in einem Service\npublic class ProductService\n{\n    private readonly IMemoryCache _cache;\n\n    public ProductService(IMemoryCache cache)\n    {\n        _cache = cache;\n    }\n\n    public async Task<Product> GetProductAsync(int id)\n    {\n        string cacheKey = $"product_{id}";\n        if (!_cache.TryGetValue(cacheKey, out Product product))\n        {\n            product = await _repository.GetProductByIdAsync(id);\n            var cacheEntryOptions = new MemoryCacheEntryOptions()\n                .SetAbsoluteExpiration(TimeSpan.FromMinutes(5))\n                .SetSlidingExpiration(TimeSpan.FromMinutes(1))\n                .SetPriority(CacheItemPriority.High);\n\n            _cache.Set(cacheKey, product, cacheEntryOptions);\n        }\n        return product;\n    }\n}\n
\n

Vorteile: Keine Netzwerklatenz, einfache Konfiguration, Unterstützung für gleitendes und absolutes Ablaufen.

\n

Nachteile: Funktioniert nicht bei Skalierung auf mehrere Server; begrenzt durch den RAM des Prozesses.

\n\n

IDistributedCache – Abstraktion für verteilte Caches

\n

Das Interface IDistributedCache ermöglicht einen einfachen Wechsel zwischen Redis, SQL Server oder NCache ohne Änderung der Geschäftslogik. Die Standardimplementierung ist MemoryDistributedCache (lokal), aber für die Produktion wird in der Regel Redis gewählt.

\n
// Registrierung der Redis-Implementierung\nbuilder.Services.AddStackExchangeRedisCache(options =>\n{\n    options.Configuration = "localhost:6379";\n    options.InstanceName = "SampleInstance";\n});\n\n// Verwendung\npublic async Task SetCacheAsync(string key, byte[] data)\n{\n    var cache = context.RequestServices.GetRequiredService<IDistributedCache>();\n    await cache.SetAsync(key, data, new DistributedCacheEntryOptions\n    {\n        AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)\n    });\n}\n
\n

Der entscheidende Vorteil ist die Vereinheitlichung: Sie schreiben den Code einmal, und der Cache-Anbieter wird über die Konfiguration geändert.

\n\n

Redis in C#: Fortgeschrittene Techniken und Muster

\n

Verbindung und Verbindungspool

\n

Für die Arbeit mit Redis in .NET wird die Bibliothek StackExchange.Redis verwendet. Anstatt jedes Mal eine neue Verbindung zu erstellen, nutzen Sie Multiplexing – eine Verbindung für die gesamte Anwendung.

\n
// Globaler Singleton\npublic static ConnectionMultiplexer redis = ConnectionMultiplexer.Connect("localhost:6379,abortConnect=false");\n\n// Datenbank abrufen\nIDatabase db = redis.GetDatabase(0);\n\n// Basisoperationen\nawait db.StringSetAsync("user:1", "John Doe", TimeSpan.FromMinutes(30));\nstring name = await db.StringGetAsync("user:1");\n
\n

Blogs

Buchempfehlungen