ASP.NET Core › Caching

What is the 'cache stampede' (thundering herd) problem, and how would you mitigate it in an ASP.NET Core application?

Advanced

Answer

A cache stampede occurs when a popular cache entry expires and many concurrent requests simultaneously experience a cache miss, all racing to recompute and repopulate the same expensive value at once, overwhelming the backing data source -- mitigated via a per-key lock/semaphore ensuring only one request recomputes while others wait, or by using IMemoryCache.GetOrCreateAsync's built-in per-key coordination, or the newer HybridCache API which provides built-in stampede protection out of the box.
private static readonly SemaphoreSlim _lock = new(1, 1);

public async Task<Product> GetProductAsync(int id) {
    if (_cache.TryGetValue($"product-{id}", out Product cached)) return cached;
    await _lock.WaitAsync();
    try {
        if (_cache.TryGetValue($"product-{id}", out cached)) return cached;
        var product = await _repository.GetByIdAsync(id);
        _cache.Set($"product-{id}", product, TimeSpan.FromMinutes(10));
        return product;
    } finally { _lock.Release(); }
}
Real-world example A viral news article's cache entry expiring under heavy simultaneous traffic previously caused 500 concurrent database queries for the same article; adding per-key locking reduces this to exactly one database query while other requests briefly wait for the now-cached result.

Common follow-ups: How does HybridCache handle this automatically without manual locking code?;What is 'stale-while-revalidate' as an alternative mitigation approach?