AI 写完的系统,挂在了 Redis 集群上
一句话核心: AI 能把每个零件做对;但它不知道你的数据要经过几条链路。而系统出问题,往往就出在这几条链路的接缝处。
一、上线之后,系统挂了
这次上线,我原以为会是最顺利的一次。
需求问得很清楚;技术方案是 AI 给的;代码也是 AI 写的;流程文档一份不少;测试也通过了。
然后,这个系统挂在了 Redis Cluster(Redis 集群)上。
那一刻我才明白:AI 能写出「单机能跑通」的代码,但它不知道我们的 Redis 是集群部署的。
后面我会讲到,AI 在这个项目里一共漏掉了三个场景。有意思的是,这三个场景看起来毫不相关,但它们的成因,是同一个。
二、先交代背景:这个需求在做什么
先把背景讲清楚,否则后面的坑不好理解。
这是一个运营管理系统,要新增一块「能力服务」的调用处理。三个关键概念:
- 能力服务:可以理解成对外提供的一种调用能力。
- 上游厂商:这种能力背后由多家厂商提供,我们记为 A、B、C。它们提供的是同一种能力,只是来源不同。
- 本次需求 :不再像以前那样固定只用一家,而是按比例或按额度自动分流------比如 30% 的请求走 A;或者 A 的额度用满之后,自动切换到 B。
三、这个需求里,最难的不是方案
拿到需求文档后,我没有急着想技术方案,而是先把四件事跟产品同事问死:
- 页面怎么配置?
- 配置是立即生效,还是次日生效?
- 配置的调整记录要展示哪些信息?
- 能力服务的计算规则到底是什么?
这四问听起来很基础,但它们才是这个需求真正的难点。
原因在于:AI 能回答「怎么做」,但回答不了「我们到底要什么」。 它不知道我们业务里那些从来没被写进文档的隐藏约定------运营改了配置,线上正在跑的流量要不要立刻切换?调整记录是给运营看的,还是给审计看的?
这些问题,AI 一个都替不了你问。
这里要记住一句话:「顺利」是最好的麻醉剂。 这次需求问得太顺、方案定得太顺,反而让我在后面放松了警惕。
四、AI 的正确用法:它铺开选项,我保留决策
需求理清之后,我做了一件现在觉得挺对的事。
我把需求文档和相关业务信息整理好,一起交给 AI,让它给出实现方案;然后我在它给的多个方案里,选出当前最优的那个。
这里的关键是:我没有让 AI 替我决策,我只是让它把可能性铺开。 决策权在我手里,因为只有我知道我们真实的约束。
接着,我把整个实现拆成了三样东西:实现文档、计划清单、设计文档。
现在回头看,恰恰是这套流程的严谨,救了这次开发------设计阶段和主体实现都很顺利,问题只出在下面这三个地方。
五、AI 漏掉的三个场景
场景 1:Redis Lua 脚本没考虑集群
我们用了一段 Redis Lua 脚本(一段在 Redis 内部原子执行的小脚本)来做分流判断:判断当前已经调用的比例、或者剩余额度,从而决定这次请求该走上游 A、B 还是 C。
这段脚本需要在 Redis 里同时读写好几个 key(比如「比例计数」和「额度计数」)。
在单机 Redis上,它工作得很好。
但我们的 Redis 是 Cluster(集群) 。集群会把数据分片到不同的 slot(槽位) 上,规则是:一段 Lua 脚本里操作的多个 key,必须落在同一个 slot;否则 Redis 会直接报 CROSSSLOT 错误。
AI 写出的是一个「单机 Redis 假设」下完全正确的脚本。它不知道、也不会主动来问我们:你们的 Redis 是集群的吗?
场景 2:新字段只进了数据库,没进缓存
这次需求新增了一个字段。而这个系统有一个历史做法:相关信息除了存进数据库,还会在 Redis 里存一份做缓存。
新版实现完之后,这个新字段同步进数据库了,但刷新缓存的时候没有带上它。
这里有一个更隐蔽的地方:这个系统有两处 刷新缓存的逻辑------应用启动时刷一次,定时器再周期性地刷一次。这两处,都没有带上新字段。
结果就是:一部分读取路径拿到的是缓存里的旧结构对象,而那个对象里根本没有这个新字段。
场景 3:缓存里的「配置标识」没跟着更新
我们缓存了一份「能力服务具体调用哪个服务」的信息。
- 改造前:只能配一个上游,所以缓存结构很简单。
- 改造后 :要按比例/额度自动筛选上游,就必须多存一个配置标识;后续靠这个标识,去找到对应的分流规则。
问题是:缓存这块的数据结构没有跟着改到位------缓存里存的还是旧的东西。于是,程序靠配置标识去找规则时,找不到。
六、这三个坑,其实是同一个坑
你有没有发现:这三件事表面上毫不相干------一个是 Lua 脚本、一个是缓存、一个是数据结构。
但它们的成因是同一个:
它们都不是「代码写得对不对」的问题,而是「数据在系统里怎么流转」的问题。
- 那个新字段,要从数据库流到缓存、从启动逻辑流到定时器,中间经过好几条链路。
- 那段 Lua 脚本,在单机世界和集群世界,遵循的是两套完全不同的规则。
- 那个配置标识,从「一个上游」变成「多个上游」,意味着所有读它的地方都得一起改。
AI 看到的是「一个点」:这段代码写得对不对。 系统出问题的,却是「一条链」:这份数据要经过几个地方,我改了一处,剩下几处要不要一起改?
所以,AI 擅长把每个零件做对;但它不会替你想这些零件怎么连起来------因为它不知道你的数据流经几条链路。
七、更值得警惕的地方,不在技术上
复盘时,我找到了真正的问题。
在我已经掌握 的那部分需求上,我给出了自己认可的方案。但在那些细枝末节上------缓存、数据同步、脚本边界------我太信任 AI 了。
而危险恰恰在这里:AI 给的方案太顺了,顺到我不愿意再去怀疑它。
顺利不是好兆头。顺利是警报。
八、AI 时代,该守住什么
想清楚之后,我给自己定了一条分工:
用 AI 拓展「想什么」,用我自己守住「漏什么」。
- AI 负责广度:快速给出一个看起来完整的方案,把可能性铺开。
- 我负责边界:集群、并发、时序、缓存一致性------这些只有在真实运行环境里才会暴露的东西。
九、总结
把这次经历压缩成三条结论:
结论一:AI 负责广度,你负责边界。 AI 的长处,是快速铺开一个看起来完整的方案;你的价值,是判断这个方案在真实环境里站不站得住。
结论二:改动一份数据之前,先画出它流经的所有链路。 三个坑里有两个(新字段、配置标识),本质都是「改了数据库,漏了缓存和刷新逻辑」。所以每次改动数据,先问自己一句:这份数据会经过哪几个地方?
结论三:越顺利,越要停下来查一遍边界。 顺利是麻醉剂。方案太顺的时候,恰恰是你最容易漏掉「细枝末节」的时候。
一份可复用的「边界自查清单」
AI 生成的代码,上线前建议逐条过一遍:
- 数据一致性:新增/修改的字段,数据库、缓存、以及所有刷新链路(启动时、定时器)是否都覆盖了?
- 部署形态:代码里有没有隐含的「单机假设」?Redis 是集群吗?数据库分库分表了吗?服务是多实例吗?
- 时序:启动时、定时器执行时、并发请求时,逻辑还成立吗?
- 边界条件:空值、超时、跨 slot、并发竞争,都考虑了吗?
- 幂等与恢复:失败重试、服务重启之后,状态还正确吗?
在 AI 能写完大部分代码之后,后端工程师的价值,正好从 AI 看不见的地方长出来。
AI 看不见集群。 AI 看不见时序。 AI 看不见你的数据流转过几条链路。
而你看得见。