Ответ
Да, активно использовал кеширование для повышения производительности и снижения нагрузки на источники данных (БД, внешние API).
Основные подходы в .NET:
-
IMemoryCache(In-Memory Cache):- Для чего: Кеширование в памяти одного экземпляра приложения. Быстро, но не распределенное.
-
Пример:
public class ProductService { private readonly IMemoryCache _cache; private const string CacheKey = "TopProducts"; public ProductService(IMemoryCache cache) => _cache = cache; public async Task<List<Product>> GetTopProductsAsync() { if (!_cache.TryGetValue(CacheKey, out List<Product> products)) { products = await _database.FetchTopProductsAsync(); // Дорогой запрос var options = new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromMinutes(5)) // "Сдвигается" при каждом обращении .SetAbsoluteExpiration(TimeSpan.FromHours(1)); // Максимальное время жизни _cache.Set(CacheKey, products, options); } return products; } }
-
IDistributedCache(Распределенный кеш):- Для чего: Когда несколько экземпляров приложения должны разделять общий кеш (веб-ферма, микросервисы).
- Поставщики: Redis (наиболее популярен), SQL Server, NCache.
- Пример (с Redis):
// В Startup/Program.cs services.AddStackExchangeRedisCache(options => { options.Configuration = "localhost:6379"; });
// В сервисе var cachedData = await _distributedCache.GetStringAsync("myKey"); if (cachedData == null) { cachedData = JsonSerializer.Serialize(freshData); await _distributedCache.SetStringAsync("myKey", cachedData, new DistributedCacheEntryOptions { AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10) }); }
Критические аспекты при работе с кешем:
- Инвалидация: Четкая стратегия обновления/удаления данных при их изменении.
- Сериализация: Для
IDistributedCacheданные должны быть сериализуемы. - Просадки (Cache Stampede): Использование
Lazyили семантикиGetOrAddдля предотвращения одновременного обновления кеша множеством потоков. - Уровни кеширования: Комбинация in-memory (L1) и распределенного (L2) кеша.