编写日期:2026-10-26
资料来源:TOGAF® Standard 10th Edition(The Open Group)、C4 Model(Simon Brown)、4+1 视图模型(Philippe Kruchten)、arc42 方法(Gernot Starke)、AWS Well-Architected Framework、Microsoft Azure 云设计模式、《Fundamentals of Software Architecture》(Mark Richards & Neal Ford)等权威资料,并结合一线开发实践中的高频问题整理。
目录
- 第 1 部分 架构师定位与知识体系
- 第 2 部分 架构设计方法论:架构师从 0 开始如何设计
- 第 3 部分 核心架构风格与设计模式详解
- 第 4 部分 真实环境完整案例:从需求到落地
- 第 5 部分 开发高频问题与详细解决方案
- 第 6 部分 从入门到精通:完整学习路线
- 附录 A 架构文档模板(arc42 精简版)
- 附录 B 架构决策记录(ADR)模板
- 附录 C 架构评审 Checklist
第 1 部分 架构师定位与知识体系
1.1 什么是软件架构师
软件架构师是对系统的结构(Structure)、架构重要决策(Architecturally Significant Decisions)、架构重要需求(ASR)与架构演进负最终责任的工程师角色。按照 Mark Richards 与 Neal Ford 在《Fundamentals of Software Architecture》中的经典定义,架构 = 结构 + 架构决策 + 设计原则 + 重要的架构特性。
软件架构的本质可以概括为四句话:
- 架构是决策的集合------系统最终呈现的形态,是无数"选 A 还是选 B"的结果。
- 架构是权衡(Trade-off)的艺术------不存在最优架构,只存在当前约束下最合适的架构。"Everything in software architecture is a trade-off."
- 架构是演进的------架构不是一次性画出来的蓝图,而是随业务、团队、技术变化持续调整的动态过程(演进式架构,Evolutionary Architecture)。
- 架构服务于业务目标------脱离业务谈架构是空中楼阁,衡量架构好坏的唯一标准是它能否支撑业务当前和可预见未来的需求。
1.2 架构师的分类与职责
| 类型 | 关注层次 | 典型职责 |
|---|---|---|
| 企业架构师(Enterprise) | 组织级 | IT 战略对齐、技术标准化、系统间治理、TOGAF/ArchiMate |
| 解决方案架构师(Solution) | 单个系统/项目级 | 端到端方案设计、技术选型、集成方案、非功能需求落实 |
| 应用/软件架构师(Application) | 应用内部 | 模块划分、接口设计、技术框架、代码架构守护 |
| 基础设施/云架构师 | 平台层 | 网络拓扑、计算存储、容器编排、IaC、成本优化 |
| 数据架构师 | 数据域 | 数据模型、数仓/湖、主数据、数据治理、数据安全 |
| 安全架构师 | 安全域 | 威胁建模、零信任、合规(等保/GDPR)、密钥管理 |
软件架构师的核心职责(无论哪种类型):
- 定义架构:确定系统的架构特性(质量属性)优先级,选择架构风格,划分模块边界。
- 技术决策与选型:以 ADR(架构决策记录)的形式做出并记录技术选型决策。
- 架构文档与沟通:用 C4 模型、4+1 视图等向不同角色(管理层/开发/运维/外部方)传达架构。
- 守护与演进:通过代码评审、适应性函数(fitness functions)、架构看板守护架构不腐化。
- 风险识别与管理:识别技术风险、单点故障、可扩展性瓶颈,制定缓解方案。
- 培养团队:把架构思维传递给开发团队,做"最后一公里"的落地辅导。
1.3 架构师与高级开发工程师的核心区别
| 维度 | 高级开发工程师 | 软件架构师 |
|---|---|---|
| 视角 | 组件内部如何实现 | 组件之间如何协作、边界如何划分 |
| 关注点 | 功能正确、代码质量 | 质量属性(性能/可用性/扩展性/成本/安全) |
| 时间跨度 | 当前迭代的实现 | 3~5 年的演进路径 |
| 沟通对象 | 开发团队 | 业务方、管理层、开发、运维、外部厂商 |
| 决策方式 | 局部最优 | 全局权衡、记录取舍理由 |
| 度量标准 | 代码可运行、测试通过 | 系统整体特性达标、变更成本可控 |
一句忠告:架构师必须持续写代码。"象牙塔架构师"(Ivory Tower Architect)是最常见的架构反模式------只画图不落地,产出的架构要么实现不了,要么和真实代码严重脱节。
1.4 架构师知识体系全景图
1.4.1 四层知识模型
┌─────────────────────────────────────────────────────┐
│ 第4层:架构思维层 │
│ 权衡思维 · 演进思维 · 风险思维 · 治理思维 · 取舍原则 │
├─────────────────────────────────────────────────────┤
│ 第3层:架构方法论层 │
│ TOGAF ADM · C4模型 · 4+1视图 · arc42 · ADR │
│ ATAM架构权衡分析 · 演进式架构 · DDD领域驱动设计 │
├─────────────────────────────────────────────────────┤
│ 第2层:架构技术与模式层 │
│ 架构风格(分层/微服务/事件驱动/管道...) · 设计模式 │
│ 分布式理论(CAP/BASE/Paxos/Raft) · 缓存/消息/搜索 │
│ 高并发三板斧(缓存/限流/降级) · 数据一致性 │
├─────────────────────────────────────────────────────┤
│ 第1层:工程基础层 │
│ 至少精通一门语言 · 数据结构与算法 · 网络(TCP/HTTP/DNS) │
│ 操作系统 · 数据库原理 · 中间件原理 · 容器/K8s/CI/CD │
└─────────────────────────────────────────────────────┘
1.4.2 必须掌握的架构特性(质量属性)清单
隐式特性(Implicit Characteristics)------最容易忽视、最容易出事的:
-
可用性(Availability) :常见目标 99.9%(三个 9,年停机约 8.76 小时)、99.95%(三个半 9,年停机约 4.38 小时)、99.99%(四个 9,年停机约 52.56 分钟)。计算公式:可用性 = 正常运行时间 /(正常运行时间 + 停机时间)。## 2) 修正 CAP 定理表述(更符合学术共识)
原表述"网络分区§发生时,一致性©与可用性(A)只能二选一"过于绝对。更准确的表述是:在发生网络分区的前提下(P 必然存在于分布式系统中),系统要么选择 CP(放弃可用性,保证一致性),要么选择 AP(放弃强一致性,保证可用性)。另外建议补充 PACELC 思想。
-
可扩展性(Scalability):垂直扩展(Scale Up)vs 水平扩展(Scale Out);有状态 → 无状态化是水平扩展的前提。
-
弹性/可伸缩(Elasticity):应对流量波峰波谷的自动伸缩能力。
-
性能(Performance):延迟(P50/P95/P99)、吞吐量(QPS/TPS)、资源利用率。
-
容错性(Fault Tolerance):故障发生时不崩溃、能降级、能自愈。
-
安全性(Security):认证/授权/审计/加密/最小权限。
-
可维护性(Maintainability):模块化、低耦合高内聚、可测试性。
-
数据一致性(Consistency):强一致 vs 最终一致。
-
成本(Cost):云时代的一等公民,过度设计就是浪费。
架构特性的分析法: 用"架构重要性分析"给特性排序------哪些特性是业务成功的必要条件?哪些必须达到可衡量的标准?正确做法是只保留 3~5 个最高优先级特性,全部都要等于全都做不好。
1.4.3 必须掌握的分布式理论
| 理论 | 核心内容 | 对架构的实际影响 |
|---|---|---|
| CAP 定理 | 当网络分区(P)发生时,一致性(C)和可用性(A)之间只能二选一。在无网络分区的正常情况下,可以同时满足 C 和 A。 | 分布式系统中网络分区几乎无法完全避免。实践中多采用"AP + 最终一致"(电商、内容等)或"CP + 部分不可用"(金融支付、分布式锁、选主等)。更贴近现实的延伸是 PACELC:若发生分区(P)则在 A 与 C 间权衡,否则(E)在延迟(L)和一致性(C)间权衡。 |
3) 修正 RPO 表述("同步落盘"不是 RPO=0 的充要条件)
原文"支付数据 RPO = 0(同步落盘)"不够严谨。真正要达到 RPO=0,需考虑主从同步方式(同步复制/半同步复制)、事务提交顺序、存储可靠性等。建议改为更客观的表述。
| BASE 理论 | 基本可用、软状态、最终一致 | AP 系统的工程化落地指导,如订单异步扣库存 |
| 一致性哈希 | 节点增减时仅少量数据迁移 | 分布式缓存、分片路由的基础 |
| Raft/Paxos | 多数派共识算法 | etcd/Consul/Nacos(Raft)、ZooKeeper(ZAB) 的底层 |
| 分布式事务 | 2PC/3PC、TCC、Saga、本地消息表、事务消息 | 跨服务数据一致性的全部工程手段(见第 5 部分 Q7) |
| 幂等性 | 同一操作执行多次结果不变 | 重试、消息消费、支付回调的基础要求 |
| Quorum 机制 | W+R>N 保证读写重叠 | N=3, W=2, R=2 读写一致的经典配置 |
1.4.4 必须熟练的中间件与技术栈(以主流 Java/云原生生态为例)
- 服务框架:Spring Boot / Spring Cloud(Alibaba)、Dubbo、gRPC
- 服务治理:Nacos / ZooKeeper / Consul(注册中心与配置中心)
- 网关:Nginx、Kong、APISIX、Spring Cloud Gateway
- 缓存:Redis(含哨兵/集群模式)、本地缓存 Caffeine、多级缓存架构
- 消息队列:Kafka、RocketMQ、RabbitMQ(选型对比见第 5 部分 Q10)
- 数据库:MySQL/PostgreSQL(分库分表 ShardingSphere)、MongoDB、TiDB
- 搜索:Elasticsearch
- 可观测性:Prometheus + Grafana(指标)、ELK/Loki(日志)、SkyWalking/Jaeger(链路追踪)------三大支柱缺一不可
- 容器与编排:Docker、Kubernetes、Helm
- CI/CD 与 IaC:GitLab CI / Jenkins / ArgoCD、Terraform、Ansible
- 限流熔断:Sentinel、Resilience4j、Hystrix(已停更,新项目勿用)
1.5 架构师常见反模式(务必警惕)
- 象牙塔架构师:脱离代码与团队,产出无法落地的"完美架构"。
- 简历驱动开发(RDD):为了用新酷技术而用,而非业务需要。
- 过度设计(Over-Engineering):10 人团队、日活 1 千的系统上微服务 + K8s + 多活。判断标准:为未来 6 个月内不会到来的规模付费,就是过度设计。
- 大泥球(Big Ball of Mud):模块边界模糊、依赖盘根错节------架构腐化的终点。
- 分布式单体(Distributed Monolith):用微服务的形式维持单体的事实------服务必须一起发布、共享数据库、同步调用链过长。这是微服务实践中最痛的失败形态。
- 供应商锁定:无抽象层地深度绑定某云厂商专有 API。
- 分析瘫痪(Analysis Paralysis):决策永远在"再调研一下",错过市场窗口。
- 文档与代码脱节:架构图停在一年前,没人信也没有用------用"文档即代码"(docs-as-code,随版本库演进)缓解。
第 2 部分 架构设计方法论:架构师从 0 开始如何设计
本章回答一个问题:接手一个新系统,架构师第一步做什么?每一步做到什么程度? 以下流程综合了 TOGAF ADM 的思想、arc42 的六大活动、《Software Architecture: The Hard Parts》的实践方法,是经过大量项目验证的可操作流程。
2.1 总体流程:七步架构设计法
①明确需求与约束 → ②识别架构特性并排序 → ③总体架构(风格选型/划分)
→ ④详细设计(模块/接口/数据) → ⑤技术选型与ADR → ⑥验证(评审/原型/演练)
→ ⑦文档化与落地守护
七步是迭代循环而非瀑布:每个增量(建议 2~4 周一个迭代)重复走一遍,逐步细化。
2.2 第一步:明确需求与约束(建筑师先看地皮)
2.2.1 要弄清楚的四类输入
| 类别 | 内容 | 典型问题 |
|---|---|---|
| 业务需求 | 核心用例、业务流程、成功标准 | "这个系统未来一年最重要的 3 个业务目标是什么?" |
| 功能需求 | 用例/用户故事清单 | 用例图 + 每个用例的触发方、输入输出 |
| 非功能需求(质量属性) | 性能、可用性、安全、合规... | "双 11 峰值 QPS 预估多少?允许停机多久?" |
| 约束(Constraints) | 时间、预算、团队技能、合规、既有系统 | "必须在等保三级内?团队只有 6 个 Java 工程师?" |
约束是架构设计的硬边界。同一个系统,6 人团队和 60 人团队的正确架构完全不同------团队结构决定架构(康威定律:组织沟通结构必然映射到系统结构,因此架构设计要与组织结构对齐,或反过来用团队拓扑影响组织)。
2.2.2 需求澄清的关键技巧:问"量"的问题
模糊需求是架构失误的第一根源。架构师要把形容词变成数字:
- ❌ "系统要快" → ✅ "核心下单接口 P99 < 300ms(在 5000 QPS 并发下)"
- ❌ "系统要稳定" → ✅ "全年可用性 ≥ 99.95%,RTO < 15 分钟,RPO < 1 分钟"
- ❌ "要能扛大流量" → ✅ "预估峰值 2 万 QPS,允许超出容量 30% 时限流拒绝"
- ❌ "数据不能丢" → ✅ "支付类交易数据力求 RPO = 0(需配合同步/半同步复制、事务持久化落盘等手段),日志、埋点等非关键数据可容忍 RPO 数十秒至数分钟"
4) 修正 Redisson 分布式锁要点(看门狗触发条件更准确)
Redisson 的看门狗(Watchdog) 只有在未显式指定 leaseTime (即传入 -1)时才会自动续期。若显式传入了 leaseTime,看门狗将不会生效,锁会在到期后自动释放。原文"默认 30s 自动续期"表述易引起误解。
2.2.3 推荐的《架构需求澄清单》(可复制使用)
1. 系统的一句话定位与业务价值
2. 核心用例 Top5(含触发频率)
3. 规模预估:用户量 / 日活 / 峰值 QPS / 数据量(1年) / 增长率
4. 可用性目标:N个9?RTO/RPO?允许停机窗口?
5. 性能目标:关键链路 P99 延迟?吞吐目标?
6. 安全与合规:等保级别?数据跨境?审计要求?
7. 团队:人数 / 技能栈 / 是否有运维
8. 约束:预算 / 交付时间 / 既有系统 / 必用技术
9. 明确"不要做"的边界(Out of Scope)
10. 成功标准:上线后如何衡量架构成功?
2.3 第二步:识别架构特性并排序(最重要的一步)
绝大多数架构失败不是功能没实现,而是架构特性没有达标------上线后性能崩了、扩展不动了、安全事故了。
2.3.1 方法:架构重要性分析
- 列出候选特性(见 1.4.2 清单)。
- 对每个特性问:"如果它不达标,业务会怎样?"------按"致命 / 受损 / 无感"分级。
- 与业务方共同确认 Top 3~5,其余作为普通工程要求。
- 为每个 Top 特性定义可测量的验收标准。
2.3.2 常见业务的特性优先级经验值
| 业务形态 | 通常最高优先特性 |
|---|---|
| 电商/交易 | 性能、可用性、一致性、可扩展性 |
| 金融支付 | 安全、一致性(强一致)、审计合规、可用性 |
| 内容/资讯 | 性能(读多写少)、成本、可扩展性 |
| 企业内部系统 | 可维护性、成本、可修改性 |
| 物联网/时序 | 吞吐量(写入)、数据保留策略、可用性 |
| SaaS 多租户 | 多租户隔离、可修改性、可扩展性 |
2.4 第三步:总体架构------风格选型与系统划分
2.4.1 架构风格选型决策表
| 架构风格 | 适合场景 | 优点 | 代价/风险 |
|---|---|---|---|
| 分层架构(单体) | 团队小、业务早期、内部系统 | 简单、易调试、事务简单 | 可扩展性差,容易腐化为大泥球 |
| 模块化单体(Modular Monolith) | 多数业务系统的最佳起点 | 边界清晰又部署简单 | 需要纪律守护模块边界 |
| 微服务 | 大团队、独立伸缩需求、高频发布 | 独立部署、技术异构、故障隔离 | 分布式复杂度全套(事务/链路/运维),见第 5 部分 |
| 事件驱动(EDA) | 异步解耦、削峰、审计溯源 | 松耦合、高吞吐、削峰 | 最终一致、调试困难、消息幂等 |
| CQRS + 事件溯源 | 读写比悬殊、需要完整审计流 | 读写独立优化、可回放 | 实现复杂度高,团队门槛大 |
| 空间/管道架构 | 数据处理、流计算 | 高吞吐、易并行 | 只适合管道类任务 |
| Serverless | 波动明显的低频任务、 glue 代码 | 零运维、按量付费 | 冷启动、执行时长限制、锁定 |
关键原则:从单体开始,演进到微服务。 除非已有明确证据(团队 >30 人、明确的服务独立伸缩需求、独立发布节奏需求),否则"模块化单体"是正确起点。Martin Fowler 的实践准则:"Monolith First"------先用模块化单体快速验证业务,边界稳定后按边界拆分,成本远低于一开始就拆微服务再失败回退。
2.4.2 系统划分的方法
按业务能力划分(首选),工具是 DDD 的限界上下文(Bounded Context):
- 事件风暴(Event Storming):与业务方一起,把领域事件贴满墙("订单已创建""库存已扣减"...)→ 按时间/因果聚类 → 识别子域(核心域/支撑域/通用域)→ 每个子域即一个服务的候选边界。
- 划分检验标准:每个上下文内高内聚(一起变更的理由只有一个);上下文之间低耦合(异步事件为主,同步调用最少);每个服务能被一个小团队(two-pizza team)完整拥有(代码+数据库+运维)。
- 红线规则 :服务之间禁止共享数据库;禁止双向依赖;跨服务数据查询通过 API 或数据冗余,而不是直连对方的库。
2.4.3 逻辑分层通用模板(无论单体还是微服务内部都适用)
┌─────────────────────────────┐
│ 接入层:网关/鉴权/限流/路由 │
├─────────────────────────────┤
│ 应用层(BFF):编排/聚合/DTO │
├─────────────────────────────┤
│ 领域层:核心业务逻辑/实体/规则 │
├─────────────────────────────┤
│ 基础设施层:DB/缓存/MQ/外部API │
└─────────────────────────────┘
依赖方向:上层依赖下层,下层不得反向依赖
(领域层完全不依赖框架细节 ------ 六边形/整洁架构原则)
2.5 第四步:详细设计
2.5.1 四张必画的图(用 C4 模型组织)
C4 模型(Simon Brown)用四个缩放层级组织架构图,自顶向下:
| 层级 | 内容 | 受众 |
|---|---|---|
| C1 系统上下文图 | 本系统 + 用户 + 外部系统 | 所有人,包括管理层 |
| C2 容器图 | 独立运行单元(Web/API/DB/MQ)与技术选型 | 架构师、开发、运维 |
| C3 组件图 | 容器内部的模块划分 | 开发团队 |
| C4 代码图 | 关键类的结构(只画核心复杂部分) | 开发 |
辅助以 4+1 视图(Kruchten)补齐维度:
- 逻辑视图:功能如何组织(类图/组件图)
- 开发视图:代码包结构与工程划分
- 过程视图:并发、进程通信、同步点
- 物理/部署视图:什么代码跑在什么硬件/节点上
- +1 场景视图:用关键用例的时序图把前四个视图串起来
实践建议:C1/C2 必画,C3 画核心服务,C4 只画最复杂的领域逻辑;再配 2~3 张关键链路时序图(下单、支付回调、缓存失效)和 1 张部署图。图够了,不要 30 张没人看的图。
2.5.2 数据架构设计(步骤化)
- 概念模型:识别核心实体与关系(ER 图)。
- 逻辑模型:范式化设计、主外键、索引策略。
- 物理模型:选型(关系型/文档型/宽表/时序)、分库分表策略、冷热分离、归档方案。
- 读写路径:核心查询的反范式冗余、缓存策略(Cache-Aside 默认,见 5.2)、报表走读写分离/数仓。
- 一致性方案:单体事务 vs Saga vs 事务消息(见 5.7)。
2.5.3 接口设计规范要点
- REST 资源化命名 + 统一响应结构
{code, message, data, traceId}; - 版本化(/v1/ 或 Header);分页、过滤、排序参数标准化;
- 幂等键(Idempotency-Key)用于写操作;限流与熔断在网关统一;
- 接口契约先行(OpenAPI/Swagger),契约变更走评审------契约即团队间的法律。
2.6 第五步:技术选型与 ADR
2.6.1 选型的四个决策原则
- 业务价值优先:选型解决的是当前架构特性短板,不是简历亮点。
- 生态与团队匹配:团队能驾驭的中间件才是好中间件;招不到人的技术栈慎选。
- 退出成本:评估锁定程度------深度绑定专有 API 前先做抽象层。
- 可演进:优先选允许"换实现"的技术(标准 SQL、标准消息协议 AMQP)。
2.6.2 每个重要决策写一条 ADR(架构决策记录)
ADR 记录的不是"架构是什么",而是"为什么是这样"。半年后没人记得为什么选 RocketMQ 而不是 Kafka,ADR 就是团队的集体记忆。模板见附录 B。触发写 ADR 的信号:跨服务边界、影响 >2 个模块、成本 >1 人月、难以回滚、影响数据模型。
2.7 第六步:验证------让架构"先失败在纸上"
- 架构评审(ATAM 简化版) :拿 3~5 个关键场景(质量属性场景)走查架构:
- 场景模板:
在 [环境] 下,[刺激] 发生时,[响应] 应在 [指标] 内完成 - 例:"在大促峰值下,下单 QPS 达 2 万时,系统 P99 延迟 < 500ms 且无数据丢失。"
- 逐场景问:这个场景下架构的哪些点会先崩?是否有应对?
- 场景模板:
- 原型验证(Walking Skeleton,走路的骨架):用 1~2 周实现"端到端打通的最小垂直切片"------一个请求从网关 → 服务 → DB → 返回,包含日志/监控/部署。它验证的是架构骨架而非业务功能。
- 风险风暴(Risk Storming):团队一起在架构图上标"风险点"(并发竞争、单点、第三方依赖),按概率×影响排序,制定缓解措施。
- 容量估算:估算 QPS → 反推机器数/连接数/缓存容量/DB 容量,写进部署方案。
2.8 第七步:文档化与落地守护
- 文档:用附录 A 的 arc42 精简模板,控制在 15~30 页;docs-as-code 放进代码仓库,与架构同步评审。
- 落地守护三件套 :
- 架构决策看板:ADR 列表 + 状态(提议/已接受/已废弃);
- 架构守护工具:ArchUnit(Java 包依赖规则)、SonarQube(圈复杂度/重复率)、dependency-cruiser(JS)------把架构约束变成自动化测试;
- 代码评审中的架构检查项:分层是否越界?是否引入了跨模块直接调用?新依赖是否评审过?
- 演进节奏:每个迭代回顾架构偏差;每季度做一次"架构健康度评估"(模块依赖图、圈复杂度趋势、变更热点)。
2.9 架构师开始一个新项目的时间表(参考)
| 阶段 | 时长 | 产出 |
|---|---|---|
| 需求澄清 + 特性排序 | 1~2 周 | 需求澄清单、特性优先级表、ASR 清单 |
| 总体架构 | 1~2 周 | C1/C2 图、架构风格 ADR、模块划分草案 |
| 详细设计 | 2 周 | C3 图、核心时序图、数据模型、接口契约 |
| 走路骨架原型 | 1~2 周 | 端到端最小可运行系统 + CI/CD + 监控 |
| 评审与修订 | 1 周 | 评审纪要、风险清单、修订后的架构文档 |
| 合计 | 6~9 周 | 可供团队长期开发的架构基线 |
第 3 部分 核心架构风格与设计模式详解
3.1 分层架构(Layered / N-Tier)
结构:表现层 → 业务层 → 持久层 → 数据库,逐层调用。
- 优点:概念简单、关注点分离、团队分工自然。
- 缺点:容易变"分层大泥球"(业务全挤在 Service 层);每次变更穿透所有层;部署不可拆分。
- 适用:中小系统、CRUD 为主的业务、架构演进的起点。
- 关键纪律 :禁止跨层调用与反向依赖;用 ArchUnit 强制
controller 不依赖 mapper等规则。
3.2 六边形架构 / 整洁架构 / DDD 分层
三者本质相同:领域逻辑居中,依赖方向指向内部(依赖倒置)。
┌──────────────────────────────┐
│ 应用层(用例编排) │
┌────┤ ┌──────────────────────────┐ ├────┐
│ 适配器 │ │ 领域层(实体/领域服务) │ │ 适配器 │
│(REST)│ │ 不依赖任何框架与外部细节 │ │(DB/MQ)│
└────┤ └──────────────────────────┘ ├────┘
└──────────────────────────────┘
- 核心价值:技术(Spring/DB/MQ)只是可替换的插件;领域逻辑可独立测试;换数据库/换框架不动业务。
- 实践要点:领域层定义接口(Repository、Gateway),基础设施层实现;DTO 与领域实体严格分离;防腐层(ACL)隔离外部系统模型。
3.3 微服务架构
3.3.1 微服务成熟度自查(满足才考虑拆分)
- 团队有成熟的 DevOps/CI-CD/可观测性能力;
- 有 3 个以上有界、稳定的业务子域;
- 服务独立伸缩/独立发布的真实需求存在;
- 团队规模足以支持"一个服务一个小团队"。
3.3.2 拆分原则
- 按限界上下文拆,不按技术层拆(禁止"所有 Service 一个服务、所有 DAO 一个服务");
- 每服务私有数据库;服务间通过 API(同步)或事件(异步)交互;
- 先粗后细:宁可先拆大(2~3 个服务),拆错再合并的代价远小于拆碎;
- 识别"变更热点":经常一起变更的代码应该在同一个服务里。
3.3.3 微服务必备基础设施清单
| 能力 | 典型组件 | 说明 |
|---|---|---|
| 服务注册与发现 | Nacos / Consul / Eureka | 服务上下线自动感知 |
| 配置中心 | Nacos / Apollo | 配置与代码分离、动态推送、灰度 |
| API 网关 | APISIX / Kong / SCG | 鉴权、限流、路由、灰度、聚合 |
| 熔断限流 | Sentinel / Resilience4j | 故障隔离,防雪崩 |
| 链路追踪 | SkyWalking / OpenTelemetry | 跨服务排障,traceId 全链路透传 |
| 消息队列 | RocketMQ / Kafka | 异步解耦、削峰、事件广播 |
| 分布式任务 | XXL-JOB / PowerJob | 避免多实例重复执行 |
| 统一可观测 | Prometheus + Grafana + Loki | 指标/日志/告警三支柱 |
3.4 事件驱动架构(EDA)
两种拓扑:
- 编排式(Orchestration,中央协调者):一个 Orchestrator 服务按流程调用/发布事件指挥各参与方。优点:流程清晰、易监控;缺点:协调者是中心化风险点。适合长流程(订单履约)。
- 协同式(Choreography,去中心化):各服务订阅事件、各自响应并发布新事件。优点:松耦合;缺点:流程散落在各处,"全局流程"难看清。适合简单联动(2~3 步)。
事件类型区分(重要):
- 事件通知:"订单已创建"------通知方不关心谁消费;
- 事件携带状态转移(Event-Carried State Transfer):事件里带全量数据,消费方落本地副本,避免回查(最终一致 + 读性能的关键手法);
- 领域事件 vs 集成事件:领域事件是领域层概念(进程内),集成事件是跨服务契约(进程间),要分开建模。
EDA 三大工程问题(详见第 5 部分):消息幂等(Q7)、顺序消费(Q9)、消息不丢(Q8)。
3.5 CQRS 与事件溯源(Event Sourcing)
- CQRS :读写模型分离。写模型保证业务不变量,读模型为查询定制(冗余表/ES/物化视图)。适合读多写少、读写模型差异大的场景。不要一上来全系统 CQRS------只在读写比悬殊的模块局部使用。
- 事件溯源:以不可变事件日志作为唯一事实来源,状态 = 事件回放。优点:天然审计、可时间旅行、可重建读模型。代价:建模门槛高、事件 schema 演进复杂、需快照优化。适合:账户流水、风控审计、协作编辑。
3.6 云设计模式精选(源自 Microsoft Azure Well-Architected,共 30+ 模式中的高频 12 个)
| 模式 | 解决的问题 | 一句话要点 |
|---|---|---|
| 断路器(Circuit Breaker) | 故障依赖拖垮调用方 | 连续失败达阈值→打开熔断→半开试探→恢复 |
| 隔舱(Bulkhead) | 一处资源耗尽拖垮全局 | 按资源池隔离(线程池/连接池/实例分组) |
| 缓存旁路(Cache-Aside) | 读性能 | 先读缓存,miss 读库回填;写时删缓存 |
| 竞争消费者(Competing Consumers) | 队列吞吐 | 多消费者抢同一队列,水平扩展处理能力 |
| 重试(Retry)+ 指数退避 | 瞬时故障 | 有限次重试 + 抖动,防重试风暴 |
| 舱壁式限流(Throttling) | 过载保护 | 按租户/接口/用户维度限流,超限快速拒绝 |
| 网关聚合(Gateway Aggregation) | 前端多次往返 | 网关合并多个后端调用为一次 |
| 补偿事务(Compensating Transaction) | 跨服务无分布式事务 | Saga:每步失败执行对应逆操作 |
| 具体化视图(Materialized View) | 复杂查询慢 | 预计算结果表,异步刷新 |
| Sidecar | 横切能力复用 | 日志采集/代理/配置以伴生进程部署 |
| 优先级队列(Priority Queue) | 重要任务被堵 | 高低优先级分队列或权重消费 |
| 健康检查端点(Health Endpoint Monitoring) | 探活 | /live(进程活着)与 /ready(可接流量)分离 |
3.7 数据架构核心模式
- 读写分离:主库写、从库读;主从延迟问题用"写后立刻读走主库"或会话级粘性解决。
- 分库分表:垂直拆(按业务域)先行,水平拆(按分片键如 user_id)兜底;分片键选择决定一切------支持的分片键必须覆盖 80% 查询;跨分片查询用异构索引(ES)或冗余表。分片数按 3 年数据量一次规划到位。
- 冷热分离:热数据(3 个月)在 MySQL,冷数据归档到对象存储/ClickHouse。
- 多级缓存:本地缓存(Caffeine,毫秒级)→ 分布式缓存(Redis,亚毫秒)→ DB。层次越多一致性问题越复杂,非必要不加层。
- 主数据与事件化同步:跨服务数据复用靠"事件携带状态转移 + 本地只读副本",不要跨库 join。
3.8 设计模式在架构中的高频应用(不是背 23 个,而是会用这些)
| 模式 | 架构级应用场景 |
|---|---|
| 策略模式 | 多渠道支付、多租户计费规则、风控规则路由 |
| 工厂 + 注册表 | SPI 扩展点机制(框架插件化) |
| 观察者/发布订阅 | 领域事件、Spring 事件、MQ 解耦 |
| 装饰器 | 中间件管道(网关 Filter 链)、AOP 增强 |
| 代理 | RPC Stub、缓存代理、熔断代理 |
| 适配器/防腐层 | 隔离第三方 API 与遗留系统模型 |
| 模板方法 | 统一流程骨架中留扩展点(导出/审批流) |
| 状态机 | 订单/工单状态流转,杜绝 if-else 状态散落 |
| 责任链 | 网关过滤器、风控规则链、审批链 |
| 单例 + 双重检查 | 配置/连接管理(现代框架下多为容器托管) |
第 4 部分 真实环境完整案例:从需求到落地(电商交易系统)
本章用一个"中型电商交易系统"贯穿第 2 部分的七步法,展示每一步在真实环境中的实际产出。案例背景:
某公司现有单体商城系统,年 GMV 5 亿,日订单 3 万;公司计划明年大促目标峰值 5000 QPS 下单,且要接入 20 个第三方渠道(小程序/H5/第三方平台)。现有团队 12 名 Java 工程师 + 2 名运维。
4.1 第一步:需求与约束分析(产出样例)
约束(硬边界):团队 12 人 Java 技能栈;预算仅够 3 年内云资源 ~200 万;等保二级;改造窗口只有 6 个月,大促前必须上线。
非功能需求量化表:
| 特性 | 目标 | 依据 |
|---|---|---|
| 性能 | 下单 P99 < 500ms @ 5000 QPS | 大促目标 |
| 可用性 | 99.95%,RTO<15min,RPO<1min | 年停机 < 4.4h |
| 一致性 | 库存/资金强一致,其余最终一致 | 资损零容忍 |
| 可扩展性 | 水平扩展,容量翻倍不改架构 | 业务增长 |
| 可维护性 | 新渠道接入 < 2 人周 | 20 渠道目标 |
结论(Top4 特性):性能、可用性、一致性、可扩展性。安全合规作为硬约束底线执行。
4.2 第二步:总体架构决策(ADR 样例)
- ADR-001:采用"模块化单体核心 + 局部微服务"的混合架构
- 背景:12 人团队不足以维护全量微服务,但订单/库存/支付需要独立伸缩;
- 决策:按限界上下文拆为 4 个服务(交易、商品、库存、支付),其余能力(会员、营销、内容)保留在模块化单体中,通过内部 API 暴露;
- 后果:基础设施复杂度可控;未来子域稳定后可继续按边界拆分。
- ADR-002:订单-库存扣减采用"RocketMQ 事务消息 + 本地消息表"的最终一致方案(理由与对比见 5.7)。
- ADR-003:缓存采用 Redis Cluster + 本地 Caffeine 两级缓存,热点商品数据本地化。
- ADR-004:数据库 MySQL 一主两从 + 按用户 ID 16 分片(订单表),预留 3 年数据增长。
4.3 架构图(C2 容器图·文字版)
用户/App/小程序
│ HTTPS
┌─────▼──────┐
│ API 网关 │ 鉴权 / 限流 / 灰度路由 / traceId 注入
└──┬───────┬─┘
│ │
┌──▼───┐ ┌─▼────┐ ┌──────────────┐
│ 交易 │ │ 商品 │ │ 模块化单体 │
│ 服务 │ │ 服务 │ │ (会员/营销/内容)│
└─┬───┬┘ └──────┘ └──────────────┘
│ │ 事务消息/事件
┌─▼─┐ ┌▼──┐ ┌───────────┐
│库存│ │支付│ │ RocketMQ │
│服务│ │服务│ └───────────┘
└─┬─┘ └─┬─┘
│ │
┌─▼─────▼─────────────────────┐
│ MySQL(主从+分片) │ Redis Cluster │ Elasticsearch │
└─────────────────────────────┘
可观测性:Prometheus + Grafana + Loki + SkyWalking(旁路部署)
4.4 核心链路时序:下单(最终一致)
网关 → 交易服务:
1. 参数校验 + 幂等检查(Redis SETNX 幂等键, TTL 10min)
2. 本地事务: 插入订单记录(状态=待确认) + 写本地消息表
3. 发 RocketMQ 半消息 → 本地事务提交 → 消息确认
库存服务(消费者):
4. 扣减库存(Redis 预扣 + Lua 原子扣减 + DB 异步落库)
5. 成功 → 发"库存已扣减"事件
交易服务:
6. 监听事件 → 订单状态置为"已确认" → 发"订单已创建"事件
失败分支:
- 库存不足 → 发"库存不足"事件 → 订单关闭 + 支付原路退回
- 消息未确认 → 本地消息表定时任务扫描补偿(500ms~2s 退避)
4.5 高并发设计要点(对应大促)
- 多级拦截:CDN/静态化 → 网关限流(令牌桶,按接口配额)→ 应用层信号量兜底;预估 5000 QPS 目标容量,网关层放行上限 6000,其余快速拒绝返回友好页。
- 热点优化:秒杀商品库存预扣在 Redis(Lua 脚本原子操作),DB 只异步落最终结果;商品详情页静态化 + CDN。
- 隔离:秒杀流量单独部署一套交易实例(泳道隔离),大促不冲击日常交易。
- 降级预案 :营销活动查询失败→降级返回默认活动;评价服务熔断不影响下单主链路。核心原则:识别主链路(下单-支付),非主链路一切可为它让路。
4.6 可观测性与运维设计
- 指标:黄金四指标(延迟/流量/错误/饱和度)+ 业务指标(下单成功率、支付转化);每接口 P50/P95/P99。
- 日志:traceId 全链路透传(网关生成 → RPC Header → MQ 消息属性 → 日志 MDC)。
- 告警分级:P0(下单成功率 < 99%,电话+短信)/ P1(错误率 > 1%,短信)/ P2(容量水位 > 70%,IM)。
- 压测:上线前全链路压测(影子库 + 流量染色),验证 5000 QPS 目标;每月例行容量演练。
- 混沌演练:每季度演练 Redis 主从切换、MQ 堆积、依赖服务宕机,验证降级预案真实有效。
4.7 落地节奏(6 个月计划)
| 月份 | 里程碑 |
|---|---|
| M1 | 走路骨架:网关+交易+DB 分片打通,CI/CD、监控、traceId 就绪 |
| M2 | 交易服务核心功能 + 本地消息表一致性方案 |
| M3 | 库存/支付服务 + 事务消息 + 幂等全链路 |
| M4 | 模块化单体改造 + 事件化集成 |
| M5 | 全链路压测 + 降级预案 + 混沌演练 |
| M6 | 灰度切流(5%→25%→50%→100%)+ 大促保障 |
4.8 案例中的关键取舍复盘
- 为什么不全上微服务? 12 人团队维护 10+ 服务的运维成本会吞噬开发时间;混合架构用 60% 的收益换 30% 的复杂度。
- 为什么库存用 Redis 预扣? 5000 QPS 直接打 DB 行锁必然超时;Redis 单 key Lua 扣减可达 10 万+ QPS,DB 只做异步最终落库。代价是极端宕机时需对账修复------用"对账任务"兜底,权衡成立。
- 为什么不用 Seata AT 强一致? AT 模式锁粒度大、性能下降明显,而业务允许"下单待确认"的秒级中间态------最终一致 + 明确的状态机是更优权衡。
第 5 部分 开发高频问题与详细解决方案
以下 15 个问题是一线开发中反复出现的架构级难题,每个都给出问题本质、详细方案与落地代码/配置要点。
Q1:接口响应慢,如何系统性排查与优化?
排查方法论(自上而下,数据说话):
- 先定位再优化:通过 APM(SkyWalking/Arthas trace)拿到耗时分解------网络/网关/应用/DB/下游 RPC 各占多少;没有数据之前不做任何优化。
- 分层检查 :
- 网络层:机房内网延迟应 < 1ms;跨机房调用重排;
- 应用层:Full GC 停顿(GC 日志)、线程池排队、锁竞争(jstack 长时间 BLOCKED);
- DB 层:慢 SQL(
slow_query_log)、缺少索引、深分页、大事务; - 下游:串行调用多个慢依赖 → 改并行(CompletableFuture)或改异步。
- 高频优化手段清单 (按收益排序):
- 加缓存(读多写少数据,Cache-Aside)------通常收益最大;
- 慢 SQL 优化:索引覆盖、避免
SELECT *、深分页改游标(WHERE id > ? LIMIT n); - 串行改并行:无依赖的 RPC 并行发起;
- 同步改异步:非核心步骤(发短信、记日志)丢消息队列;
- 批量化:N 次小查询合并为一次批量查询(解决 N+1);
- 连接池/线程池调参:连接池大小 ≈ 核数×2 + 磁盘数(HikariCP 经验公式),线程池队列有界。
Q2:缓存与数据库一致性怎么保证?
标准方案:Cache-Aside(旁路缓存)+ 延迟双删:
- 读:先读缓存 → miss 则读 DB → 回填缓存(带过期时间兜底)。
- 写:先更新 DB → 再删除缓存(不是更新缓存!避免并发写导致旧数据覆盖)。
- 延迟双删(主从架构防脏读):删缓存 → 更新 DB → 延迟 500ms~1s 再删一次(清除主从同步期间被读请求回填的旧值)。
- 兜底:缓存必须设 TTL;对强一致要求的少量数据(如余额)不落缓存或用短 TTL + 逻辑过期。
三大经典缓存问题:
| 问题 | 场景 | 解决方案 |
|---|---|---|
| 缓存穿透 | 查询不存在的数据,每次都打到 DB | ① 空值缓存(短 TTL 30s);② 布隆过滤器前置拦截 |
| 缓存击穿 | 热点 key 过期瞬间大量请求打 DB | ① 互斥锁重建(SETNX 只放一个线程回源);② 逻辑过期(不删除,异步刷新) |
| 缓存雪崩 | 大量 key 同时过期 / Redis 宕机 | ① TTL 加随机抖动;② 多级缓存;③ Redis 高可用(Cluster/哨兵)+ 限流降级兜底 |
Q3:分布式锁怎么选型和实现?
三种实现对比:
| 实现 | 优点 | 缺点/风险 | 适用 |
|---|---|---|---|
| Redis(Redisson) | 性能高、API 完善 | 主从切换可能丢锁(异步复制) | 绝大多数场景首选 |
| ZooKeeper 临时顺序节点 | 强一致、无锁过期误删问题 | 性能低于 Redis(写走 ZAB 共识) | 强一致要求高的场景 |
| 数据库乐观锁(version 字段) | 实现最简单、无额外依赖 | 高并发下冲突重试多 | 低频并发更新单行数据 |
Redisson 落地要点:
- 用
tryLock(waitTime, leaseTime, unit)。若leaseTime == -1,Redisson 将启用看门狗自动续期(默认续期间隔 30 秒,续期时长同初始锁时长) 。若显式传入正数leaseTime,看门狗不会生效,锁将在该时长到期后释放。因此对于长事务必须开启看门狗或预估足够的过期时间,防止业务未完成锁先过期;
5) 修正 TCC 一致性表述(避免"准强一致"用词)
"TCC(准强一致)"这个自创用词在业界并不常用。TCC 实际上是补偿型最终一致 的实现方式:在 Try 阶段预留资源,Confirm 全部成功才最终生效,Cancel 做补偿回滚。它能达到业务上的"接近实时一致",但从严格意义上仍属于最终一致范畴。
- 锁粒度最小化:锁"用户维度"而非"全表"(
lock:stock:{skuId}); - Redis 主从切换丢锁的兜底 :对资金类操作,不依赖单一 Redis 锁,叠加 DB 层乐观锁(
UPDATE ... SET stock = stock - 1 WHERE stock >= 0)做最终防线------"Redis 锁做性能挡板,DB 约束做正确性兜底"。
Q4:接口幂等性如何设计?
幂等 = 同一操作执行多次,结果与执行一次相同。所有写接口(支付回调、消息消费、重试请求)都必须幂等。
| 方案 | 实现方式 | 适用 |
|---|---|---|
| 天然幂等 | UPDATE account SET balance = ? WHERE id = ?(绝对值覆盖) |
能改写为状态赋值的操作 |
| 唯一约束 | 数据库唯一索引兜底,重复插入报错被捕获 | 订单号、流水号防重 |
| 防重令牌 | 进入页面先领 token,提交时 SETNX token 检查后删除 |
表单防重复提交 |
| 状态机 | UPDATE orders SET status = 'paid' WHERE id = ? AND status = 'unpaid',影响行数=0 说明已处理 |
订单/工单流转 |
| 幂等表 | 消费前先 INSERT 业务流水号到幂等表(唯一索引),成功才执行业务 | MQ 消费 |
| 分布式锁 | SETNX 业务键 + 执行 + 释放 |
通用但性能略低 |
落地建议 :外部入口(支付回调)用"唯一约束 + 状态机"双保险;MQ 消费用"幂等表";前端防重(按钮置灰)只是体验优化,服务端幂等才是正解。
Q5:高并发下库存超卖/少卖怎么防?
方案分层(按并发量级递进):
-
数据库乐观锁(百级 QPS) :
UPDATE stock SET num = num - 1 WHERE sku = ? AND num > 0------原子条件更新,不会超卖。 -
Redis 预扣 + Lua(千~万级 QPS) :
lua-- KEYS[1]=库存key, ARGV[1]=扣减数量 local stock = tonumber(redis.call('GET', KEYS[1]) or '0') if stock < tonumber(ARGV[1]) then return -1 end return redis.call('DECRBY', KEYS[1], ARGV[1])Lua 脚本保证"检查+扣减"原子执行;预扣成功后发 MQ 异步落 DB;Redis 与 DB 的差异用定时对账任务修复。
-
分段库存(十万级):把 1 个热点 SKU 的库存拆成 N 段(100 份),请求哈希路由到不同 key,扣完合并------解决单 key 热点。
-
少卖处理:支付超时未完成的订单,库存回补(延迟队列触发),宁可少卖不可超卖。
Q6:热点数据/热点账号问题如何处理?
- 识别 :Redis
--hotkeys、监控单 key QPS;业务上大促商品、头部主播、爆款文章是天然热点。 - 本地缓存:热点只读数据(商品详情)推到应用本地缓存(Caffeine,TTL 秒级),Redis 只做兜底。
- Key 打散 :计数类热点(点赞数)拆成 100 个子 key(
like:{id}:{1..100}),读时聚合、写时分片。 - 读写分离热点:热点行(秒杀)用"预扣 Redis + 异步批量落库"绕开 DB 行锁竞争。
Q7:分布式事务如何选型?
方案对比与选型表(最高频面试+实战题):
| 方案 | 一致性 | 性能 | 业务侵入 | 适用场景 |
|---|---|---|---|---|
| 2PC/XA(Seata AT) | 强 | 低(锁资源到提交) | 低 | 短事务、并发不高、要求简单 |
| TCC(Try-Confirm-Cancel) | 最终一致(业务可达成准实时一致) | 中 | 高(每个操作需实现 Try/Confirm/Cancel 三段逻辑) | 资金类:转账、支付、扣款等对资源预留敏感的场景 |
6) 修正 HikariCP 连接池配置说明(去掉绝对化公式)
CPU核数 × 2 + 磁盘数 是 HikariCP 官方在某些文章中提到的经验参考值 ,并非适用于所有场景的定律。实际应以压测数据为准,过大的连接池反而会增加上下文切换和数据库锁竞争。
| Saga(编排/协同) | 最终 | 高 | 中(写补偿逻辑) | 长流程、跨多服务:订单履约 |
| 本地消息表 | 最终 | 高 | 中 | 跨服务数据同步,可靠事件发布 |
| 事务消息(RocketMQ) | 最终 | 高 | 低 | 上游成功下游异步跟上:订单→通知/积分 |
| 最大努力通知 | 弱 | 高 | 低 | 结果通知类:支付结果通知商户 |
选型决策树:
能接受秒级最终一致吗?
├─ 不能(资金)→ 并发高吗?
│ ├─ 高 → TCC(或 Saga + 资金对账兜底)
│ └─ 低 → 2PC/AT
└─ 能 → 有 MQ 吗?
├─ 有 → 事务消息 / 本地消息表
└─ 无 → 本地消息表(顺便引入 MQ)
铁律 :所有最终一致方案必须配套对账任务(T+1 或实时比对两侧数据),一致性是"机制 + 对账"共同保证的,没有对账的最终一致是在裸奔。
Q8:MQ 消息丢失/重复如何全面防范?
消息丢失三段论(生产端→Broker→消费端):
- 生产端不丢:同步发送 + 确认(Kafka acks=all / RocketMQ 同步发送 + 重试);关键消息先落本地消息表再发送。
- Broker 不丢:持久化 + 刷盘策略(RocketMQ 同步刷盘 / Kafka 副本数 ≥ 3 + min.insync.replicas=2)。
- 消费端不丢 :关闭自动提交,业务处理成功后手动 ACK;失败进重试队列,多次失败进死信(DLQ)+ 人工/定时补偿。
重复消费 :MQ 只保证至少一次(at-least-once),重复必然存在------唯一解是消费端幂等(见 Q4 幂等表方案)。
消息积压(大促常见事故):
- 快速定位:消费者是不是挂了/消费逻辑变慢(看消费耗时);
- 紧急扩容:加消费者实例(注意 RocketMQ 消费者数 ≤ 队列数,必要时临时扩队列);
- 极端方案:新起一个"转发 topic",把积压消息原样搬运到 10 倍分区的新 topic,用 10 倍消费者消化;
- 事后复盘:设置堆积水位告警(如 > 10 万条)。
Q9:消息顺序性如何保证?
- 需求确认 :绝大多数业务只需要"同一业务实体内有序"(同一订单的 创建→支付→发货),不需要全局有序------按 order_id 分区即可。
- RocketMQ :生产端用
MessageQueueSelector按 orderId 路由到同一队列;消费端用MessageListenerOrderly(单线程消费一个队列,消费失败会阻塞该队列,慎用重试)。 - Kafka:按 key 分区(同一 key 进同一分区),分区内天然有序;消费者组内一个分区只被一个线程消费。
- 陷阱:消费失败重试会破坏顺序------顺序消费场景失败策略应为"阻塞重试 + 告警",而不是跳过。
Q10:Kafka / RocketMQ / RabbitMQ 如何选型?
| 维度 | Kafka | RocketMQ | RabbitMQ |
|---|---|---|---|
| 吞吐 | 百万级/秒,最高 | 十万级/秒 | 万级/秒 |
| 延迟 | ms 级(攒批) | ms 级 | μs~ms 级,最低 |
| 事务消息 | 无(弱,幂等流) | ✅ 原生事务消息 | 无 |
| 延迟消息 | 无(需改造) | ✅ 原生任意延迟 | 插件支持 |
| 消息回溯/重放 | ✅ 天然支持 | ✅ 支持 | 弱 |
| 适用 | 日志/埋点/大数据管道 | 业务消息(订单/交易) | 中小规模、复杂路由 |
结论:业务交易系统首选 RocketMQ(事务/延迟消息开箱即用);日志与数据管道用 Kafka;轻量异步、低规模用 RabbitMQ 甚至 Redis Stream。
Q11:服务雪崩如何预防?(熔断/限流/降级体系)
雪崩链条:下游变慢 → 调用方线程池被占满 → 上游也超时 → 逐级向上蔓延直至全站不可用。
四层防御:
- 超时:每个 RPC/DB 调用必须显式设超时(连接/读取分开),总预算可层层分配(入口 500ms = A 200ms + B 200ms + 余量 100ms)。
- 熔断 :Sentinel/Resilience4j 按错误率(如 10s 内错误率 > 50%)打开熔断,快速失败 + 半开恢复。熔断必须配降级逻辑(返回缓存/默认值/友好错误),不能裸抛异常。
- 限流 :
- 算法选择:令牌桶(允许突发,网关首选)/ 滑动窗口(平滑统计)/ 漏桶(恒定速率出);分布式限流用 Redis+Lua 或 Sentinel 集群流控;
- 维度分层:全局总量 → 接口级 → 用户级(防单用户刷爆)。
- 隔离:线程池/信号量隔离(不同下游不同线程池);核心与非核心实例分组(泳道)。
降级预案管理:预案权限要事前配置好(配置中心开关),大促前演练;"预案没有演练过的等于没有预案"。
Q12:数据库连接池/线程池怎么配置?
- 连接池(HikariCP) :HikariCP 官方曾给出
pool_size ≈ CPU核数 × 2 + 有效磁盘数的经验参考值,但这并非通用定律。连接池不是越大越好 ------过多的连接会增加数据库上下文切换、锁竞争和内存开销。多数生产环境在中小型实例上往往只需 10~50 个连接即可打满数据库,务必以真实压测确定最优值。maxLifetime应小于 MySQLwait_timeout(建议预留 30~60 秒余量),避免使用已被服务端关闭的空闲连接。 - 线程池 :CPU 密集型 ≈ 核数 + 1;IO 密集型 ≈ 核数 × (1 + 等待时间/计算时间),通常 2~4 倍核数起步后靠压测定;队列必须有界 并设拒绝策略(CallerRuns 或快速失败+告警),无界队列 = OOM 定时炸弹;线程池参数命名清晰(
order-pay-pool),禁止共享"一个池跑所有业务"。
Q13:数据库单表太大/太慢怎么办?
演进路线(不要跳步):
- 先确认是索引/SQL 问题(
EXPLAIN),很多"表大"其实是索引失效; - 归档:冷数据搬到归档表/ClickHouse,主表控制在千万级以内;
- 读写分离:读流量打从库,主库专注写;
- 分库分表 (ShardingSphere-JDBC):
- 分片键选高频查询维度(订单按 user_id);
- 分片数按 3 年数据量一次到位(避免二次扩容迁移);
- 非分片键查询(商家查订单)→ 异构一份按 merchant_id 分片的表(binlog 同步)或走 ES;
- 全局唯一 ID:雪花算法(Snowflake),注意时钟回拨问题;
- 跨分片事务尽量在应用层避免(分片键隔离业务边界)。
Q14:线上故障如何快速定位?(架构师的应急方法论)
黄金流程:先止损,再定位:
- 止损(< 5 分钟):回滚最近变更(70% 故障来自变更)/ 切流到备用集群 / 开降级开关 / 扩容。
- 定位(凭三支柱) :
- 监控大盘:哪个指标先抖(入口 QPS?错误率?GC?DB 连接?)→ 锁定层级;
- 链路追踪:用 traceId 看慢在哪一跳;
- 日志:错误日志聚合(Loki/ELK)看异常类型与爆炸半径。
- 常见故障速查:
| 现象 | 高概率原因 |
|---|---|
| 大面积超时 | 依赖的 DB/Redis 慢 → 线程池打满;Full GC 频繁 |
| CPU 100% | 死循环、正则回溯、序列化热点、GC 线程 |
| 内存持续上涨 | 缓存无界、大对象、类加载器泄漏(jmap + MAT 分析) |
| 突发错误率飙升 | 最近发布、依赖方变更、证书过期、连接池耗尽 |
| Redis 变慢 | 大 key、热 key、持久化 fork 卡顿(redis-cli --bigkeys 排查) |
- 事后:写故障复盘(时间线/根因/action item/责任人),action 必须有完成时限;高频故障上升为架构改进项。
Q15:单体如何平滑演进为微服务?(绞杀者模式)
绞杀者模式(Strangler Fig)------不推倒重来的渐进式迁移:
- 网关前置:所有流量先经过新网关(哪怕后面还是那个单体);
- 按价值排序拆分:优先拆"变更频繁/性能瓶颈/团队边界清晰"的模块;
- 新旧双写过渡:新服务上线后,写路径双写(单体 + 新服务),读切到新服务,数据比对无误后停写旧路径;
- 数据迁移:新服务私有库 + binlog/双写同步,灰度切读;
- 每拆一个模块,网关上把对应路由从单体切到新服务------像藤蔓一样逐步绞杀旧系统;
- 反绞杀警惕:若迁移 6 个月新服务还是要频繁回单体拿数据,说明边界拆错了,及时回退合并。
第 6 部分 从入门到精通:完整学习路线
6.1 四阶段成长路线(总周期约 2~4 年)
阶段一:夯实工程基础(0→1 年,资深开发的起点)
- 语言:精通一门(Java/Go/Python 任一),到"理解语言运行时"的深度(JVM 内存模型/GC、goroutine 调度、解释器机制);
- 基础三件:数据结构与算法(LeetCode 200 题量级)、计算机网络(TCP 三次握手/拥塞控制、HTTP/1.1→2→3 演进、DNS 解析链路)、操作系统(进程线程、内存管理、IO 多路复用 epoll);
- 数据库 :MySQL 索引原理(B+树)、事务(ACID + 隔离级别 + MVCC)、锁机制、
EXPLAIN调优; - 检验标准:能独立排查"接口为什么慢",能读懂线程 dump 和 GC 日志。
阶段二:中间件与分布式入门(1→2 年)
- Redis:五大数据结构底层实现、持久化(RDB/AOF)、主从/哨兵/Cluster、缓存三大问题(见 Q2);
- 消息队列:精通一个(推荐 RocketMQ 或 Kafka):存储模型、消费语义、顺序/事务/延迟消息;
- 微服务框架:Spring Cloud(注册发现/配置/网关/熔断)全链路搭一遍;
- 分布式理论:CAP/BASE/一致性哈希/Raft(推荐看 etcd Raft 论文图解);
- 容器化:Docker 熟练 + K8s 核心概念(Pod/Service/Deployment/HPA),能写 Helm Chart 部署自己的项目;
- 检验标准:能独立设计并搭建"网关 + 4 服务 + MQ + Redis + MySQL"的完整小系统,含监控告警。
阶段三:架构思维形成(2→3 年)
- 方法论:C4 模型画自己的系统;用 arc42 写一份完整架构文档;练习写 ADR;
- DDD:《领域驱动设计精粹》(Vaughn Vernon)→ 事件风暴工作坊实践一次;
- 架构风格:把第 3 部分每种风格在练习项目中各实现一次最小版本;
- 必读书目 :
- 《Fundamentals of Software Architecture》--- Mark Richards & Neal Ford(架构师第一本书)
- 《Software Architecture: The Hard Parts》--- 同作者(分布式权衡)
- 《演进式架构》--- Neal Ford(Fitness Function 思想)
- 《数据密集型应用系统设计》(DDIA)--- Martin Kleppmann(分布式数据圣经)
- 《重构》与《单元测试的艺术》(代码级架构质量)
- 检验标准:能主导一次模块级架构设计并通过评审;能给别人的架构提出有依据的质疑。
阶段四:精通与影响力(3 年以上)
- 复杂度掌控:高并发实战(限流/削峰/多级缓存/弹性伸缩)、跨机房多活、大规模数据架构(分库分表/数仓/流批一体);
- 治理能力:建立组织级架构规范、技术雷达、ADR 制度、架构评审委员会;
- 成本与组织:云成本优化(FinOps)、团队拓扑设计(用架构影响组织);
- 软技能:技术说服(用数据与权衡表说服而非职位压制)、向上沟通(把架构风险翻译成业务语言)、导师带教;
- 检验标准:能为组织定义"什么是对的架构";新人架构师的问题你都能给出第一性原理的解释。
6.2 每日/每周刻意练习清单
- 每周:读一篇论文或顶级工程博客(ACM Queue、Uber/Netflix/美团技术博客);给自己系统的架构图做一次"健康度回顾"(依赖有没有变脏?);
- 每两周:写一条 ADR(哪怕是小决策),训练"记录权衡"的肌肉记忆;
- 每月:做一次故障复盘演练或混沌演练;读一本技术书的 1/3 并输出笔记;
- 每季度:重构一个自己三年前写的模块,体会架构腐化的具体形态。
6.3 架构师能力自评雷达(定期打分,每季度一次)
| 能力项 | 1 分(弱) | 5 分(精通) |
|---|---|---|
| 技术深度(至少一个领域) | 只会用 API | 读过内核/源码,能造轮子 |
| 架构特性设计 | 不知道质量属性 | 能量化设计并验证 P99/可用性 |
| 建模与文档 | 只会画流程图 | C4/arc42/ADR 熟练且团队采纳 |
| 分布式系统 | 会调中间件 | 理解一致性协议与故障模式 |
| 业务理解 | 被动接需求 | 主动提出架构级业务建议 |
| 沟通与影响力 | 讲不清权衡 | 能说服管理层投资架构改进 |
| 风险与运维 | 出事才响应 | 预案完备,演练常态化 |
| 成本意识 | 不看账单 | 资源利用率与成本可量化治理 |
参考资料索引
- The Open Group --- TOGAF® Standard, 10th Edition(https://publications.opengroup.org/c220)
- Simon Brown --- C4 Model(https://c4model.com)
- Philippe Kruchten ---《Architectural Blueprints---The "4+1" View Model》IEEE Software, 1995
- arc42 方法(https://arc42.org/method/)
- AWS Well-Architected Framework 可靠性支柱(https://docs.aws.amazon.com/zh_cn/wellarchitected/)
- Microsoft Azure --- 支持性能效率的云设计模式(https://learn.microsoft.com/zh-cn/azure/well-architected/performance-efficiency/design-patterns)
- Mark Richards & Neal Ford ---《Fundamentals of Software Architecture》《Software Architecture: The Hard Parts》
- Martin Kleppmann ---《Designing Data-Intensive Applications》
- ThoughtWorks --- 秒杀系统架构解析(https://www.thoughtworks.com/zh-cn/insights/blog/evolutionary-architecture/design-of-high-concurrency)
- Martin Fowler --- MonolithFirst / StranglerFig / Microservices 系列文章(https://martinfowler.com)