Кэширование в C#: Redis, Memcached и встроенные решения
Кэширование – один из ключевых инструментов оптимизации производительности в современных веб-приложениях. В экосистеме C# (.NET) разработчику доступны как встроенные механизмы (IMemoryCache, IDistributedCache), так и мощные внешние решения (Redis, Memcached). В этой статье мы разберем их особенности, сравним производительность и приведем практические примеры кода.
1. Встроенные решения .NET: IMemoryCache и IDistributedCache
ASP.NET Core предоставляет два основных интерфейса для работы с кэшем: IMemoryCache (локальный кэш в памяти одного процесса) и IDistributedCache (абстракция для распределенного кэша).
IMemoryCache
Идеален для монолитных приложений или микросервисов, где не требуется синхронизация между инстансами. Кэш хранится в оперативной памяти сервера.
// Регистрация в Program.cs
builder.Services.AddMemoryCache();
// Использование в сервисе
public class DataService
{
private readonly IMemoryCache _cache;
public DataService(IMemoryCache cache)
{
_cache = cache;
}
public async Task<string> GetExpensiveDataAsync(int id)
{
string cacheKey = $"data_{id}";
if (_cache.TryGetValue(cacheKey, out string cachedData))
{
return cachedData;
}
// Эмуляция тяжелой операции
await Task.Delay(500);
string data = $"Result for {id}";
var options = new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(10))
.SetSlidingExpiration(TimeSpan.FromMinutes(2));
_cache.Set(cacheKey, data, options);
return data;
}
}
IDistributedCache
Абстракция, позволяющая подключать различные бэкенды (Redis, SQL Server, NCache) без изменения кода приложения. Регистрируется через AddDistributedRedisCache или AddDistributedSqlServerCache.
// Пример с Redis
builder.Services.AddStackExchangeRedisCache(options =>
{
options.Configuration = "localhost:6379";
options.InstanceName = "SampleInstance";
});
// Использование
public class DistributedService
{
private readonly IDistributedCache _cache;
public DistributedService(IDistributedCache cache)
{
_cache = cache;
}
public async Task<string> GetDataAsync(string key)
{
var cached = await _cache.GetStringAsync(key);
if (cached != null) return cached;
var data = $"Computed at {DateTime.Now}";
await _cache.SetStringAsync(key, data, new DistributedCacheEntryOptions
{
AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(5)
});
return data;
}
}
2. Redis: мощный распределенный кэш для C#
Redis – это in-memory хранилище данных с поддержкой сложных структур (списки, множества, хэши). Для .NET используется клиент StackExchange.Redis или высокоуровневая обертка Microsoft.Extensions.Caching.StackExchangeRedis.
Преимущества Redis в C#:
- Скорость: субмиллисекундные задержки (в среднем 0.5-1 мс).
- Pub/Sub: можно оповещать другие сервисы об изменении кэша.
- Персистентность: данные могут сохраняться на диск (RDB/AOF).
- Кластеризация: горизонтальное масштабирование из коробки.
Пример продвинутого использования с сериализацией JSON:
using StackExchange.Redis;
using System.Text.Json;
public class RedisCacheService
{
private readonly IDatabase _db;
private readonly ConnectionMultiplexer _redis;
public RedisCacheService(string connectionString)
{
_redis = ConnectionMultiplexer.Connect(connectionString);
_db = _redis.GetDatabase();
}
public async Task<T> GetOrSetAsync<T>(string key, Func<Task<T>> factory, TimeSpan? expiry = null)
{
var value = await _db.StringGetAsync(key);
if (value.HasValue)
{
return JsonSerializer.Deserialize<T>(value);
}
var result = await factory();
var serialized = JsonSerializer.Serialize(result);
await _db.StringSetAsync(key, serialized, expiry ?? TimeSpan.FromMinutes(10));
return result;
}
public async Task InvalidateAsync(string key)
{
await _db.KeyDeleteAsync(key);
}
}
// Использование:
var cache = new RedisCacheService("localhost:6379");
var data = await cache.GetOrSetAsync("user:123", async () =>
{
return await _userRepository.GetUserByIdAsync(123);
});
3. Memcached: легковесная альтернатива
Memcached – более старая, но проверенная технология распределенного кэша. Для C# существует клиент EnyimMemcached (устаревший) и современный Memcached.ClientLibrary. Однако в экосистеме .NET Memcached используется реже Redis из-за отсутствия встроенной поддержки в ASP.NET Core.
Сравнение Redis vs Memcached для C#:
| Характеристика | Redis | Memcached |
|---|---|---|
| Типы данных | Строки, списки, множества, хэши, битмапы | Только строки (ключ-значение) |
| Максимальный размер значения | 512 МБ | 1 МБ |
| Персистентность | Да (RDB/AOF) | Нет |
| Pub/Sub | Да | Нет |
| Производительность (чтение) | ~100,000 ops/sec (один узел) | ~50,000 ops/sec |
| Интеграция с .NET | Отличная (Microsoft.Extensions.Caching.StackExchangeRedis) | Слабая (нет официального пакета от Microsoft) |
Пример подключения Memcached в .NET (через NuGet пакет EnyimMemcachedCore):
Блоги
Рекомендаций по книгам
Читайте также
Продвинутый мониторинг TypeScript приложений: метрики и алерты
Контекст в Jetpack Compose: Полный гайд с примерами кода
Группировка по нескольким колонкам в LINQ: примеры и best practices
Очереди и фоновые задачи на Go: горутины, каналы и продвинутые паттерны
Лучшие IDE и инструменты для продвинутой Rust разработки