凌晨 3 点 17 分,手机震动。
我迷迷糊糊摸过来一看,运维老张的名字在屏幕上闪烁。接起来,那头的声音比上海 12 月的天气还冷:"订单服务炸了,300 多笔订单卡着创建不了,你起来看看。"
我一边骂着脏话一边打开电脑,心里已经开始复盘:上周不是刚上线了用户服务的注册接口改版吗?
事情是这样的。我们团队做的是电商系统,微服务架构,用户服务、订单服务、商品服务三个模块互相调用。上线的是 v2.5 版本,新功能是给用户注册接口加上手机号验证。
测试的时候,QA 的哥们儿对着注册流程猛如虎地测了一整天——输入手机号、发送验证码、验证通过、完成注册。完美,上线!
结果上线两小时后,灾难开始。
用户反映:下单的时候提示"订单创建失败"。一开始零星几笔,我们以为是用户操作问题。等订单异常开始批量出现的时候,老张的夺命连环 call 就打过来了。
我翻开订单服务的日志,发现错误信息是"参数校验失败:缺少必填字段 phone_number"。
等等?我们只改了用户注册接口啊,订单服务怎么会有 phone_number 的校验?
顺着调用链路查下去,发现订单服务在用户下单时会调用一个内部接口来验证用户信息的完整性。这个接口是注册服务的另一个 API,之前没动过——理论上没动过。
实际上呢?我打开注册服务的代码,发现三天前同事小王为了"优化"注册接口,把返回数据结构改了。原来返回的是:
json
{
"user_id": "12345",
"username": "test_user",
"status": "active"
}
现在变成了:
json
{
"user_id": "12345",
"username": "test_user",
"status": "active",
"phone_number": "138****8888",
"phone_verified": true
}
问题来了:小王加了 phone_number 和 phone_verified 字段,把它设成了非 null,然后在注册服务内部做了个手机号必填的校验。但他不知道的是,订单服务调用的那个验证接口,返回结构变了之后,订单服务那边没更新解析逻辑,直接拿新字段去用了——然后就校验失败了。
为什么测试没发现?因为测试只覆盖了新的注册流程,没人去跑订单创建这个"旧功能"的回归测试。
凌晨 4 点 23 分,我回滚了注册服务的改动,系统恢复。
第二天写了 8 页事故报告,开了 3 小时的复盘会,第三天开始想:这种事,怎么才能不让它再发生?
这个问题我思考了很久,也和很多同行交流过。大家都有一个共同的痛:微服务架构下,接口变更就像拆盲盒,你永远不知道哪个下游会中招。
你们团队有没有这种情况:代码改了,接口文档懒得更新,或者压根儿就忘了更新?反正我们团队是有的。特别是那种"小改动"——加个字段嘛,又不影响现有逻辑,有什么好说的?
问题就出在这里。
你以为"不影响现有逻辑",但下游服务可能正在用旧的字段做着他们自己的校验。你加了新字段,改变了返回结构,下游解析的时候轻则数据错位,重则直接崩溃。
Postman、Swagger、Apifox……这些工具我们都用过。它们的共同问题是:只能记录你当前的接口状态,没法告诉你这次改了什么、会影响谁。
测试资源永远是紧张的。QA 的时间就那么多,优先保证新功能能用。回归测试?下次迭代不紧张的时候再说吧。
但微服务之间是网状结构,不是线性关系。你改 A 接口,可能影响 B、C、D 三个服务。你让 QA 怎么测?全链路跑一遍?一套环境不够,还得准备三套隔离环境,成本高到老板想砍人。
所以现实是:回归测试靠手动,靠开发人员"良心发现"去自测,靠上线后的祈祷。
我们团队鼎盛时期有 20 多个微服务。服务之间的调用关系错综复杂,一个新人来了,光是理清这些依赖就要两周。更别说知道改哪个接口会影响哪些下游了。
现有工具没有帮我们做这个:变更影响分析。
你改了一个接口,它应该通知所有依赖方,但实际上没有。你的下游服务可能是别的团队维护的,他们不知道你改了,他们没更新,他们的测试也没跑,然后线上就炸了。
这不是团队的问题,是工具链的问题。
我们做 ApiChain 的出发点很简单:让接口变更可追踪、可管理、可回归。
不是事后救火,是事前拦截。
ApiChain 的核心设计是「版本迭代」概念。每个迭代周期内,你可以独立维护这个迭代相关的接口文档和用例。比如 v2.5 版本的注册接口改版,你就在迭代里新建接口定义、写用例、做测试。
这个迭代是独立的,和项目主分支隔离。
当迭代测试通过、准备上线时,一键关闭迭代,ApiChain 会自动把这个迭代内的所有变更归并到项目主分支。归并的时候,它会检测:你新增了哪些接口、修改了哪些字段、哪些下游可能受影响。
这个「可能受影响」的检测,就是我们解决"改了新的,崩了旧的"的关键。
我们设计了两种用例层级:
迭代用例:针对当前迭代的变更接口设计的测试用例。比如 v2.5 的注册接口改版,就写注册接口的用例,验证新功能是否正常。
项目用例:覆盖整个项目所有接口的回归测试用例。跑项目用例,就是确保整个系统没有引入新的问题。
关键操作来了:一键导出迭代用例到项目用例。
你迭代内测完了,想做项目级回归?点击导出,ApiChain 会把当前迭代的用例合并到项目用例里。然后执行项目级回归测试——这下,旧功能有没有被影响,一跑便知。
不用手动去 Postman 里一个个导,不用担心遗漏,工具帮你搞定。
传统接口测试只验证接口返回了什么。但有时候,返回值对了,数据库里的数据却不对——比如事务没提交、缓存没更新、关联表没同步。
ApiChain 支持直连数据库执行 SQL 断言。你可以写这样的用例:
SELECT status FROM orders WHERE order_id = ?
这样不仅验证了接口返回"成功",还验证了数据库里真的写入了正确的数据。双重保险。
而且测试完成后,ApiChain 支持自动清理脏数据,不污染测试环境。
这是我们很引以为豪的一个功能。
当迭代内的接口发生变更时,ApiChain 会分析变更的影响范围。它会告诉你:这个接口被哪些用例引用了、这些用例关联哪些迭代、哪些服务依赖这个接口。
基于这个分析,你可以针对性地设计回归测试策略。不是全链路跑一遍,而是精准命中可能受影响的链路。省时间,省资源,关键是——不再靠运气。
好,回到文章开头那个故事。如果当时我们用了 ApiChain,这个 Bug 是怎么被提前拦截的呢?
第一步:迭代内维护变更
v2.5 迭代开始,产品经理说"注册接口要加手机号验证"。我们在 ApiChain 里创建 v2.5 迭代,新建注册接口 v2 的定义,把新的字段结构写进去:phone_number 和 phone_verified 标记为必填。
第二步:自动影响分析
保存接口变更时,ApiChain 提示:"检测到返回值结构发生变化,新增必填字段:phone_number、phone_verified"。同时,它扫描项目里所有引用这个接口的用例,发现订单服务的用户验证接口也用了这个返回结构。
第三步:导出迭代用例到项目
v2.5 迭代测试通过后,点击"导出到项目"。ApiChain 把注册接口的 v2 版本和用户验证接口的用例合并到一起。
第四步:执行项目级回归
运行项目级回归测试,用例执行到订单创建流程时,发现:用户验证接口的用例还在用旧的返回结构解析,没有解析新增的 phone_number 字段。测试失败,报错信息清清楚楚:字段解析异常。
第五步:修改后再上线
开发人员看到测试失败,意识到用户验证接口也需要同步更新。修改完成,重新跑用例,全部通过。
上线,安心睡觉。
这就是 ApiChain 的核心价值:不是帮你发现已经发生的 Bug,而是帮你在上线前发现潜在的风险。
做了 10 年开发,我最大的感悟是:技术债早晚要还的,问题只是以什么方式还。
有些债是代码写得烂,那是你自己的问题。有些债是工具链不完善,那是行业的问题。
"改了新的,崩了旧的"这个问题,本质上是微服务架构下接口变更管理缺失的问题。我们不能靠"让大家多沟通"来解决——人多了,沟通成本指数级上升,总有遗漏。
我们能靠的是工具:让变更可追踪、让影响可分析、让回归可执行。
ApiChain 就是我们给这个问题交的答卷。开源半年多,收获了很多反馈,有赞的也有拍砖的。我们一直在迭代,一直在改进。
如果你也被这个问题困扰,欢迎来试试。地址是 https://gitee.com/onlinetool/apichain
文档在 Wiki 里写得很详细,有问题可以提 Issue。
希望这个工具能帮你省下几个凌晨 3 点。真的,写代码已经够累了,别再让 Bug 偷走你的睡眠。
(全文完)