主题
界面
主题
《高并发系统设计》 解决「能扛住」;本节解决「坏一台、抖一下、重试一波」时还能不能活。
★ 四组一手实测 ✓✓:
9 的换算:99.9% = 年停机 8.8 小时;99.99% = 52.6 分钟(每多一个 9,成本陡增)
串并联 :5 个 99.9% 服务串联 → 99.501%(年停机 1.8 天)✗✗;双活 → 99.9999% ✓✓
重试风暴:基础负载 85% 时「裸奔重试 3 次」**4 轮迭代就雪崩**(ρ=1.79)✗✗✗
加「重试预算」→ 收敛(ρ=0.935);加「熔断」→ 触发后回到 ρ=0.85 ✓✓★ 高可用不是「买更多机器」,而是「对故障的数学与预案」 ✗✓:
| 常见幻觉 ✗ | 现实 ✓ |
|---|---|
| 「我们多部署几台就很稳」 | 串联链路越长越脆(5 跳 → 99.5%)✗✗ |
| 「失败就重试,总会成功」 | 重试放大的是流量,不是可靠性 ✗✗✗ |
| 「SLA 写 99.99% 就行」 | 得算得出来、测得到、有预算约束 ✓ |
可用性 | 年停机 | 月停机 | 日停机
99% | 3.7 天 | 7.3 小时 | 14.4 分钟
99.9% | 8.8 小时 | 43.8 分钟 | 1.4 分钟
99.99% | 52.6 分钟 | 4.4 分钟 | 0.1 分钟
99.999% | 5.3 分钟 | 0.4 分钟 | 0.0 分钟★ 用法 ✓✓:对外承诺前先换算成「停机预算」 —— 「99.99%」意味着全年只能停 53 分钟:一次大促事故就超了 ✓。
串联 5 个 99.9% 的服务:0.999^5 = 99.501% → 年停机 1.8 天 ✗✗
并联(双活)2 个 99.9%:1 - 0.001² = 99.9999% → 年停机 0.5 分钟 ✓✓
3 层 × 每层双活:99.9997% → 年停机 1.6 分钟 ✓✓★★ 两条设计原则 ✓✓✓:
| 原则 | 落地手段 |
|---|---|
| 减少串联环节 ✓✓ | 合并调用(BFF/聚合层)、本地缓存、异步化 |
| 关键环节冗余 + 自动切换 ✓✓ | 多实例 + 健康检查 + 负载均衡(《Kubernetes 入门》 的容器自愈) |
★ 别忘「切换时间也算停机」 ✗:冷备切 5 分钟 = 每次故障先赔 5 分钟 ✓。
★ 场景:服务能力 1000 req/s、基础流量 850(ρ=0.85)、客户端超时 30ms、失败重试 3 次:
第 1 轮:λ= 850 → ρ=0.850 → 排队 5.7 ms → 超时率 0.94% → 重试 + 24
第 2 轮:λ= 874 → ρ=0.874 → 排队 6.9 ms → 超时率 2.00% → 重试 + 51
第 3 轮:λ= 901 → ρ=0.901 → 排队 9.1 ms → 超时率 4.62% → 重试 + 118
第 4 轮:λ= 968 → ρ=0.968 → 排队 30.1 ms → 超时率 36.87% → 重试 + 940
第 5 轮:λ=1790 → ρ=1.790 → **过载:队列无限增长,雪崩** ✗✗✗★★★ 正反馈链条 ✓✓✓:流量涨 → 排队涨 → 超时涨 → 重试涨 → 流量再涨 —— 关键是第 4 轮:超时率从 4.6% 跳到 36.9%,重试瞬间放大到 940/s ✗✗✗。
★ 三种解法的实测对比 ✓✓✓:
| 策略 | 结局 | 用户体感 |
|---|---|---|
| 不重试 | 稳定 ρ=0.85 ✓ | 约 1% 失败(可接受) |
| 重试 3 次(裸奔) | 雪崩,过载 ✗✗✗ | 全员超时 |
| 重试 + 预算 10% | 稳定 ρ=0.935 ✓ | 约 13% 超时(降级但不崩) |
| 重试 + 熔断(10%) | 熔断后回到 ρ=0.85 ✓✓ | 短暂失败后恢复 |
★★ 三条铁律 ✓✓✓:
★ 呼应 《项目 B:性能测试与故障分析》:项目 B 的故障分析里「超时设置不合理 + 无退避重试」正是同类事故 ✓。
SLO 99.9% → 月错误预算 = 43200 × 0.001 = **43.2 分钟**
本月已消耗 31.5 分钟(72.9%)→ 剩余 11.7 分钟
判定:**黄灯**:放缓发布节奏、优先修稳定性问题 ⚠️★ 使用规则 ✓✓:
预算充足(< 50%)→ 放心发版、做演练、冒可控风险 ✓
预算过半(黄灯) → 放慢节奏、修复优先 ✓
预算耗尽(红灯) → **冻结功能发布**,全员转向稳定性 ✗✓★★ 价值 ✓✓✓:把「研发要快」和「运维要稳」的争执,变成一条双方认可的线 —— 没有错误预算,SLA 就只是一句口号 ✗✓。
| 维度 | 必做项 | 呼应 |
|---|---|---|
| 冗余 | 多实例 + 多可用区;无状态化(有状态要谈复制) | 《CAP 与 BASE 理论》 |
| 隔离 | 舱壁(线程池/连接池按依赖隔离)、租户隔离 | 《线程池与 ThreadPoolExecutor》 |
| 超时 | 每个远程调用都要有超时;超时 < 上游超时(层层收敛) | 本节 5.3 ✓ |
| 重试 | 预算 + 退避 + 抖动 + 只重试幂等操作 | 《分布式事务》 |
| 熔断/降级 | 超时率/错误率阈值 + 兜底响应(缓存/默认值) | 《Sentinel 限流与熔断》 |
| 限流 | 入口限流 + 依赖保护 | 《高并发系统设计》 |
| 演练 | 故障注入(杀实例/断依赖/压满 CPU)、定期做 | 混沌工程 |
| 可观测 | RED 指标(Rate/Error/Duration)+ 告警 + 追踪 | T2-016 |
网关 3s → 服务 A 2s → 服务 B 1s → DB 500ms
★ 上游超时必须大于下游(否则下游还在干活、上游已放弃 = 白干)✗✓
★ 反例:全都配 3s → 一次慢调用可以把三层线程全部占满 3 秒 ✗✗关闭(正常)→ 错误率超阈值 → 打开(快速失败)→ 冷却期 → 半开(放少量探测)
★ 半开的意义:**恢复要有试探,不能一次性放全量** ✓✓支付超时 → 重试 → 可能扣两次 ✗✗(除非幂等,[S6-014](../distributed/S6-014))
★ 规则:**只重试幂等操作;非幂等必须先做幂等改造** ✓✓✓代码:labs/java-deep/src/main/java/cn/kb/learn/deep/architecture/AvailabilityMathLesson.java、labs/java-deep/src/main/java/cn/kb/learn/deep/architecture/RetryStormLesson.java
实测输出(节选):
===== 串并联计算:微服务为什么越拆越脆 =====
串联 5 个 99.9% 的服务(一次请求穿过 5 个):
0.999^5 = 0.99501(99.5010%)→ 年停机 1.8 天 ✗✗
并联(双活)2 个 99.9% 的实例:
1 - 0.001² = 0.999999(99.9999%)→ 年停机 0.5 分钟 ✓✓
===== 场景:失败就重试 3 次(无上限、无退避)=====
第 4 轮:λ= 968 → ρ=0.968 → 排队 30.1 ms → 超时率 36.87% → 重试 + 940
第 5 轮:λ= 1790 → ρ=1.790 → **过载:队列无限增长,雪崩** ✗✗✗
===== 场景:重试 3 次 + 重试预算 10% =====
→ 结论:**收敛于 λ=935(ρ=0.935)**(预算限制住了重试),超时率 13.3% ⚠️| # | 错误 | 说明 |
|---|---|---|
| 1 | 失败就重试、无预算无退避 ✗✗✗ | 本节实测:4 轮雪崩 ✓✓ |
| 2 | 在非幂等操作上重试 ✗✗✗ | 双扣 / 重复下单 ✓✓ |
| 3 | 超时不收敛(层层都 3s) ✗✗ | 慢调用会占满整条链的线程 ✓ |
| 4 | 冷备切换不算停机预算 ✗ | 每次故障先赔切换时间 ✓ |
| 5 | SLA 只写不测 ✗ | 没有监控与错误预算 = 空话 ✓✓ |
| 6 | 从不做故障演练 ✗✗ | 切换/降级路径从未被验证过 ✓✓ |
AvailabilityMathLesson:把你项目的 SLA 换算成停机预算 ✓✓✓;RetryStormLesson:把基础流量改成「大促水位」,观察雪崩点前移 ✓✓✓;验收方式:给出一条调用链,能指出它的串联可用性、重试风险点、超时收敛顺序与降级方案。
扩展任务:写一份《高可用设计卡》:每个依赖的「超时/重试/熔断/降级」四要素 + 演练记录 ✓✓
《DDD 领域驱动设计》 —— 从「系统怎么不坏」转向「系统怎么长得对」。
暂无