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

.NET Core 8中IMemoryCache处理OTP的缓存问题排查求助

.NET Core 8中IMemoryCache处理OTP的问题排查与优化建议

问题描述

我们在基于.NET Core 8的应用中使用IMemoryCache处理OTP时遇到问题,具体出现在resetPasswordHandle和CheckPasswordOtpHandle操作的OTP验证环节。

问题详情

存OTP逻辑(resetPasswordHandle)

public async Task<AccountResponseBase> Handle(ForgetPasswordRequest req)
{
    // 其他业务代码
    var codeCacheKey = $"{CacheConsts.FORGOT_PASS_CACHE_KEY_PREFIX}:{req.email}";
    _cache.Set(codeCacheKey, code, TimeSpan.FromMinutes(10));
}

验证OTP逻辑(CheckPasswordOtpHandle)

public async Task<PzJwtResponse> Handle(ForgetPasswordOtpRequest req)
{
    // 其他业务代码
    var cacheKey = $"{CacheConsts.FORGOT_PASS_CACHE_KEY_PREFIX}:{user.Email}";
    if (!_cache.TryGetValue(cacheKey, out string cachedCode))
    {
        return Failure(AccountFailureStatusTypes.CodeNotFoundOrExpired);
    }
}

现象

偶尔会出现持续返回CodeNotFoundOrExpired错误的情况,即使OTP已正确存入缓存,该问题需重置IIS后才能恢复正常。


问题排查与优化建议

1. 缓存未被正确获取/提前过期且需重置IIS恢复的可能原因

  • 进程回收导致缓存丢失:IIS应用池会因内存过高、空闲超时、定期回收等触发进程重启,IMemoryCache是进程内缓存,进程重启后所有缓存数据会被清空,此时OTP无法被获取;重置IIS本质是重启应用进程,重新初始化缓存,因此恢复正常。
  • 缓存键不一致:检查req.email与user.Email的格式、大小写是否完全一致(比如邮箱是否带空格、大小写差异),键不匹配会直接导致无法找到缓存项。
  • 内存压力触发缓存驱逐:当服务器内存不足时,IMemoryCache会自动驱逐优先级较低的缓存项(默认优先级为Normal),即使未到过期时间,OTP也可能被提前清理。
  • 缓存实例注入错误:若IMemoryCache未注册为单例(错误注册为Scoped或Transient),不同请求会使用独立的缓存实例,存入的OTP无法在其他实例中被获取。

2. 提升缓存稳定性的建议

  • 优先切换到分布式缓存(如Redis):IMemoryCache仅适用于单实例部署场景,若应用是多实例(负载均衡)或需要跨进程共享缓存,必须使用分布式缓存。Redis支持过期时间配置、数据持久化,能彻底避免进程重启导致的缓存丢失问题,同时多实例应用可共享OTP缓存,验证逻辑更可靠。
  • 统一缓存键生成规则:对邮箱做标准化处理(转小写、去除首尾空格),确保存、取缓存的键完全一致,示例代码:
    var normalizedEmail = req.email.Trim().ToLowerInvariant();
    var codeCacheKey = $"{CacheConsts.FORGOT_PASS_CACHE_KEY_PREFIX}:{normalizedEmail}";
    
  • 设置缓存项高优先级:给OTP这类关键缓存项设置高优先级,降低被内存压力驱逐的概率:
    _cache.Set(codeCacheKey, code, new MemoryCacheEntryOptions
    {
        AbsoluteExpirationRelativeToNow = TimeSpan.FromMinutes(10),
        Priority = CacheItemPriority.High
    });
    
  • 添加缓存操作日志:在存、取缓存的位置添加日志,记录缓存键、操作结果、过期时间,便于问题发生时快速定位是存失败还是取失败。

3. .NET Core 8中影响IMemoryCache生产环境行为的特定配置

  • 缓存大小限制:通过MemoryCacheOptions.SizeLimit设置缓存的最大容量(需配合缓存项的Size属性生效),避免缓存无限制占用内存。配置示例:
    builder.Services.AddMemoryCache(options =>
    {
        options.SizeLimit = 1024 * 1024; // 自定义容量,单位需与缓存项Size匹配
    });
    
  • 缓存项压缩:.NET Core 8新增MemoryCacheOptions.Compress配置,开启后会对超过阈值的缓存项进行压缩,节省内存空间:
    builder.Services.AddMemoryCache(options =>
    {
        options.Compress = true;
        options.CompressionThreshold = 1024; // 超过1KB的缓存项才会被压缩
    });
    
  • 过期项扫描频率:通过MemoryCacheOptions.ExpirationScanFrequency调整过期项的扫描间隔(默认1分钟),间隔过长会导致过期项延迟清理,但不会影响已过期项的获取(获取时会实时检查过期时间)。
  • 缓存统计追踪:开启MemoryCacheOptions.TrackStatistics可以收集缓存命中、驱逐等统计数据,便于监控缓存状态,但会带来一定性能开销,按需开启。

内容的提问来源于stack exchange,提问作者Vladimir Potapov

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 20:42:15