本文最初写于2017年,2026年重新整理。保留当时的问题,但不再把架构写成组件名词的集合。

2016年,我参与了一次网站整体重构。现在回头看,那次重构更接近一次代码重写:清理了年久失修的代码,却没有进一步调整数据库设计,也没有补齐日志和监控。新系统看起来更整齐,但承受变化和故障的能力提升有限。

这件事让我逐渐意识到,架构不是用了多少中间件,也不是图上画了多少方框。它首先回答几个具体问题:系统如何划分边界,容量从哪里来,故障发生后如何控制影响,以及变化能否以可承受的成本继续发生。

先把边界划清楚

分层、拆分和分布式部署都是手段。更难的是决定哪些东西适合放在一起,哪些变化需要彼此隔离。

一个相对稳定的模块,不应因为高频变化的业务功能而反复发布;低优先级服务,也不应成为核心链路的强依赖。数据库、线程池、缓存和消息队列的隔离,本质上都在限制故障传播。

边界不清时,系统表面上是一个整体,实际却很难判断一次修改会影响什么。边界清楚之后,扩容、降级和排障才有明确对象。

容量不是上线前猜一个数字

容量规划需要从真实指标出发:请求量、峰值、响应时间、错误率、线程与连接使用情况,以及数据库、缓存和消息堆积的变化。

缓存、异步和集群能够提高处理能力,但也会引入一致性、延迟和运维成本。是否使用它们,不应取决于架构图是否“完整”,而应取决于当前瓶颈在哪里。

在扩容之外,还需要为系统留下余量。系统如果长期贴着上限运行,一次流量波动、慢查询或下游延迟就可能演变成事故。

为依赖失败做准备

远程调用可能超时,数据库可能不可用,消息可能积压,配置也可能出错。可靠性设计不是假设这些问题不会发生,而是提前决定发生之后怎么办。

常见手段包括:

  • 为调用设置明确的连接、读取和整体超时;
  • 只对适合重试的操作重试,并限制次数和退避节奏;
  • 为非核心功能准备开关和降级路径;
  • 隔离不同优先级的资源,避免一处拥塞拖垮全部请求;
  • 对关键数据准备可验证的备份和恢复流程。

这些措施没有统一参数。脱离业务容量和失败成本谈超时、重试次数或缓存时间,往往只是把风险换了一个位置。

看不见,就谈不上治理

那次重构最明显的缺口之一,是日志和监控没有跟上。代码换了一遍,但系统出了问题之后,仍然缺少足够的信息判断发生了什么。

可观测性至少需要覆盖:

  • 用户侧的成功率和延迟;
  • 核心业务量及其异常变化;
  • 应用、数据库、缓存和消息系统的资源状态;
  • 一次请求跨越不同服务时的关联信息。

报警也不只是把阈值设得足够多。一个长期无人处理的报警,最终只会成为背景噪音。

架构需要允许继续修改

系统不会在一次重构后完成。业务会变,团队会变,最初正确的选择也可能失效。

所以我现在更在意的不是“设计出最终架构”,而是让系统能够被理解、被观测,也能够局部替换。好的结构不保证长期不变,但可以降低下一次调整的成本。

回头看2016年的那次重构,它的价值不在于结果有多成功,而在于让我第一次明确区分了两件事:整理代码可以改善局部质量,改变系统能力则需要重新审视边界、容量、故障和演进方式。