花拾录
← 返回知识库

验证码存进远程缓存,一次网络抖动就让整条登录链路失败

后端开发导入2026/09/220 阅读0 评论

登录接口本来好好的,可一到网络不稳的时候就开始抽风:明明验证码是对的,用户却收到"验证码错误"或"系统繁忙";刷新一下又能用,再刷新又不行。查日志发现,报错的位置根本不是验证码校验逻辑,而是它"够不到"存验证码的地方。

现象

验证码接口在高峰期或网络抖动时频繁报超时,随后整条登录链路失败。日志里能看到类似:

RedisConnectionFailureException: Unable to connect to Redis
  ... connect timed out

用户侧的表现是:输对了验证码,点登录却没有反应,或提示"验证码已过期/错误"。开发者第一反应往往是"验证码逻辑是不是写错了""是不是并发问题",但真正的问题在验证码存在了哪里。

根因

根因是架构耦合:业务把验证码这种短生命周期、单机使用、丢失也无所谓的状态,放进了远程缓存(比如 Redis)。

验证码的读写路径被设计成了这样:

  1. 用户请求验证码 → 服务端生成一个 6 位随机数 → SET captcha:<手机号> <code> EX 300 写进远程缓存;
  2. 用户提交登录 → 服务端 GET captcha:<手机号> 读出来比对。

这条链路上,远程缓存成了一个单点:只要应用与缓存之间的网络抖一下、缓存的连接超时一下,GET 拿不到值,校验就直接判失败。于是"缓存不可用"被放大成了"登录不可用"。

更深一层的问题是:验证码根本不需要被共享。 它只在一次"请求验证码—提交登录"的交互中被同一个用户读一次,是天然的本地、短命状态。把它放到远程缓存里,你付出了网络往返的代价,换来的是一个并不需要的"跨实例共享"能力,同时引入了一个不必要的故障域。

判断一份状态该放哪,关键问一句:它真的需要被多个实例共享吗?

  • 需要跨实例共享、且丢失代价高(比如用户会话、分布式锁)→ 放远程缓存,并接受它的网络成本。
  • 只在单次交互内有效、丢了重来即可(验证码、临时 token、限流计数)→ 优先放本地内存。

解决

在开发/单机阶段,把验证码从远程缓存改到本地内存,直接去掉这一环的远程依赖。用一个带过期清理的线程安全容器即可:

// 简易本地验证码存储:key -> (code, 过期时间)
private final ConcurrentHashMap<String, Entry> store = new ConcurrentHashMap<>();

record Entry(String code, long expireAt) {}

public void put(String phone, String code, long ttlMillis) {
    store.put(phone, new Entry(code, System.currentTimeMillis() + ttlMillis));
}

public boolean verify(String phone, String code) {
    Entry e = store.get(phone);
    if (e == null) return false;
    if (System.currentTimeMillis() > e.expireAt()) {
        store.remove(phone);
        return false;
    }
    return code.equals(e.code);
}

配套两点:

  • 过期清理。ConcurrentHashMap 不会自动过期,要么在 verify 时顺手清过期项,要么用一个定时任务周期扫描,避免内存无限增长。
  • 确认部署形态。单机部署时本地内存完全够用;如果确实多实例部署,需要用户被路由到同一实例(会话粘滞),或者退一步——即使校验失败也返回友好提示、允许重发,而不是直接判定登录失败。

改造后,登录链路少了"网络能不能通缓存"这个前提,抖动的传导路径被切断。

延伸与预防

这条坑的普适教训是:上线远程依赖之前,先问"这一环真的需要共享吗"。

不是所有状态都值得放远程缓存。把本地就能解决的事推给一个跨网络的服务,等于给每一次请求都绑上一个新的失败点。反过来,也要避免走极端——如果状态确实需要多实例一致(比如"同一账号只能在一处登录"),那就该放远程,并接受它的可用性成本,同时给它加降级策略(缓存不可用时走什么兜底路径)。

排查思路上还有一条:当"某个功能失败"的报错指向依赖服务时,先分清那部分是"业务必需"还是"架构强加"。 很多故障不是逻辑写错了,而是把不该耦合的东西耦合在了一起。

评论(0)

  • 还没有评论,来抢沙发~

相关文章