一次大规模重构上线后出现故障,回滚前后造成服务约 7 小时不可用。与此同时,团队开发的功能也经常在测试阶段暴露问题,或与需求理解不一致。这两件事让我开始重新看待小团队的效率:开发阶段节省的时间,可能会在联调、上线和返工时成倍付出。
架构变化要能分步验证
这次改动同时包含 IOC 容器迁移、业务模块拆分和服务远程化。原先两个 Web 项目变为三个消费者项目和四个提供者项目,还增加了 ZooKeeper、Redis 等依赖。团队需要理解的运行条件和故障路径明显变多。
我们怀疑系统存在性能瓶颈,但缺少足够的测量,不能把“拆成微服务”直接等同于“解决性能问题”。容器迁移与服务拆分也不是必须同时完成的事情:当时采用 Spring 是我们的集成选择,不能由此得出其他容器无法接入 Dubbo 的结论。
更容易控制的做法,是将改动拆成可独立验收的阶段。例如先整理模块边界,再选择确有独立扩展需求的业务远程化。每个阶段都要能回答:解决什么问题、用什么指标验证、失败后怎样退回。阶段顺序应服从项目约束,不必机械照搬某一种拆分路线。
依赖链路必须完整走通
上线后暴露出一条消息链路只有生产端、缺少消费端的问题,消息积压并伴随系统无响应。队列是否阻塞生产、何时拒绝写入,与具体实现和容量策略有关,不能把这个现象概括成所有消息队列都会无限等待。
但验收要求是明确的:不能只证明发送成功,还要证明消息被消费、业务状态被推进,失败可以重试或进入可处理的异常状态。压测应覆盖处理速度低于生产速度、消费停止、依赖超时等情况,并观察积压、延迟和资源占用。
单元测试适合验证规则和分支,集成测试验证组件协作,端到端测试验证业务闭环。小团队可以先覆盖资金、状态流转、复杂算法和频繁变动的部分,不能指望一种测试替代其他所有验证。
少量流程也要有明确产出
不需要为每次改动开长会,但重大架构变化至少要留下依赖关系、启动方式、配置项、验收标准和回滚方案。运维应提前知道新增组件、网络权限和启动顺序,开发者也要有可以稳定运行的本地或测试环境。
| 阶段 | 至少确认的内容 |
|---|---|
| 开发前 | 需求样例、异常分支、边界及验收人 |
| 合并前 | 代码检查、关键测试、配置与数据变更 |
| 发布前 | 依赖就绪、备份与恢复方式、监控及停止条件 |
| 发布后 | 核心业务验证、错误率、延迟和消息积压 |
如果支持灰度,可以先让有限流量验证新链路;如果不支持,也要给出明确的维护安排和回退触发条件。涉及数据库结构或数据格式变化时,回滚不能只准备一个旧应用包,还要考虑新旧数据是否兼容。
需求不能只经过一个人的转述
当时团队规模很小:负责人沟通需求、拆任务、参与开发,还承担大量问题定位;其他开发者主要根据文档和任务描述实现功能。人数少并不自动意味着上下文一致,关键知识集中在负责人身上仍然会造成信息断层。
实际开发者应尽早参与需求讨论,用输入、输出和边界样例确认理解。需求变化要同步到共同的任务记录,避免只在私下聊天里达成局部共识。功能完成后先按验收样例自测,再由同伴检查关键代码和行为,最后交给需求方确认。
小公司的速度来自短反馈链路。真正值得精简的是没有产出的环节,而需求澄清、风险验证和可恢复发布,恰恰是减少返工、保持速度所需要的基础。