架构选型、容量估算与 ADR:把选择写成可验证的判断

“以后可能有一亿用户”不足以证明今天要上微服务。架构选择应从当前需求、可预期变化和可承担成本出发,并说明什么时候重新考虑。

1. 先列质量要求

功能需求描述能做什么,质量要求描述在什么条件下做得怎样。例如:订单提交 p95 延迟目标、峰值流量、数据保留时间、允许的恢复窗口、团队值班能力。数字先作为明确假设,再通过测量修正,别把估算写成硬件保证。

优先排序也很重要。预算有限、团队三个人的内部系统,发布简单和排错容易可能比跨语言服务自治更重要。相反,成熟平台中多个独立团队确有不同发布周期,服务拆分可能有现实收益。

2. 估算只为找数量级

假设每天 100 万个请求,平均每秒约为 1000000 / 86400 ≈ 11.6,但平均值掩盖了突发。若计划用 20 倍平均值作为演练峰值,这是人为假设,不是流量自然规律。

在稳定系统和适当统计边界下,Little 定律可写作平均在途数约等于到达率乘平均停留时间。若平均 200 次/秒、平均停留 0.2 秒,平均在途约 40。它不直接给出线程池大小,也不用 p99 代替平均值来宣称严格成立。

Python
requests_per_day = 1_000_000 average_rps = requests_per_day / 86_400 assumed_peak_rps = average_rps * 20 average_in_flight = 200 * 0.2 print(round(average_rps, 1), round(assumed_peak_rps, 1), average_in_flight)

存储估算同样加上索引、副本、日志、保留期与增长余量。压测要说明数据规模、冷热缓存、请求分布和负载发生器是否饱和,不能只给“每秒十万次”的孤立数字。

3. 一个起步选型表

已确认需求 倾向方案 暂时不引入什么
小团队,业务边界仍在变化 模块化单体 + 关系数据库 未有收益证据的微服务拆分
需要异步导出、通知 单体 + 队列与 Worker 所有请求都改成异步消息
读写形态差异显著 专用查询模型,必要时 CQRS 默认 Event Sourcing
独立团队和发布边界成熟 有明确数据所有权的服务 共享内部表的伪自治
请求波动大且任务适配平台 评估 Serverless 无视连接与执行时限

这张表是本教程的起步建议,不是采购结论。实际选择要通过业务约束、负载与运维能力验证。

4. 用 ADR 留下决策依据

Architecture Decision Record 记录一次重要决策的背景、选项、选择和后果。不必写成几十页汇报,关键是未来的人能理解当时为什么这样做,以及什么条件变化后应该重审。

Text
决策:初版采用模块化单体,通知使用独立 Worker。 背景:三人维护;订单与库存需要本地事务;通知允许延后。 选项:纯同步单体 / 单体加 Worker / 全量微服务。 选择理由:保留事务简单性,同时隔离通知延迟。 代价:核心应用仍统一发布;需要维护 Outbox 与消费监控。 重审条件:模块间发布阻塞持续发生,且团队已具备独立值班能力。 验证:并发下单、通知停机恢复、备份恢复与发布回归。

5. 完成一份真正的设计

交付不只是框图。补上接口契约、数据表、状态机、权限、失败恢复、指标、部署与回滚。再找一个同学只读你的文档,能否复现“重复下单”“数据库超时”“消息重复”三种情况?如果读者只能运行成功路径,设计还没有讲完。

参考资料