概述
系列定位说明
本文是“分布式系统架构认知与设计”系列的第六篇,亦是本系列的收官之作。在前五篇中,我们依次构建了分布式系统的完整认知框架:第1篇《核心模型与分层架构》建立了能力域×分层矩阵的思维模型;第2篇《设计原则与权衡哲学》深入探讨了六大设计原则、四大反直觉陷阱与五大权衡;第3篇《通用架构模式》拆解了四种主流架构模式及其组合策略;第4篇《时间维度与故障传播》推导了时间参数的传递链、重试策略与故障跨层传播机制;第5篇《设计流程与实战推演》将这些知识整合为可操作的六步设计流程,并以电商订单系统为案例完成了从需求到部署的完整推演。
在前五篇中,读者已学会了“如何设计”一个分布式系统。而本文的目标,是让读者掌握“如何评审”一个分布式系统。设计是从零开始构建,评审则是在有限时间内对已有架构进行系统性的风险识别与决策验证。我们提供一套完整的架构评审方法论与50+条可直接勾选的工程化检查清单,覆盖通信、协作、存储、治理四大维度,每一条清单均源自前五篇推导的设计原理,并映射至真实的生产故障案例。此外,本文还将给出架构评审报告模板、架构演进策略、技术债务管理方法,以及覆盖全部6篇与后续6个系列的全系列知识地图,最终形成从“会设计”到“会评审”的完整能力闭环。
总结性引言
设计分布式系统很难,评审分布式系统更难——甚至比设计更具挑战。设计时,你可以从零开始自由选择技术组件,在宽阔的设计空间中权衡取舍。而评审时,你面对的是一个已经成型的、承载着业务流量与技术债务的活系统。你需要在有限的时间和信息下,快速识别那些隐藏在代码、配置和架构图背后的风险点:一个分片键的选择错误,会导致全分片广播,使数据库不堪重负;一个看似微小的超时配置失误,可能引发跨服务的重试风暴,最终导致全链路雪崩;一个熔断降级的遗漏,可能使一个非核心服务的故障拖垮整个核心链路。这些风险,在静态的架构图上极难察觉,在生产故障爆发之前也不易被发现——但一旦爆发,往往就是 P0 级事故。
本文正是为解决这一难题而生。我将从通信、协作、存储、治理四个维度,提炼出 50 余条工程化检查清单。通信评审检查你的服务间调用链是否闭环、超时是否遵循传递链、重试是否保证幂等;协作评审检查你的分布式锁是否有 fencing token、事务方案是否匹配业务要求、选主算法是否满足可用性 SLO;存储评审检查你的分片键是否所有核心查询的条件、缓存 TTL 是否随机化、冷热迁移是否有限速保护;治理评审检查你的熔断降级是否覆盖所有外部依赖、探针是否考虑 GC 停顿、告警是否分级、日志是否包含 TraceId。每一条清单都不是凭空臆想,而是基于本系列前五篇的设计原理推导,以及大量真实生产故障案例的总结——违反了某条检查项,曾经在某个知名公司的生产系统中导致了某个具体的、可复盘的事故。
此外,本文还将提供架构演进策略与技术债务管理方法,将架构评审从一次性的“专家会诊”转变为融入日常研发流程的持续治理闭环。最后,我会以一张全系列知识地图收尾,将本系列 6 篇与后续 6 个系列(理论基石、事务、数据架构、JVM、高并发、K8s)的知识点完整关联,形成从总纲到各系列的索引。当你在后续系列中学完某项技术后,可以回到本文的对应检查项,验证其合理性,形成“学习→设计→评审→优化”的完整闭环。
本文核心要点
- 架构评审四维模型:通信评审(调用链/超时/重试/死信/连接池/网关安全)、协作评审(锁安全/事务匹配/选主可用性/共识集群配置)、存储评审(分片键/缓存一致性/冷热分离安全/多租户强制过滤/数据同步链)、治理评审(熔断降级覆盖/探针合理性/告警分级/全链路追踪/安全配置)。
- 50+ 条工程化检查清单:每条包含检查项、设计原理(为什么重要)、违反后果(会导致什么故障)、前文知识关联(详见系列第 X 篇),并辅以正确配置与错误配置的正反对比。
- 评审流程五步法:评审准备(收集架构文档)→ 逐维评审(对照检查清单)→ 问题分级(P0/P1/P2)→ 整改跟踪(责任到人+期限)→ 评审闭环(报告归档+基线建立)。
- 架构演进策略:单体 → 微服务 → 事件驱动 → 数据密集型 → 云原生的渐进式路径,每次演进触发一次架构评审。
- 技术债务管理:L1(影响可用性/安全,立即修复)/ L2(影响可维护性,1-2 迭代)/ L3(影响扩展性,技术规划排期),每季度预留 20% 容量偿还技术债务。
- 全系列知识地图:本系列 6 篇 + 后续 6 个系列在能力域×分层矩阵中的完整知识索引。
文章组织架构图
flowchart TB
subgraph "方法论与模型"
A1["1. 架构评审方法论:目的、原则、流程与能力域×分层矩阵映射"]
end
subgraph "四维评审核心"
A2["2. 通信评审检查清单:调用链/超时/重试/死信/连接池/网关安全"]
A3["3. 协作评审检查清单:分布式锁/事务/选主/共识集群"]
A4["4. 存储评审检查清单:分片键/缓存/冷热/多租户/数据同步"]
A5["5. 治理评审检查清单:熔断降级/探针/告警/全链路追踪/安全"]
end
subgraph "流程与基线"
A6["6. 评审报告模板与基线设定"]
end
subgraph "演进与债务"
A7["7. 架构演进策略与技术债务管理"]
end
subgraph "知识索引"
A8["8. 全系列知识地图与后续系列索引"]
end
subgraph "能力巩固"
A9["9. 面试高频专题"]
end
A1 --> A2
A1 --> A3
A1 --> A4
A1 --> A5
A2 & A3 & A4 & A5 --> A6
A6 --> A7
A7 --> A8
A8 --> A9
图1:文章组织架构图
- 图表主旨概括:本文从方法论出发,依次展开四维评审清单,再延伸到报告模板、演进策略和知识索引,最后以面试题巩固。
- 逐元素分解:模块1建立评审方法论基础;模块2~5是全文核心——四维评审检查清单,每一条都包含设计原理、故障案例与前文关联;模块6提供可直接使用的评审报告模板与基线机制;模块7给出架构从单体到云原生的演进路径及技术债务分级偿还策略;模块8绘制全系列知识地图;模块9提供高价值的面试专题。
- 设计原理映射:此结构遵循“先建立认知框架,再逐维深入检查,最后沉淀为流程与制度”的工程思维。评审方法论是“心法”,检查清单是“招式”,报告模板与基线是“制度”,演进策略是“方向”,知识地图是“索引”。
- 工程联系与关键结论:架构评审并非一次性的活动,而应嵌入整个软件开发生命周期。本文提供的检查清单和流程,可以直接作为团队架构评审会议的议程和评审基线。将架构评审制度化,是避免生产事故、控制技术债务、保障系统长期健康发展的核心工程实践。
1. 架构评审方法论:目的、原则、流程与能力域×分层矩阵映射
1.1 架构评审的三大目的
架构评审(Architecture Review)不是“找茬”,更不是“技术选秀”,而是一项严谨的工程风险识别与决策验证活动。其核心目的有三:
- 风险识别(Risk Identification):在系统上线或重大变更之前,系统化地暴露架构中潜在的可用性、性能、安全性、成本风险。例如,一个看似合理的超时配置可能在流量高峰时因“超时叠加”导致重试风暴,这些风险在代码审查或功能测试中极难发现,必须通过结构化的架构评审来捕捉。
- 决策验证(Decision Validation):验证架构设计中的关键技术决策是否与业务目标及非功能性需求(性能、可用性、安全性、可维护性、成本)保持一致。例如,选择 Saga 事务模式是否真正匹配了业务的“最终一致性”容忍度?分片键的选择是否真的覆盖了所有核心查询?评审确保设计决策不是基于某个人的技术偏好,而是基于业务优先级和量化指标。
- 基线建立(Baseline Establishment):为系统建立一个架构健康度的“基线快照”,作为后续迭代演进、故障复盘、技术债务管理的参照点。没有基线的架构评审是盲目的,有了基线,我们才能衡量架构是变得更好还是更差。
1.2 架构评审的三大原则
- 基于检查清单而非个人经验:人类的工作记忆有限,即使是经验丰富的架构师也可能在评审中遗漏关键点。一份结构化的、持续更新的检查清单(Checklist)能保证评审的一致性与完整性,避免遗漏。Atul Gawande 在《清单革命》中早已论证,在复杂领域,专家也会犯错,清单是避免“无能之错”的有效工具。
- 基于量化指标而非主观感觉:“这看起来很快”、“应该扛得住”这类表述在架构评审中毫无意义。评审必须基于量化数据说话——具体的 TPS/QPS、P99 延迟、可用性百分比、成本数字、容量规划公式。只有在量化指标的约束下,才能做出理性的权衡。例如,讨论缓存是否应该预热,必须以数据库能承受的 QPS 和缓存未命中的预估流量为依据。
- 基于业务优先级而非技术偏好:技术选型必须服务于业务目标,而非反过来。评审时,必须反复追问:“这个技术选择是为了解决什么业务问题?是否引入了与业务规模不匹配的复杂度?”。过早引入 Redis Cluster 处理几千的 QPS 是不必要的成本与运维负担;要求所有业务都实现 TCC 强一致性是过度设计。业务优先级是架构取舍的最高准则。
1.3 评审的四维模型与能力域×分层矩阵的映射
在系列第1篇中,我们构建了四大能力域(通信、协作、存储、治理)与五层分层(接入层、服务层、数据层、基础设施层、业务层)的矩阵模型。架构评审自然而然地聚焦于这个矩阵的交叉格(Cell)中。我们将评审点归纳为四个维度,每个维度恰好对应一个或多个矩阵格:
- 通信评审:聚焦 服务层 × 通信格(RPC/MQ/Gateway) 的调用链、超时、重试、幂等。同时也涉及接入层与外部系统的通信安全。
- 协作评审:聚焦 服务层 × 协作格(分布式锁/事务/选主) 与 数据层 × 协作格(事务方案) 的正确性与可用性。
- 存储评审:聚焦 数据层 × 存储格(分库分表/缓存/搜索/列存/冷热) 的性能、成本、隔离性。
- 治理评审:聚焦 接入层 × 治理格(限流/鉴权)、服务层 × 治理格(服务发现/熔断/配置)、基础设施层 × 治理格(监控/告警/K8s) 的可观测性与弹性。
1.4 架构评审四维模型图
flowchart TD
subgraph Comm ["通信评审"]
direction TB
C1["调用链闭环 (P0)"]
C2["超时传递链 (P0)"]
C3["重试幂等 (P0)"]
C4["死信处理 (P1)"]
C5["连接池保护 (P1)"]
C6["网关安全 (P1)"]
end
subgraph Coord ["协作评审"]
direction TB
D1["锁FencingToken (P0)"]
D2["事务匹配 (P0)"]
D3["选主可用性 (P0)"]
D4["共识集群奇数节点 (P1)"]
D5["磁盘容量告警 (P2)"]
end
subgraph Store ["存储评审"]
direction TB
E1["分片键合理性 (P0)"]
E2["缓存一致性 (P1)"]
E3["冷热分离限速 (P1)"]
E4["多租户强制过滤 (P0)"]
E5["数据同步链 (P1)"]
end
subgraph Gov ["治理评审"]
direction TB
F1["熔断降级覆盖 (P0)"]
F2["探针合理性 (P1)"]
F3["告警分级 (P1)"]
F4["全链路追踪 (P1)"]
F5["安全配置 (P1)"]
end
Comm --- Coord --- Store --- Gov
classDef comm fill:#f1f5f9,stroke:#334155,color:#0f172a
classDef coord fill:#ede9fe,stroke:#8b5cf6,color:#3b2f4b
classDef store fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef gov fill:#e2e8f0,stroke:#475569,color:#1e293b
class C1,C2,C3,C4,C5,C6 comm
class D1,D2,D3,D4,D5 coord
class E1,E2,E3,E4,E5 store
class F1,F2,F3,F4,F5 gov
图2:架构评审四维模型图(象限图)
- 图表主旨概括:将评审点按关注维度划分为四个象限,并标注了每个维度的核心检查项及其典型风险等级(P0/P1/P2)。
- 逐元素分解:
- 通信评审:关注服务间如何“交谈”,结构性强(调用链、超时配置),行为也重要(重试风暴)。核心风险在于错误的配置会导致级联故障。
- 协作评审:关注服务间如何“协同工作”(锁、事务、选主),更偏向业务逻辑正确性,数据一致性和可用性是核心。
- 存储评审:关注数据的“安放之处”,偏向数据架构设计,性能和隔离性是核心。
- 治理评审:关注系统的“健康与安全”,偏向基础设施与运维,可观测性和弹性是核心。
- 设计原理映射:四个维度的划分直接源于能力域×分层矩阵。通信和协作主要落在服务层;存储主要落在数据层;治理横跨接入、服务、基础设施层。这种划分使得评审者可以按域聚焦,避免遗漏。
- 工程联系与关键结论:任何架构评审都应从这四个维度分别展开检查,不能只关注其中一个维度而忽略其他。生产故障往往是多维度风险耦合的结果——例如,通信域的超时未配好(通信风险)+ 治理域的熔断未覆盖(治理风险)= 雪崩。四维评审是一张安全网。
1.5 架构评审流程图
flowchart TD
subgraph A [1. 评审准备]
A1[收集架构文档]
A2[明确评审范围与业务目标]
A1 --> A2
end
subgraph B [2. 逐维评审]
B1[通信评审检查清单]
B2[协作评审检查清单]
B3[存储评审检查清单]
B4[治理评审检查清单]
end
subgraph C [3. 问题分级]
C1[P0 阻塞上线]
C2[P1 强烈建议修复]
C3[P2 建议优化]
end
subgraph D [4. 整改跟踪]
D1[指定责任人与期限]
D2[修复后二次评审]
end
subgraph E [5. 评审闭环]
E1[评审报告归档]
E2[建立/更新架构基线]
E3[反馈至故障复盘与检查清单]
end
A2 --> B1 & B2 & B3 & B4
B1 & B2 & B3 & B4 --> C1 & C2 & C3
C1 & C2 & C3 --> D1
D1 --> D2
D2 --> E1
E1 --> E2
E2 --> E3
E3 -.-> A1
图3:架构评审流程图
- 图表主旨概括:展示了从准备到闭环的完整五步流程,并强调了故障复盘对检查清单的持续反哺。
- 逐元素分解:
- 评审准备:输入为系统的架构图、时序图、技术选型决策表、容量规划表、时间参数配置表等;输出为本次评审的范围(如“聚焦订单核心链路”)、业务目标(如“支撑双十一 10 万 TPS”)和参与角色(架构师、高级开发、SRE)。
- 逐维评审:依据本文第2~5章的检查清单,逐条核对。需要被评审系统的负责人逐条应答或展示证据,评审小组记录问题。
- 问题分级:将发现的问题按照严重程度分为 P0/P1/P2 三级(详见1.6节)。
- 整改跟踪:每个问题必须有明确的责任人和修复期限,修复完成后需要二次评审验证。不能只提出问题不跟踪解决。
- 评审闭环:评审报告最终归档,作为系统架构基线。同时,将本次评审发现的问题(尤其是遗漏项)与故障复盘结合,反哺检查清单,使清单持续演进。
- 设计原理映射:该流程参考了 Google SRE 的生产就绪检查(Production Readiness Review, PRR)和 Netflix 的架构评审流程,强调“有始有终,持续改进”。评审不是终点,而是架构治理循环的起点。
- 工程联系与关键结论:架构评审流程必须制度化。建议每个季度对核心系统进行一次定期评审,并在每次大版本发布前进行增量评审。没有闭环的评审等于没有评审。
2. 通信评审检查清单
通信是分布式系统的神经网络。服务间调用链路的任何一处设计不当,都可能在故障时转化为风暴。本章给出15条通信域检查清单,每条均包含设计原理、违反后果及前文知识关联。
2.1 调用链闭环与长度检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COMM-01:所有服务间调用链是否形成闭环?是否存在 A→B→C→A 的循环依赖? | 通信域 | 循环调用在正常时可能无恙,但一旦某个节点超时或故障,重试机制会沿着环路不断放大请求量,形成“重试风暴”。详见第4篇故障传播链。 | A→B→C→A 循环依赖,C 故障超时→B 重试→A 重试→再次调用 C,瞬时流量指数增长,最终打垮所有服务。 | P0 | 第4篇(故障传播) | 高并发与稳定性工程(限流/熔断) |
| CHK-COMM-02:核心链路的调用链深度是否 ≤5 层? | 通信域 | 假设每层服务可用性为 99.9%,5 层链路的整体可用性仅为 99.5%。层数越多,故障概率呈指数级增加。详见第4篇时间参数传递链中的可用性串行计算。 | 10 层调用链,整体可用性降至 99.0%,每月多出数小时不可用时间。同时,过长的调用链会导致整体延迟增大,难以满足 SLO。 | P1 | 第4篇 | 高并发与稳定性工程(SLO 设定) |
真实故障案例:某金融系统,用户查询账户余额的调用链为 API Gateway → 用户服务 → 账户服务 → 资产服务 → 用户服务(用于反查权限)→ 资产服务。该环路在生产压测时,因资产服务一个慢 SQL,导致网关超时、用户服务重试、资产服务压力更大,最终形成重试风暴,整个核心链路瘫痪。
调用链闭环检查方法:绘制系统的服务依赖拓扑图,使用 PageRank 类似的算法检测强连通分量,或至少在架构评审时逐条追踪每个接口的调用路径,确保无环路。
2.2 超时传递链检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COMM-03:所有服务间调用的超时配置是否遵循“上游超时 > 下游超时之和”原则? | 通信域 | 上游必须在所有下游完成之前不提前断开连接,否则会导致客户端收到 502/504 错误,而服务端仍在执行请求(浪费资源且可能产生幽灵事务)。详见第4篇时间参数传递链。 | Gateway 超时 3s,但订单服务超时 2s + 库存服务超时 2s > 3s。当库存服务正常响应但总耗时 3.5s 时,Gateway 已超时断开,用户看到失败,但订单已创建、库存已扣减,造成数据不一致。 | P0 | 第4篇 | 分布式事务工程实践(补偿机制) |
| CHK-COMM-04:是否从最上游开始,逐层检查并记录了每个 RPC/MQ/DB 调用的超时配置,并形成超时配置树? | 通信域 | 超时配置散落在各个配置文件中,极易出现不一致或链式不满足的情况。用表格或树形结构显式化所有超时值,是验证正确性的前提。 | 配置不一致,如 Dubbo 超时 1s,但下游服务实际处理时间 P99=1.2s,导致大量正常请求被误判超时,浪费重试资源。 | P1 | 第4篇 | - |
| CHK-COMM-05:超时时间是否考虑了业务峰值的延迟抖动?例如 DB 慢查询、GC 停顿、网络重传。 | 通信域 | 静态的超时设置在面对生产环境波动时可能偏紧。超时应设置略高于 P99.9 延迟,或采用自适应超时(如 Google SRE 的 hedging 机制)。 | 大促期间,DB 因锁竞争导致查询延迟从 50ms 飙升至 500ms,但 RPC 超时仍为 300ms,导致大量请求超时,服务不可用。 | P1 | 第4篇(时间参数) | JVM 深度调优(GS对超时的影响) |
配置正反对比:
# ---------- 错误配置 ----------
# Gateway
spring.cloud.gateway.routes[0].filters[0].args.timeout: 3000 # 3s
# OrderService (Dubbo)
dubbo.provider.timeout: 2000 # 2s
# InventoryService (Dubbo)
dubbo.provider.timeout: 2000 # 2s
# 违反:Gateway 3s < 2s + 2s = 4s
# ---------- 正确配置 ----------
# Gateway
spring.cloud.gateway.routes[0].filters[0].args.timeout: 6000 # 6s,留有余量
# OrderService (Dubbo)
dubbo.provider.timeout: 2500 # 2.5s
# InventoryService (Dubbo)
dubbo.provider.timeout: 1500 # 1.5s
# 满足:Gateway 6s > 2.5s + 1.5s = 4s,且每层内部还有网络和序列化开销
# 同时,InventoryService 的超时应小于 OrderService,因为它是被调用方
2.3 重试幂等检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COMM-06:所有可能重试的写操作(RPC/DB/MQ)是否保证了幂等?通过唯一键、状态机或 fencing token 实现。 | 通信域 | 网络不可靠,重试是常态。非幂等写操作在重试时会导致重复扣款、重复发货等严重事故。详见第4篇幂等保障的三种方案。 | 支付回调接口因网络超时被重试 3 次,而回调处理逻辑未做幂等,导致用户信用卡被扣款 3 次。生产事故。 | P0 | 第4篇(幂等设计) | 分布式事务工程实践(TCC幂等) |
| CHK-COMM-07:重试次数与退避策略是否匹配业务的容忍时间?例如,支付重试不应在 5s 内重试 3 次后直接放弃。 | 通信域 | 不恰当的重试策略可能导致“一时失败变成永久失败”,或者重试过于密集打垮下游。需要结合业务最大等待时间设计退避(指数退避 + 随机抖动)。 | 支付通知因下游短信网关抖动失败,RocketMQ 在 1 分钟内重试 16 次,全部失败后进入死信。而短信网关 2 分钟后自恢复,消息却已丢失。 | P1 | 第4篇(重试策略) | 高并发与稳定性工程(重试风暴防治) |
正确配置示例(RocketMQ 消费者):
// 消费重试策略设置
consumer.setMaxReconsumeTimes(16); // 共重试16次
consumer.setConsumeTimeout(15 * 60 * 1000); // 消费超时15分钟
// 消息消费逻辑必须实现幂等,比如根据 bizOrderId 做 Redis setnx 防重
2.4 消息队列死信与监控检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COMM-08:每个 RocketMQ Topic / Kafka Topic 是否配置了死信队列(DLQ)? | 通信域 | 消息重试耗尽后会被丢弃或进入死信。没有死信队列意味着消息永久丢失,无法回溯。有死信队列则可以后续人工处理或补偿。 | 订单状态变更消息因下游服务 BUG 消费失败,重试 16 次后丢弃。未配置 DLQ,导致大量订单状态未同步,用户投诉。 | P1 | 第3篇(MQ模式) | 分布式事务工程实践(可靠消息) |
| CHK-COMM-09:死信队列是否有监控告警(P1级,15分钟内响应)?是否有死信管理平台支持重放? | 通信域 | 仅仅有死信队列不够,必须有人关注。死信堆积意味着业务数据不一致正在累积,需要及时介入。 | 死信队列积压 10 万条消息,无人知晓。直到财务对账发现巨额差异,影响月报。 | P1 | 第2篇(可观测性) | 高并发与稳定性工程(告警体系) |
2.5 连接池保护与隔离检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COMM-10:数据库连接池(HikariCP)是否设置了最大连接数(maximumPoolSize),并且该值是否根据数据库最大连接数和实例数合理计算? | 通信域 | 无限制的连接池会在慢查询或流量尖峰时耗光数据库连接,导致所有服务线程阻塞等待连接,引发雪崩。详见第4篇故障跨层传播链。 | 某服务一个慢查询导致连接池从 20 耗尽至 0,而其他健康接口也需要获取连接,导致整个服务无响应,进而上游超时重试,全链路崩溃。 | P0 | 第4篇(连接池耗尽) | JVM深度调优(线程池配合) |
| CHK-COMM-11:不同服务或不同业务域是否使用独立的数据库连接池或至少独立的数据库用户? | 通信域 | 共享连接池会导致故障隔离性差。一个慢查询或大数据写入可能占满连接,影响其他无关业务。 | 报表服务与订单服务共用同一数据库用户和连接池,报表的一条大查询导致连接池阻塞,订单服务无法下单。 | P1 | 第1篇(分层隔离) | 分布式数据架构(读写分离) |
配置正反对比(HikariCP):
# 错误:无限制或过大
spring.datasource.hikari.maximumPoolSize: -1 # 无限制!
# 正确:基于公式计算
# 假设数据库 max_connections=1000,部署 5 个服务实例,每个实例最多 1000/5 - 10 = 190
spring.datasource.hikari.maximumPoolSize: 30 # 根据实际并发估算
spring.datasource.hikari.minimumIdle: 5
spring.datasource.hikari.connectionTimeout: 3000
2.6 API 网关安全与限流检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COMM-12:Spring Cloud Gateway / Istio Ingress 是否配置了 CORS、CSRF 防护、请求大小限制、SQL 注入/XSS 过滤等 Web 安全策略? | 通信域 | 网关是系统的第一道防线,必须在恶意流量和异常请求进入内部服务前进行拦截和清洗。 | 未限制请求体大小,攻击者发送 1GB 的 JSON 导致网关 OOM;未过滤 XSS,导致存储型 XSS 攻击,用户 cookie 泄露。 | P0 | 第1篇(接入层) | 高并发与稳定性工程(API安全) |
| CHK-COMM-13:是否配置了基于令牌桶或漏桶的 RateLimiter 限流策略,并且限流后返回标准的 429 状态码及友好的提示? | 通信域 | 限流防止恶意刷接口、防止突发流量打垮下游。没有限流的网关形同虚设。 | 某秒杀活动,瞬时流量是平常的 100 倍,未配置限流,直接穿透到订单服务,导致服务 OOM 重启,正常的用户也无法访问。 | P0 | 第5篇(容量规划) | 高并发与稳定性工程(Sentinel) |
Gateway 限流配置示例:
spring:
cloud:
gateway:
routes:
- id: order_route
uri: lb://order-service
filters:
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 100 # 每秒令牌数
redis-rate-limiter.burstCapacity: 200 # 突发容量
通信评审检查清单汇总表:共 13 条,P0 级 7 条,P1 级 6 条。
3. 协作评审检查清单
协作是分布式系统实现正确性与可用性的关键。分布式锁、事务、选主、共识等机制的错误配置或选型失误,直接导致数据错乱、双主、全集群不可用等灾难性后果。本章给出10条检查清单。
3.1 分布式锁安全性检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COLL-01:分布式锁是否具备 fencing token 机制,防止 GC 停顿导致锁过期后其他客户端获取锁,原客户端恢复后仍认为自己持有锁? | 协作域 | 没有 fencing token,锁就不是安全的。GC 停顿、网络延迟都可能导致锁被静默释放,原持有者继续执行临界区代码,造成数据破坏。详见分布式理论基石第6篇。 | Redis 红锁(Redlock)实现,因 GC 停顿导致锁过期,两个客户端同时扣减库存,造成超卖。 | P0 | 第2篇(正确性) | 分布式理论基石(第6篇锁正确性证明) |
| CHK-COLL-02:锁的 TTL(租约时间)是否大于业务逻辑的最大执行时间(包括 GC 和网络延迟)? | 协作域 | TTL 过短,锁可能在业务未完成时自动释放,让其他竞争者进入;TTL 过长,则在持有者崩溃时,其他竞争者需要等待过久,降低可用性。 | Redis 锁 TTL=10s,而生成报表的业务逻辑有时需要 15s,导致锁提前释放,多个实例同时生成报表,写入冲突。 | P0 | 第4篇(时间参数) | 分布式理论基石(锁的TTL) |
| CHK-COLL-03:是否使用了自动续期机制(如 Redisson 的 watchdog)来保持锁,直到业务显式释放? | 协作域 | 自动续期可以解决 TTL 设置难题:你不需要精确预估业务执行时间,只要业务还在健康执行,锁就保持;若进程崩溃,锁最终会过期。 | 手动续期逻辑易出错,一旦忘记续期,锁提前释放。Redisson 的 watch dog 默认每 10s 续期一次,TTL 30s,非常可靠。 | P1 | - | 分布式理论基石(Redisson源码) |
正确配置示例(Redisson RLock + fencing token):
// Redisson 提供了基于 Redis 的 RedLock 和普通的 RLock,都内置了 watchdog
RLock lock = redissonClient.getLock("order:lock:" + orderId);
lock.lock(); // 默认 TTL 30s,watchdog 每 10s 续期,业务完成后 unlock
// Fencing token 通常需要结合数据库版本号或 ZK zxid 实现:
// 例如,获取锁时从 Redis 递增一个计数器作为 token,更新数据时带上 token,
// 并在更新时校验 token >= 当前记录的 token,防止旧主覆盖。
long token = redisTemplate.opsForValue().increment("lock:token:" + lockKey);
// 执行业务,更新时携带 token
3.2 事务方案匹配检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COLL-04:分布式事务方案的选型(XA/AT/TCC/Saga/可靠消息)是否与业务对一致性、隔离性、性能的要求匹配? | 协作域 | 强一致性方案(AT/TCC)成本高、性能差,用于低价值、高吞吐场景会过度设计;最终一致性方案用于金融交易可能导致资损。详见第2篇五大权衡中的“性能 vs 正确性”。 | 金融转账系统为追求性能选用了 Saga 模式,转账服务成功,入账服务补偿失败,导致资金挂账,无法对账。 | P0 | 第2篇(权衡) | 分布式事务工程实践(第8篇选型决策树) |
| CHK-COLL-05:事务超时时间是否大于 GC 停顿时间 + 业务执行时间 + 所有参与者网络往返时间? | 协作域 | 事务超时过短会导致正常事务被回滚,造成业务失败或必须重试;过长则长期持有锁,降低并发。 | Seata AT 模式超时设为 5s,但大促期间 GC 停顿 6s,导致本可成功的事务被回滚,大量订单失败。 | P1 | 第4篇(时间参数) | 分布式事务工程实践(AT源码超时处理) |
事务匹配速查:
| 一致性要求 | 推荐方案 | 典型场景 | 性能成本 |
|---|---|---|---|
| 强一致(零容忍不一致) | XA / TCC | 金融转账、库存扣减 | 高 |
| 最终一致(秒级不一致可接受) | AT / 可靠消息 | 电商订单、积分 | 中 |
| 最终一致(分钟级) | Saga | 长流程审批、旅行预订 | 低 |
3.3 选主算法与可用性检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COLL-06:选主算法的故障转移时间(Raft 选举 ~300ms、ZK session timeout 30s、K8s Lease 15s)是否满足业务的可用性 SLO? | 协作域 | 选主期间,系统无法提供排他服务(如定时任务)。如果故障转移时间过长,会导致长时间服务中断。详见分布式理论基石第7篇。 | 定时任务使用 ZK 选主,session timeout 30s,Leader 崩溃后,需要 30s 才能选出新 Leader,在此期间定时任务中断,影响资金结算。 | P0 | 第5篇(SLO) | 分布式理论基石(第7篇选举) |
| CHK-COLL-07:是否明确选主组件的部署节点数?通常建议奇数节点(3/5/7)。 | 协作域 | 偶数节点在容错能力上没有优势,却增加了网络开销和复杂度。 | etcd 部署 4 节点,允许 1 节点故障,与 3 节点相同;但若 2 节点故障,集群不可用(4 节点需 3 票多数)。不如 3 节点经济。 | P1 | - | 分布式理论基石(Raft奇数节点证明) |
3.4 共识集群配置检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-COLL-08:共识集群(etcd/ZK)是否奇数节点部署,且总数不超过 7 个? | 协作域 | 集群节点越多,写入性能越低(需要多数派确认)。Raft 推荐 3 或 5 节点。 | 部署 9 个 etcd 节点,写请求需等待 5 个节点确认,延迟高,且网络分区概率增大。 | P1 | - | 分布式理论基石(Raft性能) |
CHK-COLL-09:etcd 是否配置了 --quota-backend-bytes 磁盘容量告警,防止 DB 大小超限进入只读? | 协作域 | etcd 默认有存储限制(2GB),达到后变为只读,整个 K8s 集群将无法变更。 | 集群因大量 ConfigMap/Secret 导致 etcd DB 达到 2GB 上限,只读,所有 Deployment 更新挂起,导致线上故障。 | P0 | 第5篇(容量规划) | K8s生产化运维深度(etcd运维) |
etcd 配置建议:
# 限制存储大小并设置告警
--quota-backend-bytes=8589934592 # 8GB
--auto-compaction-mode=periodic
--auto-compaction-retention=1h
# Prometheus 告警:etcd_mvcc_db_total_size_in_bytes / etcd_server_quota_backend_bytes > 0.8
协作评审检查清单汇总:共 9 条,P0 级 5 条,P1 级 4 条。
4. 存储评审检查清单
存储是分布式系统的基石,也是最容易出现性能瓶颈和数据不一致的地方。分片、缓存、冷热分离、多租户隔离等任何一个细节的疏忽,都可能导致生产级灾难。本章给出13条检查清单。
4.1 分片键合理性检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-STOR-01:分库分表的分片键是否是 80% 以上核心查询(包括关联查询)的 WHERE 条件或路由条件? | 存储域 | 如果分片键不在查询条件中,会导致全分片广播(Scatter-Gather),丧失分库分表的线性扩展能力,成为性能瓶颈。详见分布式数据架构第1篇。 | 使用 order_id 分片,但运营后台经常按 user_id 或 create_time 跨片查询,导致所有分片都执行该 SQL,CPU 飙高,DB 连接池耗尽。 | P0 | 第3篇(数据密集型) | 分布式数据架构(第1篇分片键设计) |
| CHK-STOR-02:分片键的基数(区分度)是否远大于分片数(通常建议 > 分片数 × 10)? | 存储域 | 分片键基数过低会导致严重的数据倾斜,热点分片成为瓶颈。 | 使用 status 字段(只有 0,1,2 三种值)分片,90% 的流量打在 status=1 的分片上,该分片 CPU 长期 100%,而其他分片空转。 | P0 | 第5篇(容量规划) | 分布式数据架构(第1篇分片倾斜) |
CHK-STOR-03:分片数是否基于未来 3 年的容量规划计算?公式:总预估数据量 / 单分片舒适容量 × 1.3。 | 存储域 | 初期分片太少,后期扩容需迁移大量数据,影响服务;初期分片太多,造成资源浪费和复杂性。 | 初创团队按当前 100 万数据设置 4 个分片,一年后数据量 5000 万,单分片过大,查询变慢。扩容时不得不停机迁移。 | P1 | 第5篇(容量规划) | 分布式数据架构(扩容方案) |
正确分片键选择示例:
-- 以电商订单为例,核心查询:买家查自己的订单、卖家查店铺订单、系统按订单号查
-- 买家端:SELECT * FROM order WHERE user_id = ? AND create_time > ?
-- 卖家端:SELECT * FROM order WHERE shop_id = ? AND status = ?
-- 系统端:SELECT * FROM order WHERE order_id = ?
-- 因此,user_id 作为分片键覆盖买家 90% 查询,shop_id 作为二级分片或路由表
-- 实际采用 user_id 分库分表,shop_id 查询通过异构索引或旁路表解决
4.2 缓存一致性检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-STOR-04:缓存刷新方案(Cache-Aside / Write-Through / Write-Behind)是否与业务对不一致窗口的容忍度匹配? | 存储域 | 不同的缓存策略带来的最终一致性窗口不同。金融账户信息要求强一致,不适合最终一致缓存。 | 账户余额使用 Cache-Aside,先更新 DB,再删 Redis。若删 Redis 失败,缓存中仍是旧值,用户看到错误余额。 | P0 | 第3篇(缓存模式) | 分布式数据架构(第6篇缓存策略) |
| CHK-STOR-05:缓存 TTL 是否加上了随机值(如 ±10%),防止缓存雪崩? | 存储域 | 所有缓存同一时刻过期,瞬时大量请求穿透到 DB,可能瞬间压垮 DB。随机化 TTL 将过期时间均匀分散。 | 首页缓存 TTL 全部设为 300s,每天凌晨 0 点集中过期,20 万请求同时打到 DB,主库瞬间负载 100%,触发主从切换。 | P0 | 第4篇(故障雪崩) | 分布式数据架构(缓存雪崩防护) |
| CHK-STOR-06:是否配置了缓存穿透(布隆过滤器 / 缓存空值)、缓存击穿(互斥锁 / 逻辑过期)的防御方案? | 存储域 | 穿透:查询不存在的数据,绕过缓存直接打 DB;击穿:热点 key 过期瞬间大量请求打 DB。都需要防护。 | 恶意攻击用随机 ID 查询商品,绕过缓存,直接打到 DB 引发 CPU 飙高。 | P1 | 第4篇(故障传播) | 分布式数据架构(缓存穿透/击穿) |
正确配置示例:
// 缓存空值防止穿透
if (value == null) {
redisTemplate.opsForValue().set(key, "null", 60, TimeUnit.SECONDS);
return null;
}
// 互斥锁防止击穿
String lockKey = "lock:product:" + productId;
if (redisTemplate.opsForValue().setIfAbsent(lockKey, "1", 10, TimeUnit.SECONDS)) {
try {
// 查DB,写缓存
} finally {
redisTemplate.delete(lockKey);
}
} else {
Thread.sleep(50);
return getFromCache(key);
}
4.3 冷热分离安全检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
CHK-STOR-07:冷数据迁移工具(如 pt-archiver、DataX)是否配置了限速参数(如 --max-lag、--limit),避免影响主库? | 存储域 | 批量 DELETE 或 SELECT 会产生大量 Binlog,导致从库延迟;全表扫描会占用主库 IO。 | pt-archiver 未设置 --max-lag,大量 DELETE 产生 Binlog 洪峰,从库延迟飙升到 300s,影响所有读服务。 | P0 | 第5篇(数据迁移) | 分布式数据架构(第5篇冷热分离) |
CHK-STOR-08:Elasticsearch ILM(Index Lifecycle Management)冷阶段迁移前是否执行了 forcemerge 以回收段空间,且迁移索引是否调整了副本数? | 存储域 | forcemerge 能减少冷数据的段数,节省存储和查询开销;调整副本数可降低存储成本。 | 未 forcemerge,冷索引有 100 个段,占用 2 倍于热索引的磁盘,查询性能也差。 | P1 | - | 分布式数据架构(ES运维) |
| CHK-STOR-09:冷数据查询的响应时间是否满足业务 SLO?若冷存储为对象存储,延迟可能数百毫秒,业务能接受吗? | 存储域 | 将冷数据迁移到 S3/OSS 后,查询延迟从毫秒级变成秒级,必须与产品确认。 | 用户查询 3 个月前的订单,因冷存储延迟 3s,页面超时空白,引发投诉。 | P1 | 第5篇(SLO) | 分布式数据架构(冷查询优化) |
4.4 多租户隔离强制检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-STOR-10:多租户共享表方案,是否使用了 PostgreSQL RLS(行级安全)或 MySQL 视图 + DEFINER 强制过滤,而不是仅依赖应用层手动追加 WHERE tenant_id? | 存储域 | 应用层过滤极易因开发疏忽或 ORM 逃逸导致跨租户数据泄露。数据库层强制过滤(RLS)是最后一道防线。详见分布式数据架构第3篇。 | 开发写了一个原生 SQL 忘记加 tenant_id = ?,导致租户 A 的报表服务看到了租户 B 的财务数据,严重数据泄露事故。 | P0 | 第2篇(安全第一) | 分布式数据架构(第3篇多租户隔离) |
CHK-STOR-11:若使用 PostgreSQL RLS,连接池在归还连接前是否执行了 RESET ROLE 或 DISCARD ALL,防止上下文污染? | 存储域 | RLS 依赖 current_setting('app.tenant_id'),如果连接复用时未清理,下一个请求可能沿用上一个请求的租户上下文。 | 连接池复用导致租户上下文残留,请求 A 设置的 tenant_id=1 被请求 B 误用,B 看到了 A 的数据。 | P0 | - | 分布式数据架构(连接池上下文管理) |
正确配置示例(PG RLS):
-- 开启 RLS
ALTER TABLE orders ENABLE ROW LEVEL SECURITY;
-- 创建策略:只有 tenant_id 匹配当前设置的行才可见
CREATE POLICY tenant_isolation ON orders
USING (tenant_id = current_setting('app.tenant_id')::integer);
-- 应用在获取连接时设置
SET app.tenant_id = '123';
-- 归返连接池前重置
RESET app.tenant_id;
4.5 数据同步链检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-STOR-12:MySQL → Debezium → Kafka → Sink (ES/ClickHouse/Redis) 的 CDC 数据同步链中,每个环节的延迟(SecondsBehindMaster, Consumer Lag)是否配置了监控告警? | 存储域 | 同步链任意环节堵塞会导致整个数据链路阻塞,搜索引擎或缓存中的数据严重滞后,影响业务决策。 | Debezium 因解析大事务卡住,SecondsBehindMaster 达到 10 分钟,导致搜索商品索引无最新上架商品,运营投诉。 | P1 | 第5篇(数据链路) | 分布式数据架构(CDC链路监控) |
| CHK-STOR-13:Sink 端是否具备幂等写入能力,以处理 Kafka 的消息重复或回溯? | 存储域 | Kafka 不保证 exactly-once,Sink 端必须能容忍重复消息。 | Kafka Consumer commit 失败导致消息重复消费,ES 中同一文档被重复索引,导致数据不一致。 | P1 | 第2篇(幂等) | 分布式数据架构(数据同步幂等) |
存储评审检查清单汇总:共 13 条,P0 级 6 条,P1 级 7 条。
5. 治理评审检查清单
治理是分布式系统的免疫系统。没有熔断降级、合理的探针、分级的告警和全链路追踪,系统在高压或故障下将盲目运行,直至崩溃。本章给出14条检查清单。
5.1 熔断降级覆盖检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-GOV-01:所有外部依赖(数据库、缓存、MQ、第三方 API)是否配置了熔断器(Sentinel DegradeRule / Resilience4j CircuitBreaker)? | 治理域 | 熔断器能快速失败,避免调用方线程因等待不可用依赖而耗尽,阻断故障扩散。详见第2篇“优雅降级”原则与第4篇故障传播链。 | 推荐服务依赖的 Redis 挂了,未熔断,调用推荐服务的订单服务线程池全部阻塞等待 Redis 超时,进而订单服务不可用,全链路雪崩。 | P0 | 第2篇/第4篇 | 高并发与稳定性工程(Sentinel/Resilience4j) |
| CHK-GOV-02:对于每个熔断降级点,是否有经过验证的兜底逻辑(Fallback),且兜底数据(如空列表、缓存旧值、默认值)是否不会破坏业务逻辑? | 治理域 | 没有兜底逻辑的熔断会直接返回错误,用户体验差。而设计不当的兜底可能导致逻辑错误(如降级返回了过期的库存)。 | 熔断后直接返回 null,前端显示“系统错误”,不如返回缓存的首页数据。 | P1 | 第2篇(降级) | 高并发与稳定性工程(降级策略) |
| CHK-GOV-03:降级逻辑是否进行了分级?如核心服务(下单、支付)不允许降级或仅允许静态化降级,非核心服务(推荐、广告)可大幅降级。 | 治理域 | 无差别降级可能导致核心业务流程中断。 | 支付服务依赖风控,风控不可用时降级为直接返回错误,导致支付全部失败,业务中断。 | P0 | 第2篇(权衡) | 高并发与稳定性工程(降级分级) |
Sentinel 熔断配置示例:
// 对商品详情接口配置慢调用比例熔断
DegradeRule rule = new DegradeRule("getProductDetail")
.setGrade(CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType())
.setCount(0.5) // 慢调用比例阈值 50%
.setTimeWindow(10) // 熔断时长 10s
.setMinRequestAmount(10)
.setSlowRatioThreshold(1000); // 最大 RT 1000ms
DegradeRuleManager.loadRules(Collections.singletonList(rule));
5.2 探针配置合理性检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-GOV-04:Kubernetes livenessProbe 的超时时间是否大于 GC 最大停顿时间 × 2? | 治理域 | 若探针超时小于 GC 停顿,Kubelet 会误判 Pod 不健康,频繁重启,加重负载。推导见第4篇时间参数传递链。 | livenessProbe timeout=2s,CMS GC 停顿 3s,导致 Pod 被重启,重启后重新加载缓存,又引发大量 GC,形成“死亡循环”。 | P0 | 第4篇(探针推导) | JVM 深度调优(GC时间) / K8s生产化运维深度(探针) |
| CHK-GOV-05:initialDelaySeconds 是否大于应用启动时间(含依赖初始化、缓存预热)? | 治理域 | 若启动未完成就开始探针,会导致 Pod 反复就绪失败,延长发布甚至无法发布。 | 应用启动需 60s,initialDelaySeconds 设置为 30s,readinessProbe 连续失败,Pod 被标记为 NotReady,最终发布超时回滚。 | P1 | 第4篇(启动时间) | K8s生产化运维深度(启动优化) |
| CHK-GOV-06:failureThreshold 和 periodSeconds 的乘积是否合理?是否能在短暂抖动后自动恢复而不是立即杀死 Pod? | 治理域 | 过于敏感的探针会导致 Pod 频繁重启,不稳定的服务变得更不稳定。 | 设置 failureThreshold=1, periodSeconds=5,一次短暂的 CPU 飙升导致探针失败,Pod 被 Kill,流量中断。应设置为 failureThreshold=3。 | P1 | 第4篇(时间参数) | K8s生产化运维深度(探针调优) |
正确探针配置示例:
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 90 # 应用启动 90s 后开始探测
periodSeconds: 10
timeoutSeconds: 5 # 预估 GC 最大停顿 2s,5 > 2*2
failureThreshold: 3 # 连续 3 次失败才认为不健康
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080
initialDelaySeconds: 60 # 启动后 60s 开始就绪检查
periodSeconds: 5
failureThreshold: 3
5.3 告警分级与响应检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-GOV-07:告警是否按照 P0(电话+5min响应)、P1(即时通讯+15min响应)、P2(邮件+1h响应)进行了明确分级? | 治理域 | 告警不分级会导致“告警疲劳”,要么淹没人,要么没人重视。 | 所有告警统一用邮件通知,凌晨 3 点数据库主从同步延迟 P0 告警无人知晓,直到早上用户投诉才发现。 | P0 | 第2篇(可观测性) | 高并发与稳定性工程(告警体系) |
| CHK-GOV-08:告警规则是否配置了抑制策略和静默期,防止告警风暴? | 治理域 | 一个大范围故障可能瞬时产生数百条告警,将值班人员淹没,无法快速定位根因。需要将同类告警聚合,或在特定维护窗口静默。 | 一个交换机故障导致 50 个服务不可用,产生 500 条告警短信,值班手机被打爆,错过了真正的核心网络故障告警。 | P1 | - | 高并发与稳定性工程(告警抑制) |
CHK-GOV-09:是否存在误报防范机制?如 Prometheus 的 for 持续时间,避免瞬时抖动触发告警。 | 治理域 | CPU 瞬间 100% 很正常,如果立刻告警会徒增干扰。 | 平均负载瞬间飙高,立即触发告警,响应人员上线后发现早已恢复,数次后变得麻木。 | P1 | - | Prometheus/Alertmanager 最佳实践 |
Prometheus 告警规则示例(带 for):
groups:
- name: critical
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status="500"}[5m]) > 0.05
for: 5m # 持续 5 分钟才触发
labels:
severity: P0
annotations:
summary: "服务 {{ $labels.instance }} 错误率高于 5%"
5.4 全链路追踪检查(2条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-GOV-10:日志中是否包含了 TraceId,并且 TraceId 在 Gateway 生成,通过 HTTP Header / Dubbo Attachment / Kafka Header 全链路传递? | 治理域 | TraceId 是将一次分布式调用串联起来的唯一标识。没有它,故障排查如同大海捞针。详见第2篇“可观测性内置”原则。 | 一次用户投诉的慢请求,因无 TraceId,需要跨 5 个服务、数十个节点上按时间戳人肉关联日志,耗时 2 小时。 | P0 | 第2篇(可观测性) | SkyWalking/Jaeger 集成 |
| CHK-GOV-11:是否能够通过 TraceId 在 SkyWalking 或 Jaeger 等 APM 平台中,快速检索到一次完整的调用链,并看到每个 Span 的耗时和状态? | 治理域 | 仅有 TraceId 还不够,需要 APM 自动采集和聚合。 | 日志中有 TraceId,但 APM 未集成,仍需手动 grep 拼接,效率低下。 | P1 | - | SkyWalking 最佳实践 |
Spring Boot 中集成 SkyWalking 并传递 TraceId:
// 通过 SkyWalking agent 自动注入,只需在启动参数加
-javaagent:skywalking-agent.jar -Dskywalking.agent.service_name=order-service
// 在日志配置中使用 %tid 打印 TraceId(SkyWalking 自动替换)
// logback.xml: [%tid] %msg%n
5.5 安全配置检查(3条)
| 检查项 | 所属维度 | 设计原理 | 违反后果 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|---|
| CHK-GOV-12:K8s RBAC 是否遵循最小权限原则?每个 ServiceAccount 仅授予所需 verbs 和 resources。 | 治理域 | 如果 Pod 拥有过高权限,一旦容器被攻破,攻击者可操作整个集群。 | 一个 Web 应用的 ServiceAccount 被绑定了 cluster-admin 角色,攻击者通过 RCE 获取了该 Pod 的 Token,进而删除了所有 namespace。 | P0 | 第5篇(部署安全) | K8s生产化运维深度(RBAC最佳实践) |
| CHK-GOV-13:Istio 是否开启了 mTLS(PeerAuthentication STRICT 模式)? | 治理域 | mTLS 保证服务间通信加密并强制双向身份认证,防止中间人攻击和未授权访问。 | 未启用 mTLS,攻击者窃听到 K8s 网络中的一个 Pod 发送的明文 JWT Token,伪造身份调用内部服务。 | P0 | 第5篇(通信安全) | Istio/K8s运维安全 |
| CHK-GOV-14:数据库密码、API 密钥是否通过 K8s Secret 挂载或外部 Vault 管理,而没有硬编码在配置文件中? | 治理域 | 配置文件中硬编码密码极易泄露到代码仓库,造成安全事故。 | 代码仓库被误公开,数据库密码硬编码在 application.yml 中,导致数据库被拖库。 | P0 | 第2篇(安全第一) | K8s生产化运维深度(Secret管理) |
治理评审检查清单汇总:共 14 条,P0 级 7 条,P1 级 7 条。
6. 评审报告模板与基线设定
6.1 架构评审报告模板
评审报告是评审活动的最终产出物,必须归档并作为架构基线。以下为可直接填写的 Markdown 模板:
# 架构评审报告
## 一、评审对象
- **系统名称**:电商订单核心链路
- **评审日期**:2026-05-18
- **参与人员**:张架构(评审组长)、李开发、王SRE、赵产品
- **当前架构版本**:v3.2.0
- **评审类型**:[ ] 新系统上线 [x] 大版本迭代 [ ] 季度定期评审 [ ] 故障后专项评审
## 二、评审范围与业务目标
- **评审覆盖的能力域**:通信域(RPC调用链、消息队列)、协作域(分布式锁、事务)、存储域(分库分表、缓存)、治理域(熔断、监控)
- **本次评审范围聚焦**:下单→支付→库存扣减的核心事务链路
- **业务目标**:支撑双十一峰值 10万 TPS,下单 P99 延迟 < 1s,支付成功率 > 99.99%
- **非功能性目标**:可用性 99.97%,无单点故障,数据强一致,可监控可追踪
## 三、架构评审四维检查清单执行情况
### 3.1 通信评审 (13条)
- [x] CHK-COMM-01 调用链闭环 ...
- [ ] CHK-COMM-03 超时传递链 ...
- **发现问题**:Gateway 超时 4s < OrderService 3s + InventoryService 2s
- **风险等级**:P0
- **整改建议**:调整 Gateway 超时至 8s,见附件配置
### 3.2 协作评审 (9条)
- [x] CHK-COLL-01 FencingToken ...
- [ ] ...
### 3.3 存储评审 (13条)
- [ ] ...
### 3.4 治理评审 (14条)
- [ ] ...
## 四、问题清单
| 编号 | 维度 | 违反检查项 | 问题描述 | 风险等级 | 责任人 | 修复期限 | 当前状态 |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| ISS-01 | 通信 | CHK-COMM-03 | Gateway 超时 < 下游和 | P0 | 李开发 | 2026-05-25 | 未修复 |
| ISS-02 | 协作 | CHK-COLL-04 | 支付事务使用 Saga 不满足强一致 | P0 | 张架构 | 2026-06-01 | 未修复 |
| ISS-03 | 存储 | CHK-STOR-05 | 缓存 TTL 未随机化 | P1 | 王SRE | 2026-05-30 | 未修复 |
| ISS-04 | 治理 | CHK-GOV-07 | 告警未分级,全部邮件 | P0 | 王SRE | 2026-05-22 | 已修复 |
## 五、评审结论
- [ ] 通过
- [x] 有条件通过(存在 P0 问题 3 项,必须修复后二次评审;P1 问题 2 项可上线后限期修复)
- [ ] 不通过(存在未解决的 P0 阻塞问题,禁止上线)
## 六、整改跟踪与二次评审
- **二次评审时间**:2026-05-28
- **验证结果**:ISS-01/02/04 已修复并验证通过,ISS-03 风险可接受,允许上线。
## 七、架构基线更新
- **本次建立的基线文件**:`architecture-baseline-v3.3.0.md`
- **主要变更**:修正了超时配置树,支付事务更换为 AT 模式,补充了告警分级规则。
- **下次季度评审预约**:2026-08-18
6.2 评审基线设定与闭环
基线设定:首次完整评审后,产出一份架构基线文档,包含所有已通过的检查项状态、已知但已接受的风险(如某个分片键无法覆盖的查询需手动拼接)、以及当时的容量规划数据。后续任何一次架构变更(扩容、升级、增加新服务)都必须参照基线进行增量评审,并更新基线。
故障复盘与检查清单的双向反馈:每次生产故障复盘后,必须执行一个标准步骤:“该故障是否能够被现有架构评审检查清单所捕获?”
- 若可以,但评审时未发现,则加强评审执行力度或工具化(如引入自动化架构验证工具)。
- 若不能,则将该故障的根因提炼为一条新的检查项,补充到清单中,并标注来源故障。这样,检查清单将随着系统成长而演化,成为团队血泪教训的积累。
7. 架构演进策略与技术债务管理
架构不是一成不变的,它随着业务增长、数据量膨胀、技术栈升级而演进。评审清单也必须随着演进阶段的不同,动态调整检查的重点。
7.1 渐进式演进路径
下图展示了一条典型的从单体到云原生的渐进式演进路径,以及每个阶段的标志性技术动作和评审触发点。
flowchart TD
A["单体应用"] -->|"垂直拆分<br/>按业务边界拆服务"| B["微服务初阶"]
B -->|"异步解耦<br/>引入消息队列"| C["事件驱动架构"]
C -->|"数据增长<br/>分库分表/缓存"| D["数据密集型架构"]
D -->|"容器化与弹性<br/>迁移至K8s/Istio"| E["云原生架构"]
A -.->|"评审触发点<br/>逻辑清晰度"| A1["重点:业务边界<br/>模块间调用"]
B -.->|"评审触发点<br/>通信与治理"| B1["重点:RPC超时/重试<br/>熔断限流"]
C -.->|"评审触发点<br/>数据一致性与幂等"| C1["重点:MQ死信/幂等<br/>最终一致性"]
D -.->|"评审触发点<br/>存储架构"| D1["重点:分片键/缓存<br/>冷热多租户"]
E -.->|"评审触发点<br/>基础设施与安全"| E1["重点:探针/资源限制<br/>mTLS/HPA"]
图4:架构演进路径与各阶段评审重点
- 图表主旨概括:展示了分布式系统架构演进的五个典型阶段,并标注了每个阶段引入新组件或新模式时,架构评审需要特别关注的检查域。
- 逐层分解:
- 单体 → 微服务初阶:拆服务引入 RPC 调用,通信评审(超时、幂等)和治理评审(熔断)成为重点。此时存储层可能仍是单库,但服务间调用链开始形成。
- 微服务初阶 → 事件驱动:引入 MQ 实现异步解耦,协作评审(最终一致性、死信处理)和通信评审(消息幂等)成为关键。
- 事件驱动 → 数据密集型:数据量驱动分库分表、引入 Redis、ES 等,存储评审(分片键、缓存一致性、冷热分离)成为核心。
- 数据密集型 → 云原生:迁移至 K8s,治理评审(探针、资源配额、HPA、mTLS、监控告警)和基础设施安全上升为 P0 关注点。
- 设计原理映射:此演进路径是“渐进式交付”思想的体现,避免一步到位引入全部复杂度。每次演进只引入当前瓶颈急需的解决方案,评审也随之聚焦新增的风险域。
- 工程联系与关键结论:切勿试图从单体一步跳至云原生。每次架构演进都是一次重大变更,必须触发一次完整的四维架构评审,尤其关注新旧组件交互产生的风险。
7.2 技术债务的分级与管理
技术债务是架构评审中必须诚实面对的部分。我们将债务按影响程度分为三级:
| 债务级别 | 定义 | 示例 | 偿还策略 |
|---|---|---|---|
| L1 (Critical) | 影响系统可用性或数据安全,必须立即偿还 | 未配置熔断降级;日志无 TraceId;硬编码密码;无分片键广播查询 | 当前迭代暂停新功能,紧急修复,P0 级别。 |
| L2 (High) | 严重影响开发效率、可维护性或存在潜在稳定性风险 | 服务间共享数据库;硬编码配置散落各处;重复的样板代码;缺失单元测试 | 规划在接下来 1-2 个迭代中偿还,与业务需求并行。 |
| L3 (Moderate) | 影响未来扩展性和技术栈先进性,但不阻塞当前业务 | 分片键不利于未来扩容;使用了过时的库;部分模块未容器化 | 列入技术规划 backlog,在季度技术优化 Sprint 中安排,不紧急。 |
技术债务偿还策略:
- 时间分配:每个迭代(Sprint)预留 20% 的时间专门用于偿还技术债务,防止债务无限累积。
- 大促前集中偿还 L1:每次大促(如双十一、618)前一个半月左右,进行专项压测和架构评审,集中修复所有 L1 级债务,确保系统以最健康的状态迎接流量高峰。
- 淡季大版本升级:利用业务淡季,进行需要停机或重写的大版本升级(如分片扩容、K8s 迁移、JDK 升级),偿还 L3 债务。
8. 全系列知识地图与后续系列索引
这是本系列的收官,也是整个分布式知识体系的起点。下面这张知识地图,将你已掌握的知识(本系列6篇)与你即将探索的广阔领域(后续6个系列)关联起来,形成一张可导航的认知网。
8.1 全系列知识地图
flowchart TD
subgraph "<b>本系列:分布式系统架构认知与设计</b>"
P1["第1篇<br>核心模型与分层架构"]
P2["第2篇<br>设计原则与权衡哲学"]
P3["第3篇<br>通用架构模式"]
P4["第4篇<br>时间维度与故障传播"]
P5["第5篇<br>设计流程与实战推演"]
P6["第6篇<br>架构评审与检查清单"]
end
subgraph "<b>后续系列 1-3</b>"
T1["分布式理论基石<br>CAP/BASE/共识/锁/ID"]
T2["分布式事务工程实践<br>XA/TCC/Saga/AT 源码与方案"]
T3["分布式数据架构与存储选型<br>分库分表/缓存/搜索/列存/冷热/多租户"]
end
subgraph "<b>后续系列 4-6</b>"
T4["JVM 深度调优与高性能编程<br>GC/内存/线程/性能基准"]
T5["高并发与稳定性工程<br>限流/熔断/降级/压测/SLO/监控"]
T6["Kubernetes 生产化运维深度<br>调度/网络/存储/安全/Operator"]
end
P1 --> P2 --> P3 --> P4 --> P5 --> P6
P6 -.->|"通信检查项"| T1 & T2
P6 -.->|"协作检查项"| T1 & T2
P6 -.->|"存储检查项"| T3
P6 -.->|"治理检查项"| T5 & T6
P6 -.->|"JVM检查项"| T4
P1 -.-> T1
P3 -.-> T2
P4 -.-> T5
P5 -.-> T6
classDef main fill:#f0f4ff,stroke:#4f6ef6,stroke-width:2px,color:#1e3a8a
classDef theory fill:#f3e8ff,stroke:#9333ea,stroke-width:2px,color:#581c87
classDef eng fill:#ecfdf5,stroke:#059669,stroke-width:2px,color:#064e3b
class P1,P2,P3,P4,P5,P6 main
class T1,T2,T3 theory
class T4,T5,T6 eng
图5:全系列知识地图
- 图表主旨概括:以本系列第六篇的检查清单为“评审入口”,辐射连接后续六个系列。读者学完某个专项系列后,可以回查本文对应的检查项验证理解。
- 逐层/逐元素分解:
- 中心枢纽:本文(第6篇)是连接理论与实践、总纲与细节的枢纽。所有检查项都标注了其在后续系列中的详细论述篇号。
- 后续系列与检查项的映射:
- 分布式理论基石:提供分布式锁正确性证明、共识算法、分布式 ID 生成等理论基础,对应本文协作域和通信域部分检查项。
- 分布式事务工程实践:深入 Seata AT/TCC/Saga 源码及最佳实践,对应协作域事务匹配和超时检查项。
- 分布式数据架构:详尽阐述分片、缓存、搜索、冷热、多租户等方案,直接对应存储域全部检查项。
- JVM 深度调优:GC 调优、线程模型,直接影响超时设置、探针配置和系统稳定性,对应治理域探针检查和性能基座。
- 高并发与稳定性工程:Sentinel/Resilience4j、全链路压测、监控告警体系,对应治理域熔断降级、限流、告警检查项。
- Kubernetes 生产化运维:Pod 调度、网络策略、RBAC、HPA、安全上下文,对应治理域探针、安全、资源检查项。
- 设计原理映射:知识地图遵循“先全局认知(本系列),再专项深入(后续系列),最后回到全局评审(本文)”的学习曲线。符合从整体到局部再回到整体的认知规律。
- 工程联系与关键结论:建议的学习路径:本系列(总纲)→ 理论基石 → 事务 → 数据架构 → JVM → 高并发 → K8s → 回读本系列第6篇。当你学完每个专项系列,你就能理解本文中相应检查项背后的深层原理,届时你不仅是一个会评审的架构师,更是一个能亲手实现和调优这些机制的工程师。
9. 面试高频专题
9.1 分布式系统架构评审的核心目的是什么?评审的四个维度各自关注什么?
一句话回答:核心目的是系统化识别架构风险、验证设计决策与业务目标一致性、建立架构基线;四个维度分别关注服务通信(调用链、超时)、服务协作(锁、事务)、数据存储(分片、缓存)和系统治理(熔断、监控)。
详细解释: 架构评审不是找茬,而是防止生产事故的最后一道工程防线。其核心目的有三:第一,风险识别——在系统上线前或重大变更前,找出那些在代码审查和功能测试中难以发现的架构级缺陷,如超时配置不满足传递链导致的重试风暴。第二,决策验证——确保技术选型不是基于个人喜好,而是服务于业务对一致性、性能的要求,例如转账场景必须使用 TCC 而非 Saga。第三,基线建立——为系统建立架构健康度快照,便于后续演进和故障复盘。
评审的四个维度是从能力域×分层矩阵中抽象出来的:通信评审关注服务间调用的正确性与韧性(超时、重试、幂等、死信);协作评审关注分布式协同机制的安全性与可用性(锁的互斥性、事务一致性、选主时间);存储评审关注数据架构的性能、隔离与成本(分片键、缓存策略、冷热数据、多租户隔离);治理评审关注系统的可观测性、弹性与安全(熔断降级、探针、告警分级、全链路追踪、安全配置)。四维评审缺一不可,生产事故往往是多维度风险耦合的结果。
多角度追问:
- 问:为什么说评审必须基于检查清单而非个人经验? 答:人的工作记忆有限,即使是资深架构师也可能在压力下遗漏检查项。检查清单保证了评审的一致性和完整性,避免犯“无能之错”。《清单革命》中已经论证,在复杂领域,清单是减少人为疏漏的有效工具。
- 问:评审四个维度和能力域×分层矩阵的具体映射关系是什么? 答:通信评审主要对应服务层×通信格;协作评审对应服务层×协作格和数据层×协作格;存储评审对应数据层×存储格;治理评审横跨接入层×治理格、服务层×治理格和基础设施层×治理格。这种矩阵映射确保评审无死角覆盖。
- 问:架构评审和代码审查(Code Review)有什么区别? 答:代码审查关注实现细节、代码风格、逻辑错误,属于微观层面;架构评审关注系统整体结构、组件交互、非功能性需求,属于宏观层面。两者互补,架构评审通常在新项目启动、大版本迭代或故障后触发,而代码审查是日常开发活动。
加分回答:
- 学术观点:Richard P. Gabriel 的“Worse is Better”哲学提醒我们,架构评审应避免过度追求完美而牺牲实用性。评审应聚焦于真正可能导致系统崩溃的 P0/P1 风险,而非无止境地的技术洁癖。
- 业界实践:Netflix 的 Architecture Review Process 强调“上下文而非控制”,评审小组提供建议而非强制命令,团队最终负责决策。这种文化鼓励创新,同时保持系统整体健康。
9.2 通信评审中最关键的检查项有哪些?为什么超时传递链必须满足“上游 > 下游之和”?
一句话回答:最关键的检查项包括调用链闭环、超时传递链、重试幂等和死信处理;超时传递链不满足会导致网关提前断开连接,而服务端仍在处理请求,造成资源浪费和数据不一致。
详细解释: 通信评审中最容易导致 P0 级事故的检查项有:
- 调用链闭环:存在 A→B→C→A 的循环依赖,一旦 C 超时,重试会沿环路放大,形成重试风暴。
- 超时传递链:如果 Gateway 的超时小于所有下游服务超时之和,当总处理时间接近 Gateway 超时时,Gateway 会立即断开客户端连接并返回 504,但服务端仍在继续执行请求,可能导致幽灵订单(订单创建了但用户以为失败再次提交)或数据不一致。
- 重试幂等:非幂等的写操作在重试时会导致重复扣款、重复发货等严重问题。
- 死信处理:消息重试耗尽后若无死信队列,消息永久丢失,业务流程中断。
超时传递链是防止级联超时的基石。正确配置要求每一层上游的超时时间必须大于其调用的所有下游服务的超时时间总和(加上网络及序列化开销)。例如:Gateway 6s > OrderService 2.5s + InventoryService 1.5s。验证方法是从最上游开始,逐层向下检查每个服务的超时配置,构建超时配置树,确保不等式处处成立。
多角度追问:
- 问:如果不满足传递链,除了网关超时外,还会有什么后果? 答:还会导致资源浪费:下游服务还在处理一个上游已经放弃的请求,消耗数据库连接、线程等资源。更危险的是,如果下游服务已经提交了本地事务但上游认为失败,就产生了数据不一致。
- 问:Dubbo 的超时和重试机制如果配置不当,会如何加剧这个问题? 答:Dubbo 默认失败自动重试(retries=2),如果超时设置过短,正常请求被误判超时并重试,导致下游短时间内收到 3 倍请求,可能瞬间压垮服务。
- 问:如何实现超时配置的自动化验证? 答:可以使用配置中心(Nacos/Apollo)集中管理超时配置,并编写一个验证脚本,读取所有服务的超时值,自动构建调用链超时不等式并报警。
加分回答:
- 源码细节:Spring Cloud Gateway 的
HttpClient基于 Netty,其超时通过response-timeout实现,如果上游超时断连,会发送 RST 包,后端服务若用 Tomcat 会抛出ClientAbortException。 - 业界实践:Google SRE 建议使用“自适应超时”和“对冲请求”(Hedged Requests)来应对尾延迟,即当请求超过一定阈值未返回时,向另一台服务器发送相同请求,取先返回者。
9.3 协作评审中分布式锁的安全性如何检查?fencing token 为什么是必选项?
一句话回答:安全性检查需确认锁有防死锁(TTL + 续期)、互斥保证(fencing token)和高可用;fencing token 必选是因为 GC 停顿或网络延迟可导致锁过期被他人获取,原客户端继续写入时破坏互斥。
详细解释: 分布式锁安全性评审核心三点:
- TTL 与续期:锁的 TTL 必须大于业务最大执行时间(包括 GC 和网络),或使用 Redisson 的 watchdog 自动续期,防止业务未完成锁却释放。
- Fencing Token:这是分布式锁正确性的灵魂。即使有 watchdog,也存在极端情况:客户端 A 获取锁后发生长时间 GC 停顿(超过 TTL 且续期线程也停顿),锁被释放,客户端 B 成功获取锁并开始操作。随后 A 的 GC 结束,继续执行,如果没有 fencing token,A 会继续写入,破坏 B 的操作。Fencing token(单调递增编号)要求:锁服务在颁发锁时附带一个 token,存储系统(如数据库)在写入时校验 token,拒绝小于当前已见最大 token 的写入(类似于乐观锁版本号)。这需要数据库或存储系统的配合。
- 高可用:锁的实现避免单点,Redis Redlock 算法虽受争议,但若使用 etcd/ZooKeeper 的持久节点和顺序临时节点,可提供更强的一致性保证。
fencing token 是必选项的原因:Martin Kleppmann 在其著名的文章《How to do distributed locking》中证明,没有 fencing token,任何基于 TTL 的锁在理论上都无法保证互斥。因为暂停的进程无法自我感知暂停,也无法保证在其暂停期间锁不会过期。Fencing token 将互斥性从锁服务延伸到了存储资源层,是唯一的安全网。
多角度追问:
- 问:Redis 的红锁(Redlock)实现是否解决了 fencing token 问题? 答:Martin Kleppmann 认为没有,因为 Redis 不提供单调递增的隔离 token,且客户端无法在写入存储时附带 token。但我们可以通过 Redis 的 INCR 生成 token,并在业务表上增加 version 字段来校验,从而变通实现。
- 问:ZooKeeper 的临时顺序节点为什么天然带有 fencing token 属性? 答:ZK 的临时顺序节点会返回一个自增序号(zxid 或 cversion),可作为 token。当获取锁时获得该序号,释放时检查自己的节点是否还是最小,如果是则执行。但若要防止 GC 停顿问题,仍需将序号传递给下游存储。
- 问:在使用 Redisson 的 RLock 时,如何实现简单的 fencing?
答:可以在获取锁后,从 Redis 原子递增一个计数器作为锁的版本号,在更新 MySQL 时,使用
UPDATE table SET value = ?, version = ? WHERE id = ? AND version < ?,保证只有更高版本的写入才能成功。
加分回答:
- 学术观点:Fencing token 本质上是 Lamport 逻辑时钟的应用,提供了一种全局偏序,用版本号来仲裁并发写入。
- 源码细节:ZooKeeper 的锁食谱(Lock Recipe)中,
getChildren获取的节点名称后缀是 10 位数字序号,可以用作 token。
9.4 存储评审中分片键的选择为什么如此重要?如何验证分片键是否合理?
一句话回答:分片键决定了数据分布和查询路由,选错会导致全分片广播、数据倾斜甚至拒绝服务;合理验证要看它是否出现在核心查询 WHERE 条件中、基数是否远大于分片数、分片数是否基于容量规划。
详细解释: 分片键是分库分表的灵魂。一旦选定,后期修改代价极其高昂(全量数据迁移)。它的重要性在于:
- 路由功能:没有分片键的查询必须广播到所有分片,丧失水平扩展能力。
- 数据均匀:分片键基数低会导致严重的数据倾斜,部分节点成为热点。
- 容量可预测:分片数过少,单分片数据量可能超出 MySQL 单表舒适阈值(一般建议 2000 万行以内),性能下降;分片数过多,资源浪费,跨分片事务概率增大。
验证方法:
- 查询覆盖验证:列出系统所有 SQL,统计涉及分片键作为 WHERE 条件或 JOIN 条件的查询比例,至少应 > 80%。对于必须跨片的查询,必须有异构索引表或旁路方案。
- 区分度验证:
SELECT COUNT(DISTINCT shard_key) FROM table计算基数,应 > 分片数 × 10(例如 8 分片需要至少 80 个不同的值)。使用status这种只有几个枚举值的字段绝对不行。 - 容量公式验证:预估未来 3 年数据量,除以单分片舒适容量(如 1000 万),再乘以冗余系数 1.3,得到合理分片数。
- SQL 实际执行计划验证:在测试环境使用带分片键和不带分片键的查询,通过 ShardingSphere 的 SQL 日志验证路由是否正确。
多角度追问:
- 问:订单系统常见的分片键选择有哪些?各有什么优劣?
答:买家端常用
user_id,能覆盖买家查自己订单的场景,但卖家按shop_id查就需要广播或构建反向索引。如果采用order_id基因法(如订单号后几位携带用户 ID 特征),可以兼顾两者,但需要额外设计。 - 问:如果必须支持多种维度的跨片查询,有什么架构方案? 答:可以通过 CQRS 模式,将数据实时同步到 Elasticsearch 或 ClickHouse 中,由这些引擎提供多维度搜索查询,而 MySQL 仅负责基于分片键的在线事务查询(主键/唯一键查询)。
- 问:ShardingSphere-JDBC 在遇到没有分片键的查询时默认行为是什么?如何避免危险?
答:默认会广播到所有分片。可以通过
hintManager.setDatabaseShardingValue强制路由或配置default-database-strategy规则,但最佳实践是代码审查中禁止无分片键的语句,除非是在后台低频管理功能中。
加分回答:
- 设计模式:基于基因法的分片键设计,类似于将分片信息编码进主键,使得从订单 ID 可以反解出用户 ID 进行路由,这是分布式系统标识设计中的常用技巧。
9.5 治理评审中探针配置的常见错误是什么?livenessProbe 超时为什么要大于 GC 停顿 ×2?
一句话回答:常见错误是探针超时过短、启动延迟不足、失败阈值过低;livenessProbe 超时大于 GC 停顿 ×2 是为了防止 Kubelet 误判 Pod 不健康导致重启,因为 GC 停顿期间服务进程无法响应任何请求。
详细解释: Kubernetes 探针配置最常见的三种错误:
- livenessProbe 超时过短:如果超时时间(timeoutSeconds)小于 JVM GC 最大停顿时间,GC 发生时探针会超时失败,Kubelet 误以为 Pod 死锁,触发重启。重启后应用需要重新预热缓存、建立连接池,又会引发大量的 YGC/Full GC,可能再次超时,形成“循环重启”。
- initialDelaySeconds 不足:应用启动(Spring 容器加载、连接池建立、缓存预热)未完成就开始探活,连续失败导致 Pod 从不 Ready 变成 Restart,发布失败。
- failureThreshold 过小:设置为 1,一次网络波动或瞬时负载尖峰就导致容器被 Kill,系统不稳定。应设置至少 3 次失败、每次间隔 10s,给予恢复缓冲。
GC 停顿 ×2 的推导: livenessProbe 超时应大于预估的最大 GC 停顿时间的两倍,留出安全余量。因为:
- 超时是一次完整的 HTTP 请求周期,包括建立连接、发送请求、服务处理、返回响应。GC 停顿可能发生在任何一个环节。
- 如果最大停顿是 2s,超时至少 4s。并建议将
failureThreshold设为 3 或 5,这样连续多次失败才判定为不健康,确保不会因为偶发的较长 GC 误杀 Pod。 - 该值需要经过压测和 GC 日志分析得出,不应猜设。
多角度追问:
- 问:readinessProbe 和 livenessProbe 的区别是什么?配置时各自的侧重点? 答:Readiness 决定流量是否进入 Pod,失败则移出 Service;Liveness 决定 Pod 是否需要重启,失败则杀容器。Readiness 可以更频繁、更敏感,因为不涉及重启;Liveness 必须保守,防止误杀。
- 问:如何选择探针类型(HTTP / TCP / Exec)?
答:HTTP 最常用,可以验证服务内部逻辑(如
/health);TCP 仅检查端口,轻量但不准确;Exec 可以执行自定义健康检查脚本。Spring Boot Actuator 提供了/health/liveness和/health/readiness端点,推荐使用。 - 问:如何在应用层配合探针,使健康检查更准确?
答:使用 Spring Boot Actuator 的 Health Indicator,可以聚合数据库、Redis、RabbitMQ 等组件的健康状态。但注意,依赖组件的不健康不应立即导致 Pod 不健康(例如 Redis 短暂不可用),避免级联重启。可以设计为:组件不可用时返回
DOWN,但 readiness 可以配置为忽略某些组件的状态。
加分回答:
- 源码细节:Spring Boot 的
AvailabilityChangeEvent和LivenessState可以让你通过 API 手动变更活性状态。例如,当发现发生了不可恢复的 OOM 时,主动将自身标记为BROKEN,比等待探针失败更快。 - 业界实践:Google SRE 建议使用“Watchdog”模式,在应用内部启动一个定时器,如果规定时间内未重置,自动 crash,而不要依赖外部探针检测死锁。
9.6 架构评审的问题如何分级(P0/P1/P2)?每级的响应时间与修复策略是什么?
一句话回答:P0 为阻塞上线级,影响可用性、安全或数据一致性,需立即修复;P1 为强烈建议修复级,影响性能、可维护性或存在潜在风险,限时修复;P2 为建议优化级,影响成本或技术先进性,计划排期。
详细解释: 问题分级是架构评审落地的关键,必须有明确的定义和强制力。
| 级别 | 定义 | 响应时间 | 修复策略 | 示例 |
|---|---|---|---|---|
| P0 | 直接导致系统不可用、数据丢失/泄露、全链路雪崩、安全漏洞等严重生产事故 | 阻塞当前上线,立即(<24h)修复,修复后必须二次评审 | 停止新功能开发,抽调最核心工程师紧急修复 | 超时传递链违反、重试未幂等、未配置熔断、硬编码密码、未分级的告警 |
| P1 | 存在明显性能瓶颈、单点故障、可维护性差、监控盲区,虽不会立即引发事故但风险较高 | 限时在上线后 1-2 周内修复,或在下个迭代中完成 | 与业务需求并行排期,要求在 deadline 前完成 | 无死信队列监控、缓存 TTL 未随机化、连接池未隔离、TraceId 未集成到 APM |
| P2 | 技术债务、可优化点,影响开发效率或未来扩展,但当前系统可稳定运行 | 无需立即行动,排入技术规划 backlog | 在季度技术优化 Sprint 或业务淡季统一偿还 | 分片数规划不够超前、使用了略旧的库、配置文件未集中管理 |
多角度追问:
- 问:如果团队资源有限,P1 问题能不能降级为 P2? 答:不能。分级是基于风险,不是基于资源。如果风险确实是 P1,但资源不足,应如实记录风险并上报技术负责人,争取资源,或明确接受该风险并设定监控项。不能因为资源不足而修改风险等级,那会掩盖真正的问题。
- 问:P0 问题未修复是否绝对禁止上线? 答:原则上,是的。除非有 CTO 或 VP 级别的特批,并且有充分的应急预案(如手动降级、关闭该功能),否则评审组应拒绝发布。这需要公司文化支持,否则评审失去意义。
- 问:如何保证问题分级的一致性,避免主观争吵? 答:团队应事先共同定义好各级别对应的故障场景,并形成文档。评审时依据定义投票决定。例如,定义“凡可能导致数据库被拖库的为 P0”,这样就有了统一标尺。
加分回答:
- 设计模式:问题分级本身就是一种优先级排序模式(Priority Triage),源自医疗急诊的分诊制度。在工程中,它确保最宝贵的修复力量总是投入到最致命的风险上。
- 业界实践:Google SRE 的错误预算机制可以很好配合:当系统错误预算耗尽,所有与稳定性相关的 P1 问题将自动升级为 P0,强制冻结功能发布,直到稳定性恢复。
9.7 技术债务如何分级(L1/L2/L3)?如何制定合理的偿还策略?
一句话回答:L1 影响可用性/安全需立即偿还,L2 影响可维护性需 1-2 迭代偿还,L3 影响未来扩展性需排期偿还;策略是每 Sprint 留 20% 容量、大促前集中修 L1、淡季大版本升级。
详细解释:技术债务管理是架构持续健康的关键。分级标准如下:
- L1(Critical Debt):直接威胁系统安全或稳定。例如:缺失熔断降级、日志无 TraceId、未做限流。这些债务的存在,意味着系统随时可能因一个小故障崩溃。必须停下手头功能开发立即修复。
- L2(High Debt):严重影响团队开发效率或已经造成了明显的稳定性隐患,但还没到一触即溃的程度。例如:服务间共享数据库、配置文件硬编码且散落各处、单元测试缺失导致回归 bug 多。应当在未来 1-2 个迭代内完成修复,并与产品经理沟通占用部分业务容量。
- L3(Moderate Debt):为了快速上线而做出的妥协,不影响当前运行,但长远会成为瓶颈。例如:分片键不支持平滑扩容、使用了版本过时的消息队列客户端、未应用容器化。这些应放入技术 Backlog,在季度技术优化 Sprint 或大版本重构中解决。
偿还策略的核心是“制度化”:
- 20% 容量预留:每个 Sprint 划分 20% 的时间专门处理技术债务,这是敏捷开发中的常见实践,防止债务只增不减。
- 大促前集中修复 L1:大促前 6 周进行压测和债务排查,将发现的 L1 债务全部修复,确保迎战流量峰值时系统足够健壮。
- 淡季大版本升级:利用春节、夏季等业务相对低峰期,进行架构层面的 L3 债务偿还,如数据迁移、K8s 切换等需要较长时间和可能引起短暂停机的项目。
多角度追问:
- 问:如何说服产品经理同意暂停新功能去偿还技术债务? 答:用风险数据和故障案例说话。例如:“因为我们没做限流,去年双十一期间短暂崩溃 5 分钟,直接损失 XXX 万元。偿还这项债务可以避免类似损失。”将技术债务与业务风险直接挂钩。
- 问:技术债务的利息(Interest)体现在哪里? 答:债务的利息就是团队为每次变更付出的额外时间、更高的缺陷率以及更慢的上线速度。例如,共享数据库导致一次简单的字段增加需要协调三个团队修改代码、统一上线,这就是利息。
- 问:如何衡量技术债务的总量? 答:可以通过架构评审报告中的 P1/P2 问题数、代码扫描工具(SonarQube)的 Issues 数量、以及业务响应慢的原因分析中归因为技术债务的比例来粗略估算。
加分回答:
- 隐喻:Ward Cunningham 创造“技术债务”一词时,强调的是“用先发布后重构的方式学习正确的设计”,债务应是主动且有计划的,而非无意识的烂代码。评审应区分“战略性债务”和“无意的混乱”。
- 最佳实践:建立“技术债务登记册”,任何人在开发中发现的债务都可以登记,并在每次架构评审时审查。确保债务可见,是偿还的第一步。
9.8 系统设计题:电商订单系统架构评审
题目:一个电商订单系统的架构图如下:
- 接入层:Spring Cloud Gateway → 应用服务。
- 服务层:订单服务(Dubbo)→ 库存服务 / 支付服务。
- 协作:使用 Seata AT 模式保证订单创建和库存扣减的分布式事务。
- 存储:ShardingSphere-JDBC 按
user_id分 4 片,Redis Cluster 作为缓存,RocketMQ 用于异步通知(如发送下单成功短信)。 - 治理:所有服务部署在 K8s 上,使用 Istio 作为服务网格,Sentinel 做限流熔断,Prometheus + Grafana 监控,SkyWalking 做链路追踪。
- 部署:生产环境 3 节点集群,每个服务 2 个副本。
请从通信、协作、存储、治理四个维度对这套架构进行系统化评审:
- 指出至少 5 个潜在风险点(含风险等级 P0/P1/P2);
- 给出每个风险点的整改建议与优先级排序;
- 给出技术债务偿还的推荐路径;
- 提出架构演进的下一步建议。
答案
1. 架构图、业务流程与关键时序
系统架构图(Mermaid):
flowchart TB
User("用户") --> GW["Spring Cloud Gateway"]
GW --> OrderSvc["订单服务<br/>Dubbo"]
OrderSvc --> InvSvc["库存服务<br/>Dubbo"]
OrderSvc --> PaySvc["支付服务<br/>Dubbo"]
OrderSvc --> MQ["RocketMQ"]
MQ --> NotifySvc["通知服务"]
OrderSvc --> Sharding[("ShardingSphere-JDBC<br/>user_id 分片")]
InvSvc --> Redis[("Redis Cluster<br/>库存缓存")]
PaySvc --> Redis
subgraph "Kubernetes Cluster"
GW
OrderSvc
InvSvc
PaySvc
NotifySvc
end
Istio["Istio Service Mesh"] -.-> GW & OrderSvc & InvSvc & PaySvc
Sentinel["Sentinel"] -.->|"熔断降级"| OrderSvc & PaySvc
SkyWalking["SkyWalking"] -.->|"链路追踪"| OrderSvc & InvSvc & PaySvc
Prometheus["Prometheus"] -.->|"监控"| OrderSvc & InvSvc & PaySvc
classDef gateway fill:#f1f5f9,stroke:#334155,stroke-width:2px,color:#0f172a
classDef service fill:#ede9fe,stroke:#8b5cf6,stroke-width:2px,color:#3b2f4b
classDef mq fill:#fef3c7,stroke:#d97706,stroke-width:2px,color:#78350f
classDef db fill:#dbeafe,stroke:#2563eb,stroke-width:2px,color:#1e3a8a
classDef infra fill:#e2e8f0,stroke:#475569,stroke-width:2px,color:#1e293b
class GW gateway
class OrderSvc,InvSvc,PaySvc,NotifySvc service
class MQ mq
class Sharding,Redis db
class Istio,Sentinel,SkyWalking,Prometheus infra
下单业务流程时序图(简化):
sequenceDiagram
participant U as 用户
participant GW as Gateway
participant O as 订单服务
participant I as 库存服务
participant DB as ShardingSphere
participant P as 支付服务
participant MQ as RocketMQ
U->>GW: POST /order
GW->>O: createOrder()
O->>O: 生成订单ID,开启Seata AT全局事务
O->>I: deductStock(skuId, qty)
I->>I: 扣减缓存库存(Redis)
I-->>O: 扣减成功
O->>DB: INSERT INTO order ... (user_id=1001)
O->>P: createPayment(orderId, amount)
P-->>O: 支付单创建成功
O->>O: 全局事务提交
O->>MQ: 发送“订单已创建”消息
O-->>GW: 下单成功
GW-->>U: 200 OK
MQ->>Notifier: 短信/推送通知
2. 风险点识别与评审(四个维度)
通信评审:
-
风险1(P0):超时传递链未验证。图中未给出各服务超时配置。假设 Gateway 默认 3s,订单服务 Dubbo 超时 2s,库存服务 DB 操作可能 1.5s,支付服务调用外部银行接口可能 4s。显然 3s < 2s + 4s,在支付环节 Gateway 会超时断开,但订单可能已创建,支付已发起,造成数据不一致。
- 整改:必须显式定义超时树:Gateway 10s > Order 6s > max(Inventory 3s, Payment 5s)。同时 Payment 调外部银行接口应有独立线程池,且超时设置要结合对方 SLA。
-
风险2(P1):RocketMQ 消息发送无明确的死信处理与监控。通知服务可能消费失败进入死信,无告警则消息丢失。
- 整改:为每个核心 Topic 配置 DLQ,并对 DLQ 消息积压设置 P1 告警(> 10 条/15 分钟)。
协作评审:
-
风险3(P0):Seata AT 模式是否正确匹配业务?库存扣减属于强一致场景,AT 模式基于数据库本地事务+全局锁,若与 Redis 缓存扣减配合不当,可能存在一致性问题(缓存先扣减成功,DB 最终因全局锁冲突回滚,缓存和 DB 不一致)。
- 整改:如果库存扣减是核心强一致要求,建议采用 TCC 模式或取消 Redis 预扣减,直接由 AT 在 DB 层扣减,并保证 AT 超时 > 所有 RM 执行时间之和。或者使用 Redis 作为缓存,DB 为准,发生回滚时通过事务消息补偿缓存。
-
风险4(P1):选主算法未说明。如果订单服务有定时任务(如取消超时未支付订单),需确认选主方案。K8s Lease 默认 15s 故障转移时间是否满足业务要求?如果要求 <5s,需改用 Raft。
- 整改:明确定时任务选主机制,评估故障转移时间。
存储评审:
- 风险5(P0):分片键
user_id无法覆盖卖家查询店铺订单、运营按时间查报表等核心查询。卖家查订单会全分片广播,运营报表亦然。在大促期间,全分片广播 + 复杂聚合将直接打爆数据库。- 整改:为卖家查询建立异构索引表(如 MySQL 二级索引表或同步到 Elasticsearch),运营报表同步到 ClickHouse/Doris。分片键选择必须满足用户端核心查询,运营和卖家走搜索分析引擎。
- 风险6(P1):Redis Cluster 作为库存缓存,缓存策略未说明。若采用 Cache-Aside,缓存与 DB 的一致性如何保证?TTL 是否随机化?是否有击穿防护?
- 整改:明确库存缓存策略。对于热点库存,可使用逻辑过期 + 互斥锁防击穿,并设置随机 TTL。
治理评审:
- 风险7(P0):Istio 是否开启了 mTLS STRICT 模式?Sentinel 是否覆盖了所有外部依赖(数据库、Redis、RocketMQ)?若未覆盖,数据库慢查询可能拖死整个订单服务。
- 整改:开启 mTLS,并验证所有外部依赖已接入 Sentinel 熔断,且设置合理的降级逻辑(如支付降级为稍后重试)。
- 风险8(P1):K8s 探针未给出配置。必须验证
livenessProbe timeout > GC最大停顿时间×2,initialDelaySeconds是否足够。- 整改:根据压测时的 GC 日志,调整探针参数,避免误重启。
3. 风险汇总与优先级排序
| 风险编号 | 维度 | 风险描述 | 等级 | 修复建议 | 修复顺序 |
|---|---|---|---|---|---|
| 1 | 通信 | 超时传递链配置可能不满足 | P0 | 建立超时配置树,调整Gateway和Dubbo超时 | 1 |
| 5 | 存储 | 分片键导致卖家查询全广播 | P0 | 建设异构索引或搜索服务 | 2 |
| 3 | 协作 | Seata AT 与 Redis 缓存扣减一致性问题 | P0 | 改为 TCC 或纯 DB 扣减 + 缓存补偿 | 3 |
| 7 | 治理 | 熔断未全覆盖 / mTLS 未开启 | P0 | 全量梳理外部依赖并配置熔断,开启 STRICT | 4 |
| 2 | 通信 | 死信队列无监控 | P1 | 配置告警规则 | 5 |
| 6 | 存储 | 缓存 TTL 随机化与击穿防护缺失 | P1 | 实现互斥锁和随机 TTL | 6 |
| 4 | 协作 | 定时任务选主未明确 | P1 | 明确 K8s Lease 或 Raft,评估故障转移时间 | 7 |
| 8 | 治理 | 探针配置未知,可能误杀 | P1 | 根据 GC 日志配置合理探针 | 8 |
4. 技术债务偿还路径
- L1 债务(立即修复):风险1、3、5、7。这些是 P0 风险,必须在下一次上线前修复。需要停下手头新功能,由核心团队执行。
- L2 债务(1-2 迭代内):风险2、4、6、8。与业务需求并行,在下个迭代中分配 30% 资源修复。
- L3 债务(技术规划):整个系统尚未提到读写分离、数据冷热分离、多租户(如果是 SaaS)。如果未来数据量进一步增长,需要考虑:对订单表进行冷热分离(历史订单迁移到 ES/ClickHouse)、引入 Binlog 订阅同步。这属于技术演进,排入下季度规划。
5. 架构演进的下一步建议
当前架构已经具备微服务、分布式事务、分库分表和部分治理能力,属于“数据密集型”早期。下一步演进建议:
- 引入 CQRS:将订单查询和下单事务分离。下单继续走 Seata AT + ShardingSphere,查询通过 CDC (Debezium → Kafka → Elasticsearch) 构建搜索索引,解决多维度查询问题。
- 精细化容量规划与弹性:在 K8s 上配置 HPA(基于 CPU/内存或自定义指标如 QPS),实现自动弹性伸缩。
- 引入全链路压测:基于流量录制回放,定期进行全链路压测,验证容量模型和超时配置,提前发现瓶颈。
- 安全加固:推进全链路 mTLS,数据库密码使用 Vault 动态管理。
附录 A:架构评审速查表
本速查表汇总了《分布式系统架构评审与检查清单》一文中所有检查项,按四个维度(通信、协作、存储、治理)分组,包含检查项ID、简要描述、所属维度、风险等级、关联的本系列篇目以及后续系列详细展开位置,方便在日常架构评审会议中快速检索和逐项核对。
| 检查项ID | 简要描述 | 所属维度 | 风险等级 | 关联本系列篇号 | 关联后续系列篇号 |
|---|---|---|---|---|---|
| CHK-COMM-01 | 所有服务间调用链是否形成闭环?是否存在 A→B→C→A 的循环依赖? | 通信 | P0 | 第4篇(故障传播链) | 高并发与稳定性工程(限流/熔断) |
| CHK-COMM-02 | 核心链路的调用链深度是否 ≤5 层,以确保整体可用性满足 SLO? | 通信 | P1 | 第4篇(可用性串行计算) | 高并发与稳定性工程(SLO 设定) |
| CHK-COMM-03 | 所有服务间调用的超时配置是否遵循“上游超时 > 下游超时之和”原则? | 通信 | P0 | 第4篇(时间参数传递链) | 分布式事务工程实践(补偿机制) |
| CHK-COMM-04 | 是否从最上游开始,逐层检查并记录了每个 RPC/MQ/DB 调用的超时配置,并形成超时配置树? | 通信 | P1 | 第4篇(时间参数传递链) | - |
| CHK-COMM-05 | 超时时间是否考虑了业务峰值的延迟抖动,如 DB 慢查询、GC 停顿、网络重传? | 通信 | P1 | 第4篇(时间参数) | JVM 深度调优(GC对超时的影响) |
| CHK-COMM-06 | 所有可能重试的写操作是否保证了幂等?通过唯一键、状态机或 fencing token 实现。 | 通信 | P0 | 第4篇(幂等设计) | 分布式事务工程实践(TCC幂等) |
| CHK-COMM-07 | 重试次数与退避策略是否匹配业务的容忍时间?如支付重试不应在 5s 内放弃。 | 通信 | P1 | 第4篇(重试策略) | 高并发与稳定性工程(重试风暴防治) |
| CHK-COMM-08 | 每个 Topic 是否配置了死信队列(DLQ),以防消息重试耗尽后永久丢失? | 通信 | P1 | 第3篇(MQ模式) | 分布式事务工程实践(可靠消息) |
| CHK-COMM-09 | 死信队列是否有监控告警(P1级,15分钟内响应)和死信管理平台支持重放? | 通信 | P1 | 第2篇(可观测性) | 高并发与稳定性工程(告警体系) |
| CHK-COMM-10 | 数据库连接池(HikariCP)是否设置了最大连接数,且根据数据库最大连接数和实例数合理计算? | 通信 | P0 | 第4篇(连接池耗尽) | JVM深度调优(线程池配合) |
| CHK-COMM-11 | 不同服务或不同业务域是否使用独立的数据库连接池或至少独立的数据库用户? | 通信 | P1 | 第1篇(分层隔离) | 分布式数据架构(读写分离) |
| CHK-COMM-12 | 网关是否配置了 CORS、CSRF 防护、请求大小限制、SQL 注入/XSS 过滤等安全策略? | 通信 | P0 | 第1篇(接入层) | 高并发与稳定性工程(API安全) |
| CHK-COMM-13 | 是否配置了 RateLimiter 限流策略,并且限流后返回标准的 429 状态码? | 通信 | P0 | 第5篇(容量规划) | 高并发与稳定性工程(Sentinel) |
| CHK-COLL-01 | 分布式锁是否具备 fencing token 机制,防止 GC 停顿导致锁过期后其他客户端获取锁? | 协作 | P0 | 第2篇(正确性) | 分布式理论基石(第6篇锁正确性证明) |
| CHK-COLL-02 | 锁的 TTL(租约时间)是否大于业务逻辑的最大执行时间(包括 GC 和网络延迟)? | 协作 | P0 | 第4篇(时间参数) | 分布式理论基石(锁的TTL) |
| CHK-COLL-03 | 是否使用了自动续期机制(如 Redisson 的 watchdog)来保持锁,直到业务显式释放? | 协作 | P1 | - | 分布式理论基石(Redisson源码) |
| CHK-COLL-04 | 分布式事务方案的选型(XA/AT/TCC/Saga)是否与业务对一致性、隔离性、性能的要求匹配? | 协作 | P0 | 第2篇(权衡) | 分布式事务工程实践(第8篇选型决策树) |
| CHK-COLL-05 | 事务超时时间是否大于 GC 停顿时间 + 业务执行时间 + 所有参与者网络往返时间? | 协作 | P1 | 第4篇(时间参数) | 分布式事务工程实践(AT源码超时处理) |
| CHK-COLL-06 | 选主算法的故障转移时间是否满足业务的可用性 SLO? | 协作 | P0 | 第5篇(SLO) | 分布式理论基石(第7篇选举) |
| CHK-COLL-07 | 是否明确选主组件的部署节点数为奇数(3/5/7)? | 协作 | P1 | - | 分布式理论基石(Raft奇数节点证明) |
| CHK-COLL-08 | 共识集群(etcd/ZK)是否奇数节点部署,且总数不超过 7 个? | 协作 | P1 | - | 分布式理论基石(Raft性能) |
| CHK-COLL-09 | 共识集群是否配置了磁盘容量告警(如 etcd --quota-backend-bytes)? | 协作 | P0 | 第5篇(容量规划) | K8s生产化运维深度(etcd运维) |
| CHK-STOR-01 | 分库分表的分片键是否是 80% 以上核心查询的 WHERE 条件或路由条件? | 存储 | P0 | 第3篇(数据密集型) | 分布式数据架构(第1篇分片键设计) |
| CHK-STOR-02 | 分片键的基数(区分度)是否远大于分片数(通常建议 > 分片数 ×10)? | 存储 | P0 | 第5篇(容量规划) | 分布式数据架构(第1篇分片倾斜) |
| CHK-STOR-03 | 分片数是否基于未来 3 年的容量规划计算?(总数据量/单分片舒适容量×1.3) | 存储 | P1 | 第5篇(容量规划) | 分布式数据架构(扩容方案) |
| CHK-STOR-04 | 缓存刷新方案(Cache-Aside等)是否与业务对不一致窗口的容忍度匹配? | 存储 | P0 | 第3篇(缓存模式) | 分布式数据架构(第6篇缓存策略) |
| CHK-STOR-05 | 缓存 TTL 是否加上了随机值(如 ±10%),防止缓存雪崩? | 存储 | P0 | 第4篇(故障雪崩) | 分布式数据架构(缓存雪崩防护) |
| CHK-STOR-06 | 是否配置了缓存穿透(布隆过滤器/缓存空值)、缓存击穿(互斥锁/逻辑过期)的防御方案? | 存储 | P1 | 第4篇(故障传播) | 分布式数据架构(缓存穿透/击穿) |
| CHK-STOR-07 | 冷数据迁移工具是否配置了限速参数(如 --max-lag),避免影响主库? | 存储 | P0 | 第5篇(数据迁移) | 分布式数据架构(第5篇冷热分离) |
| CHK-STOR-08 | ES ILM 冷阶段迁移前是否执行了 forcemerge 以回收段空间,并调整了索引副本? | 存储 | P1 | - | 分布式数据架构(ES运维) |
| CHK-STOR-09 | 冷数据查询的响应时间是否满足业务 SLO?若为对象存储,延迟可达秒级。 | 存储 | P1 | 第5篇(SLO) | 分布式数据架构(冷查询优化) |
| CHK-STOR-10 | 多租户共享表方案,是否使用了 PG RLS 或 MySQL 视图强制过滤,而非仅应用层加条件? | 存储 | P0 | 第2篇(安全第一) | 分布式数据架构(第3篇多租户隔离) |
| CHK-STOR-11 | 使用 PG RLS 时,连接池在归还连接前是否执行了 RESET ROLE 防上下文污染? | 存储 | P0 | - | 分布式数据架构(连接池上下文管理) |
| CHK-STOR-12 | CDC 数据同步链中,每个环节的延迟是否配置了监控告警(SecondsBehindMaster 等)? | 存储 | P1 | 第5篇(数据链路) | 分布式数据架构(CDC链路监控) |
| CHK-STOR-13 | Sink 端是否具备幂等写入能力,以处理 Kafka 的消息重复或回溯? | 存储 | P1 | 第2篇(幂等) | 分布式数据架构(数据同步幂等) |
| CHK-GOV-01 | 所有外部依赖(DB/Redis/MQ/三方API)是否配置了熔断器? | 治理 | P0 | 第2篇/第4篇 | 高并发与稳定性工程(Sentinel) |
| CHK-GOV-02 | 对于每个熔断降级点,是否有经过验证的兜底逻辑,且兜底数据不会破坏业务? | 治理 | P1 | 第2篇(降级) | 高并发与稳定性工程(降级策略) |
| CHK-GOV-03 | 降级逻辑是否进行了分级?核心服务不允许降级或仅静态化,非核心可大幅降级。 | 治理 | P0 | 第2篇(权衡) | 高并发与稳定性工程(降级分级) |
| CHK-GOV-04 | K8s livenessProbe 的超时时间是否大于 GC 最大停顿时间 ×2? | 治理 | P0 | 第4篇(探针推导) | JVM 深度调优 / K8s探针 |
| CHK-GOV-05 | initialDelaySeconds 是否大于应用启动时间(含依赖初始化、缓存预热)? | 治理 | P1 | 第4篇(启动时间) | K8s生产化运维深度(启动优化) |
| CHK-GOV-06 | failureThreshold 设置是否合理?能否在短暂抖动后自动恢复而不是立即杀死 Pod? | 治理 | P1 | 第4篇(时间参数) | K8s生产化运维深度(探针调优) |
| CHK-GOV-07 | 告警是否按照 P0(电话+5min)、P1(即时通讯+15min)、P2(邮件+1h)进行了明确分级? | 治理 | P0 | 第2篇(可观测性) | 高并发与稳定性工程(告警体系) |
| CHK-GOV-08 | 告警规则是否配置了抑制策略和静默期,防止告警风暴? | 治理 | P1 | - | 高并发与稳定性工程(告警抑制) |
| CHK-GOV-09 | 是否存在误报防范机制?如 Prometheus 的 for 持续时间,避免瞬时抖动触发告警。 | 治理 | P1 | - | Prometheus/Alertmanager 最佳实践 |
| CHK-GOV-10 | 日志中是否包含 TraceId,并在 Gateway 生成,通过 Header/Attachment 全链路传递? | 治理 | P0 | 第2篇(可观测性) | SkyWalking/Jaeger 集成 |
| CHK-GOV-11 | 能否通过 TraceId 在 SkyWalking 等 APM 中快速检索一次完整调用链并看到每个 Span 耗时? | 治理 | P1 | - | SkyWalking 最佳实践 |
| CHK-GOV-12 | K8s RBAC 是否遵循最小权限原则?每个 ServiceAccount 仅授予所需 verbs 和 resources。 | 治理 | P0 | 第5篇(部署安全) | K8s生产化运维深度(RBAC实践) |
| CHK-GOV-13 | Istio 是否开启了 mTLS(PeerAuthentication STRICT 模式)? | 治理 | P0 | 第5篇(通信安全) | Istio/K8s运维安全 |
| CHK-GOV-14 | 数据库密码、API 密钥是否通过 K8s Secret 挂载或外部 Vault 管理,无硬编码? | 治理 | P0 | 第2篇(安全第一) | K8s生产化运维深度(Secret管理) |
本文完结。
延伸阅读
- 《The Checklist Manifesto》 - Atul Gawande
- AWS Well-Architected Framework(卓越架构五大支柱)
- Google SRE Book, Chapter 13: Production Readiness Review
- Netflix Technology Blog: Architecture Review Process
- 《Clean Architecture》 - Robert C. Martin, Part V & VI