上个月凌晨两点被运维电话喊起来的时候,我正抱着猫补觉。
是电商大促的全链路压测,订单服务调用户中心的接口直接报500。查了半小时才发现,上周刚发的用户信息接口,后端偷偷把返回值里的user_id从Long改成了String,前端和订单服务都还在按数字解析,直接栈溢出。
真的。
之前总觉得接口版本兼容是架构师要抠的高大上命题,真踩了生产事故才明白,90%的问题根本不是技术不够复杂,是最基础的规则没落地。
你以为的兼容,其实是甩锅
很多团队现在的兼容规则说起来挺好笑的:改接口的时候在飞书文档里标个“不兼容更新”,@一下所有下游对接人,就算完事。
这哪是兼容,这是甩锅。
上次有个后端同事改用户基础信息接口,把nickname字段从必填改成了选填,就只在共享文档里提了一句,根本没做任何接口层面的兜底。结果大促当天,一大批早年注册的老用户没填过昵称,订单服务拿不到nickname的值,直接把近两万笔订单标记成异常,差点赔出去几十万优惠券。
真正的兼容从来不是靠文档同步,而是靠接口本身的设计逻辑兜底。
文档会漏看,人会忘事,跨团队沟通永远有信息差,只有接口本身不随便删字段、不改原有字段的类型,才是真的把兼容做在了前面。

别一上来就搞复杂的版本路由
说到版本兼容,很多人第一反应就是在URL里加/v2、/v3,或者在请求Header里塞X-API-Version,让网关做路由转发。
能理解。
但真的没必要上来就搞这套。
去年去一家做本地生活的互联网公司交流,他们用户中心的接口在网关里挂了7个版本,从v1到v7,还有三个没标版本号的历史遗留接口。当初写这些接口的开发要么离职了,要么转岗做了产品,没人敢动这些路由规则,就这么一直挂着。新的业务需求要对接,还要先翻三天历史文档,搞清楚该调哪个版本,效率低到离谱。
非必要不要新增独立的版本路由。
能通过新增字段兼容的,绝对不要开新的接口版本。比如你要把user_id从Long改成String,那就直接在返回值里加个user_id_str字段,旧的user_id字段继续返回Long类型,下游服务要迁移的自己慢慢切,等过个三五个月,监控里看到没有服务再调旧字段了,再把旧字段删掉就行。
这种做法的成本比搞一套全链路版本路由低太多了,而且不会留下一堆没人敢碰的历史包袱。

落地的时候别忽略这些没人说的细节

规则说起来简单,真落地的时候全是坑。
比如很多团队定了“不随便改旧字段”的规则,但没人校验。开发改了旧字段的类型,代码评审的时候没人注意,直接合并上线,出了问题才追悔莫及。
说实话,我现在跟团队提的第一个要求就是,接口变更的校验必须左移到CI阶段。只要代码里动了已有接口的入参出参类型,或者删了原有字段,CI流水线直接给你打回,不让合并,除非你加了对应的兼容字段。
还有个很容易漏的细节:别等出问题了才知道哪个下游还在调你的旧接口。我们现在在服务注册中心里加了个小逻辑,每个服务调接口的时候,都会把自己依赖的字段信息上报上去。用户中心发新版本的时候,直接扫一遍上报的依赖数据,看到哪个服务还在用旧的字段,直接给对应的负责人发告警,提前催着迁移,比等生产告警响了再处理强一百倍。
哦对,还有个小技巧:别靠人手动同步接口变更信息。我们现在写了个小脚本,只要接口文档有更新,自动把变更内容推到对应的下游对接群里,省得有人忘发。
上次那个凌晨的事故之后,我们团队定了个死规矩。
任何接口变更,只要是会影响下游解析的,必须先加兼容字段,等所有下游迁移完成,才能删除旧字段。
这大半年压测,再也没出过这种因为接口不兼容导致的幺蛾子。