You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core中IMemoryCache定时刷新与闲置缓存清理方案咨询

Hey Dave, 刚好我之前处理过类似的缓存刷新需求,针对你用IMemoryCache缓存Web API数据、需要每小时精准失效的场景,给你几个靠谱的解决方案:

方案1:绝对过期+主动预刷新(兼顾性能和实时性)

滑动过期的问题确实如你所说——如果用户持续访问,缓存会一直续命,导致拿到 stale 数据。所以首先要用绝对过期时间替代滑动过期,确保缓存最多存活1小时。同时为了避免用户请求刚好碰到缓存过期时的延迟,可以在缓存快要失效时主动异步刷新。

示例代码:

public async Task<ApiResponse> GetCachedApiDataAsync(IMemoryCache cache)
{
    const string cacheKey = "HourlyApiData";
    
    // 尝试读取缓存
    if (cache.TryGetValue(cacheKey, out ApiResponse cachedData))
    {
        // 检查缓存剩余有效期,小于5分钟则后台异步刷新
        var cacheEntry = cache.GetCacheEntry(cacheKey);
        var timeLeft = cacheEntry.AbsoluteExpiration.Value - DateTimeOffset.UtcNow;
        if (timeLeft.TotalMinutes < 5)
        {
            // 用_ = 避免阻塞当前请求
            _ = RefreshCacheAsync(cache);
        }
        return cachedData;
    }
    
    // 缓存不存在时,直接获取新数据并设置1小时绝对过期
    var freshData = await FetchDataFromSourceAsync();
    cache.Set(cacheKey, freshData, new MemoryCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
    });
    return freshData;
}

private async Task RefreshCacheAsync(IMemoryCache cache)
{
    const string cacheKey = "HourlyApiData";
    var freshData = await FetchDataFromSourceAsync();
    cache.Set(cacheKey, freshData, new MemoryCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
    });
}
方案2:后台定时任务强制刷新(精准控制过期时间)

如果需要完全确保到点就更新缓存,不管有没有用户访问,可以用.NET的BackgroundService写一个定时任务,每小时主动刷新缓存。这种方式最直接,能彻底避免 stale 数据。

示例代码:

// 定时刷新缓存的后台服务
public class HourlyCacheRefreshService : BackgroundService
{
    private readonly IMemoryCache _cache;
    private readonly IServiceScopeFactory _scopeFactory;
    private readonly TimeSpan _refreshInterval = TimeSpan.FromHours(1);

    public HourlyCacheRefreshService(IMemoryCache cache, IServiceScopeFactory scopeFactory)
    {
        _cache = cache;
        _scopeFactory = scopeFactory;
    }

    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        // 启动时先刷新一次,避免初始缓存为空
        await RefreshCache();
        
        while (!stoppingToken.IsCancellationRequested)
        {
            await Task.Delay(_refreshInterval, stoppingToken);
            await RefreshCache();
        }
    }

    private async Task RefreshCache()
    {
        // 创建作用域获取API服务(避免长生命周期服务注入问题)
        using var scope = _scopeFactory.CreateScope();
        var apiService = scope.ServiceProvider.GetRequiredService<IApiDataService>();
        
        var freshData = await apiService.FetchDataFromSourceAsync();
        _cache.Set("HourlyApiData", freshData, new MemoryCacheEntryOptions
        {
            AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1)
        });
    }
}

然后在Program.cs里注册这个后台服务:

builder.Services.AddHostedService<HourlyCacheRefreshService>();
方案3:自定义缓存项监控与手动失效(高度可控)

如果需要更灵活的缓存监控(比如记录所有缓存项的过期时间、手动触发失效),可以维护一个缓存元数据字典,定时扫描并移除过期的缓存项。这种方式适合需要精细化管理缓存的场景。

示例代码:

// 用于记录缓存项的过期时间
private readonly ConcurrentDictionary<string, DateTimeOffset> _cacheExpiryTracker = new();

public void SetTrackedCache(IMemoryCache cache, string key, object value, TimeSpan absoluteExpiration)
{
    var expiryTime = DateTimeOffset.UtcNow.Add(absoluteExpiration);
    cache.Set(key, value, new MemoryCacheEntryOptions
    {
        AbsoluteExpiration = expiryTime
    });
    _cacheExpiryTracker.TryAdd(key, expiryTime);
}

// 定时扫描并清理过期缓存的方法
public async Task ScanAndCleanExpiredCache(IMemoryCache cache, CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken); // 每5分钟扫描一次
        var now = DateTimeOffset.UtcNow;
        
        // 找出所有过期的缓存键
        var expiredKeys = _cacheExpiryTracker
            .Where(kv => kv.Value <= now)
            .Select(kv => kv.Key)
            .ToList();
        
        foreach (var key in expiredKeys)
        {
            cache.Remove(key);
            _cacheExpiryTracker.TryRemove(key, out _);
        }
    }
}

最后总结

  • 优先推荐方案1+方案2结合:绝对过期保证缓存不会无限续命,后台定时任务确保到点必更,主动预刷新提升用户体验。
  • 滑动过期完全不适合你这种有固定更新周期的场景,一定要避免使用。

内容的提问来源于stack exchange,提问作者Dave Morrison

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 17:07:34