Software Architect · 模块 10

一旦系统越过单进程的边界,就有了延迟、重试、部分失败,以及不再唯一的真相。

Partial failure · timeout · retry · consistency · CAP

§ 01

在分布式系统里,失败可以是部分的:一个组件确信操作成功了,另一个组件却还不知道这件事。

网络不是一个函数

把信寄出去,不代表收信人收到了、看了、看懂了。网络也是这样。

调用相邻服务可能以 success、timeout、network error 收尾,也可能在 client 已经放弃之后才收到响应。Server 可能已经执行了操作,但 client 没收到回复;client 可能 retry 了一次,server 收到了重复请求。

所以分布式设计离不开 timeouts、带 backoff 的 retries、idempotency、circuit breakers、correlation ids 和清晰的责任边界。少了这些,系统能跑只是因为负载还小。

Consistency 是要花钱的

整栋楼的钟可以校到一致,楼越大,做到完全精确就越贵。

Strong consistency 对用户和开发者都方便,但它会限制 availability 和 latency。Eventual consistency 扩展性更好、对故障更宽容,但需要补偿、等待状态,以及一份诚实展示中间状态的 UX。

架构师不该把 CAP theorem 当口号挥舞。更值得问的具体问题是:业务在哪里要求严格一致,在哪里可以容忍传播延迟?

§ 02

分布式系统的复杂度都集中在边界上:钱、库存、通知、报表。

正例:order 与 email 拥有不同的保证

收据比营销邮件重要。丢收据是事故,丢营销邮件只是让人不高兴。

创建 order 和扣款必须被严格管控。Email 确认可以走 outbox 和 retry worker。Email 晚一点送达,order 依旧合法。

把不同强度的保证拆开,可以避免把 distributed transaction 拽到 eventual consistency 就够用的地方。

反例:七个服务的同步调用链

如果上班要连乘七部电梯,一部卡住就毁掉一整天。

Frontend 调 API,API 调 checkout,checkout 调 pricing,pricing 调 catalog,然后 identity、payment、notification。每段都配 30 秒 timeout。一旦出问题,用户在那等,工程师就得找哪一环坏了。

同步链条把 latency 和故障率一起放大。它们要么被缩短、被缓存、被改成 async,要么需要带显式 degradation path 的设计。

自查
  • 执行成功后又发生 timeout,会怎样? - 哪些操作必须 idempotent? - 哪里需要 strong consistency? - 用户会看到哪种 partial failure,UI 又如何向他解释?