第 2 讲:架构设计三原则与四步法
核心结论(10 条必记)
- 合适原则:合适优于业界领先 -- 架构要匹配业务规模、团队能力、资源约束
- 简单原则:简单优于复杂 -- 能用简单方案解决的,不要用复杂方案
- 演化原则:演化优于一步到位 -- 架构是演进的,不是一开始就设计完美的
- 四步法第一步:识别复杂度(最重要) -- 方向错了,后面都白搭
- 四步法第二步:设计 3-5 个备选方案 -- 有差异性,不是同一方案的变体
- 四步法第三步:多维度评估,选最合适的 -- 综合考虑团队能力和资源约束
- 四步法第四步:细化落地,输出设计文档 -- 架构设计文档是可追溯的重要产出
- 三原则的关系:合适定方向、简单定方案、演化定时机
- 不要为"设计模式"而设计,忘了目的是解决问题
- 如果用一张 A4 纸画不清楚系统架构,那可能太复杂了
一、为什么需要架构设计原则和方法?
场景 1:无从下手
产品经理: "我们要做一个秒杀系统。"
开发小李: "好的......然后呢?我该怎么开始设计架构?"
小李百度了几十篇文章,每篇都不一样,最后更迷茫了。
问题:缺乏系统化的设计方法
场景 2:决策困难
架构评审会上: 小王说性能最好选 A,小张说可用性最高选 B,小刘说最简单选 C。 会议开了两小时,没有结论。
问题:缺乏决策原则
场景 3:过度设计
某创业公司,产品还没上线,3 个开发,技术负责人决定用微服务 + 异地多活 + Kubernetes,"一步到位"。 三个月后,系统还没上线,钱快烧完了。
问题:违反了架构设计原则
二、架构设计三大原则
原则一:合适原则
合适优于业界领先。
架构设计首先要合适,不是追求最先进。合适意味着与业务规模、团队能力、资源约束相匹配。
架构是有成本的(开发、维护、学习、运维),越复杂的架构成本越高。如果业务规模撑不起这个成本,再先进的架构也是负担。
反面案例
案例 1:创业公司照搬阿里中台
某创业公司(20 人、日活 5000、业务还在探索期)决定搞中台。 花了半年搭中台,业务迭代严重滞后,最后公司倒闭了。
阿里中台是为了支撑几十个业务线、几万人协作,创业公司根本不需要。
案例 2:3 人团队搞 20 个微服务
每个人要维护 6-7 个服务,排查问题要跨多个服务,部署、测试、运维都很痛苦,效率反而下降。
微服务有"三个火枪手原则":一个服务最好 3 个人维护。3 个人最多维护 1-3 个服务。
正面案例:Instagram 的单体架构
2012 年被 Facebook 收购时,13 名员工服务 3000 万用户,用的是最简单的 Django 单体架构。后来用户增长到几亿,才开始做服务拆分。
早期选择了合适的架构,把精力放在产品上,等业务真正需要时再演进。
如何判断"合适"?
| 维度 | 问题 |
|---|---|
| 业务规模 | 当前用户量、数据量、并发量?未来 1 年预期? |
| 团队规模 | 有多少开发?多少运维?技术水平? |
| 资源约束 | 有多少预算?多少时间? |
| 业务阶段 | MVP 探索期?快速增长期?稳定期? |
如果这个架构方案的维护成本超过了它带来的收益,那就是不合适的。
原则二:简单原则
简单优于复杂。
能用简单方案解决的,不要用复杂方案。复杂度是架构的敌人,简单的系统更容易理解、维护、演进。
软件系统有个规律:复杂度会随着时间指数级增长。 一开始就很复杂,一年后没人看得懂,两年后只能推倒重来。
反面案例
案例 1:过度抽象
某订单系统搞了订单工厂、订单策略、订单适配器、订单建造者、订单装饰器、订单代理...... 一个简单下单流程代码跳了十几层,新人三个月看不懂,改个小功能要改十几个类。
为了"设计模式"而设计,忘了目的是解决问题。
案例 2:过度技术栈
后端 Java + Go + Python + Node.js,数据库 MySQL + PostgreSQL + MongoDB + Redis + ES,消息队列 Kafka + RabbitMQ + RocketMQ...... 没人能全部掌握,招人困难,运维噩梦。
正面案例:Stack Overflow 的架构
C# + ASP.NET + SQL Server + Redis + Elasticsearch + HAProxy,就这么简单,支撑了每月几十亿的 PV。
如何判断"简单"?
| 问题 | 简单 | 复杂 |
|---|---|---|
| 新人多久能看懂? | 1-2 周 | 1-3 个月 |
| 改一个小功能要改几处? | 1-3 处 | 10+ 处 |
| 排查问题跨多少系统? | 1-3 个 | 10+ 个 |
| 技术栈有几种? | 2-5 种 | 10+ 种 |
如果你用一张 A4 纸画不清楚系统架构,那可能太复杂了。
原则三:演化原则
演化优于一步到位。
架构是演化出来的,不是一开始就设计完美的。不要试图预测未来所有可能性,等问题真正出现时,再做相应的架构调整。
原因:
- 未来不可预测 -- 不知道业务方向、用户量、会遇到什么问题
- 提前设计成本高 -- 可能设计了用不上的功能,甚至方向都是错的
- 等问题出现再解决更准确 -- 问题清晰了方案才能对症下药
经典案例:淘宝架构演进
| 阶段 | 时间 | 规模 | 问题 | 方案 |
|---|---|---|---|---|
| PHP 时代 | 2003-2004 | 刚起步 | -- | LAMP 单体 |
| Java 时代 | 2004-2007 | 快速增长 | PHP 性能瓶颈 | 迁移 Java,引入 MVC |
| 分布式时代 | 2007-2009 | 千万级用户 | 单体太大、DB 瓶颈 | 服务化 + 分库分表 |
| 异地多活 | 2009-2013 | 亿级用户 | 单机房风险 | 跨城容灾 |
| 中台时代 | 2013-至今 | 几十个业务线 | 重复建设 | 能力复用 |
如果 2003 年就按 2023 年的架构设计,淘宝可能早就死了。每一次演进,都是遇到真实问题后的解决方案。
如何判断"该演进了"?
| 信号 | 说明 |
|---|---|
| 性能瓶颈 | 响应时间变慢、QPS 上不去 |
| 可用性问题 | 经常宕机、故障恢复慢 |
| 团队协作困难 | 代码冲突多、部署相互阻塞 |
| 维护成本高 | 改一个小功能要改很多地方 |
| 扩容困难 | 加机器效果不明显 |
当前架构已经成为业务发展的瓶颈,而不是支撑。
三原则小结
| 原则 | 核心思想 | 关键词 |
|---|---|---|
| 合适原则 | 合适优于业界领先 | 匹配业务、团队、资源 |
| 简单原则 | 简单优于复杂 | KISS、易理解、易维护 |
| 演化原则 | 演化优于一步到位 | 迭代、按需、不预测未来 |
合适原则 -> 告诉你选什么方向
简单原则 -> 告诉你选什么方案
演化原则 -> 告诉你什么时候做三、架构设计四步法
第一步:识别复杂度
↓
第二步:设计备选方案
↓
第三步:评估和选择
↓
第四步:细化和落地第一步:识别复杂度
架构设计的第一步,是识别系统的核心复杂度在哪里。这是最重要的一步。
反面案例
某内部管理系统(100 人、最多 10 并发、上班时间能用就行),团队花了三个月设计分库分表 + 读写分离 + 异地多活 + 微服务。 真正的问题(业务逻辑复杂)反而没解决好。
没有识别真正的复杂度。核心复杂度是业务逻辑复杂,不是高性能、高可用。
如何识别复杂度?
步骤 1:明确系统的核心功能
- 这个系统是做什么的?
- 最核心的功能是什么?
- 用户最关心什么?
步骤 2:对照三大复杂度来源逐个分析
| 复杂度 | 分析问题 |
|---|---|
| 高性能 | 预期 QPS?响应时间?数据量?是否有高并发场景? |
| 高可用 | 可用性要求?宕机影响?是否需要 7x24? |
| 可扩展 | 未来功能变化?团队扩大?用户量增长? |
步骤 3:确定核心复杂度
通常一个系统会有 1-2 个核心复杂度,不会全都有。
复杂度识别模板
【系统名称】:_________________
【核心功能】:
1. _________________
2. _________________
【高性能分析】:
- 预期 QPS:_______
- 响应时间要求:_______ ms
- 高性能复杂度等级:低 / 中 / 高
【高可用分析】:
- 可用性要求:_______ %
- 宕机影响:_________________
- 高可用复杂度等级:低 / 中 / 高
【可扩展分析】:
- 未来 1 年变化预期:_______
- 可扩展复杂度等级:低 / 中 / 高
【核心复杂度结论】:
主要复杂度:_________________
次要复杂度:_________________常见复杂度判断标准
| 复杂度 | 低 | 中 | 高 |
|---|---|---|---|
| 性能 | QPS < 1000 | 1000-10000 | QPS > 10000 |
| 可用性 | < 99% | 99%-99.9% | > 99.9% |
| 数据量 | < 100 万 | 100 万-1 亿 | > 1 亿 |
| 团队 | < 5 人 | 5-20 人 | > 20 人 |
第二步:设计备选方案
针对核心复杂度,设计 3-5 个备选方案。
为什么要多个方案?
- 避免思维定式 -- 只想一个方案容易陷入局部最优
- 便于评估决策 -- 有对比才能看出优劣
- 降低风险 -- 首选方案有问题还有备选
方案设计的要点
要点 1:方案要有差异性
不是同一方案的不同配置,而是本质不同的方案。
要点 2:方案要覆盖不同取向
性能优先、可用性优先、简单性优先、成本优先,覆盖不同维度。
要点 3:方案要可落地
考虑团队能力、时间约束、资源是否充足。
备选方案模板
【方案名称】:_________________
【方案概述】:一句话描述
【核心思路】:1. ___ 2. ___ 3. ___
【关键技术】:___
【优点】:1. ___ 2. ___
【缺点】:1. ___ 2. ___
【风险】:___
【适用场景】:___实战案例:秒杀系统备选方案
核心复杂度:高性能(瞬时高并发)
方案 A:纯数据库方案
用户 → Nginx → 应用服务器 → MySQL
优点:架构简单、数据一致性好、开发成本低
缺点:性能差、数据库容易成为瓶颈
适用:QPS < 1000 的小规模活动方案 B:缓存 + 数据库方案
用户 → Nginx → 应用服务器 → Redis(扣库存)→ MySQL(异步创建订单)
优点:性能高(Redis 单机 10 万 QPS)、架构相对简单
缺点:缓存和数据库一致性问题、Redis 宕机风险
适用:QPS 1000-10 万的中等规模方案 C:缓存 + 消息队列方案
用户 → Nginx → 应用服务器 → Redis(扣库存)→ 消息队列 → 消费者 → MySQL
优点:性能极高、削峰效果好、数据库压力小
缺点:架构复杂、用户体验变异步、需处理消息丢失/重复消费
适用:QPS > 10 万的大规模活动方案 D:分层过滤方案
用户 → CDN → Nginx(限流)→ 应用(校验)→ Redis → 消息队列 → MySQL
优点:性能最高、层层保护后端
缺点:架构最复杂、各层需协调
适用:QPS > 100 万的超大规模第三步:评估和选择
用多个维度评估备选方案,选出最合适的方案。
评估维度
| 维度 | 说明 |
|---|---|
| 性能 | 能否满足 QPS、响应时间要求 |
| 可用性 | 故障概率、恢复时间 |
| 可扩展性 | 加机器、加功能是否方便 |
| 成本 | 开发成本、运维成本、硬件成本 |
| 复杂度 | 团队能否驾驭、新人学习成本 |
评估方法:360 度环评
步骤 1:确定权重(秒杀系统示例)
- 性能 30%(最重要)
- 可用性 20%
- 成本 20%
- 复杂度 20%
- 可扩展性 10%
步骤 2:打分(1-5 分)
| 方案 | 性能 | 可用性 | 成本 | 复杂度 | 可扩展性 |
|---|---|---|---|---|---|
| 方案 A | 2 | 4 | 5 | 5 | 2 |
| 方案 B | 4 | 3 | 4 | 4 | 3 |
| 方案 C | 5 | 3 | 3 | 3 | 4 |
| 方案 D | 5 | 4 | 2 | 2 | 5 |
步骤 3:计算加权得分
| 方案 | 加权总分 |
|---|---|
| 方案 A | 3.6 |
| 方案 B | 3.7 |
| 方案 C | 3.7 |
| 方案 D | 3.6 |
步骤 4:综合分析
光看分数还不够,还要考虑团队能力、时间约束、风险偏好、未来演进性。
实战案例:秒杀系统方案选择
背景: 团队 5 人、时间 2 个月、QPS 预期 5 万、有 Redis 经验无消息队列经验。
| 方案 | 加权得分 | 团队能力 | 时间 | 结论 |
|---|---|---|---|---|
| 方案 A | 3.6 | 能做 | 够 | 性能不够 |
| 方案 B | 3.7 | 能做 | 够 | 推荐 |
| 方案 C | 3.7 | 缺经验 | 不够 | 风险高 |
| 方案 D | 3.6 | 太复杂 | 不够 | 过度设计 |
选择方案 B:性能满足、团队有经验、2 个月可完成、后续可演进到方案 C。
决策原则
- 优先满足核心需求 -- 核心复杂度是性能就优先性能
- 分数接近选简单方案 -- 简单方案风险更低
- 考虑演进性 -- 不要选到死胡同
- 考虑团队能力 -- 不要高估团队能力
第四步:细化和落地
将选定的方案细化,输出可执行的设计文档。
细化的内容
| 内容 | 说明 |
|---|---|
| 系统架构图 | 组件、关系、数据流、关键接口 |
| 技术选型 | 语言、框架、数据库、缓存、消息队列 |
| 数据设计 | 表结构、缓存数据结构、分片策略 |
| 接口设计 | 服务间接口、对外接口、协议 |
| 容量规划 | 服务器数量、DB 配置、缓存容量 |
| 高可用设计 | 故障应对、降级、限流、熔断 |
| 监控报警 | 监控指标、报警阈值、应急预案 |
| 灰度方案 | 灰度发布、回滚策略 |
架构设计文档模板
# XXX 系统架构设计文档
## 1. 背景
### 1.1 业务背景
### 1.2 技术背景
## 2. 需求分析
### 2.1 功能需求
### 2.2 非功能需求(性能、可用性、数据量)
## 3. 复杂度分析
### 3.1 高性能分析
### 3.2 高可用分析
### 3.3 可扩展分析
### 3.4 复杂度结论
## 4. 备选方案
### 4.1 方案一(描述、优缺点)
### 4.2 方案二
### 4.3 方案三
## 5. 方案评估
### 5.1 评估维度与权重
### 5.2 评估打分
### 5.3 方案选择与理由
## 6. 详细设计
### 6.1 系统架构图
### 6.2 技术选型
### 6.3 数据设计
### 6.4 接口设计
### 6.5 容量规划
## 7. 高可用设计
### 7.1 故障分析(FMEA)
### 7.2 降级方案
### 7.3 限流方案
## 8. 监控报警
## 9. 部署方案(灰度、回滚)
## 10. 风险与应对
## 11. 里程碑计划四、四步法完整案例:消息队列架构设计
背景
某电商公司要自研消息队列中间件,用于内部系统解耦和异步处理。日消息量 1000 万条,消息大小 1KB 左右。
第一步:识别复杂度
| 复杂度 | 分析 | 等级 |
|---|---|---|
| 高性能 | 峰值 1200 QPS,不算高 | 低 |
| 高可用 | 消息不能丢,可用性 99.9% | 中(核心) |
| 可扩展 | 未来可能接入更多系统、消息量增长 10 倍 | 中 |
核心复杂度:高可用(消息不能丢)
第二步:设计备选方案
方案 A:MySQL 消息表
生产者 → MySQL(消息表)← 消费者(轮询)
优点:实现简单、消息持久化不丢失
缺点:性能一般、轮询效率低方案 B:Redis List
生产者 → Redis List ← 消费者(BLPOP)
优点:性能高、实现简单
缺点:Redis 宕机消息可能丢失、不支持消息确认方案 C:自研仿 Kafka
生产者 → Broker 集群(磁盘持久化)← 消费者
优点:高性能、高可用(副本)、可扩展(分区)
缺点:实现复杂、开发周期长第三步:评估和选择
权重:可用性 30%、性能 20%、复杂度 25%、可扩展 15%、成本 10%
| 方案 | 加权得分 | 核心问题 |
|---|---|---|
| 方案 A | 3.45 | 性能一般但满足可用性 |
| 方案 B | 3.60 | 可用性差、消息可能丢失 |
| 方案 C | 3.75 | 得分最高但实现复杂 |
选择方案 A(MySQL 方案)
理由:满足核心需求(消息不丢)、实现简单风险低、2 个月可完成、后续可演进到方案 C。
第四步:细化
CREATE TABLE mq_message (
id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
topic VARCHAR(128) NOT NULL,
msg_key VARCHAR(128) NOT NULL,
msg_body TEXT NOT NULL,
status TINYINT NOT NULL DEFAULT 0 COMMENT '0-待消费 1-已消费',
retry_count INT NOT NULL DEFAULT 0,
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_topic_status (topic, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;高可用:MySQL 主从复制、消息重试机制、死信队列、监控报警。
五、面试高频题
Q1:架构设计有哪些原则?
三大原则:合适原则(合适优于业界领先,匹配业务规模和团队能力)、简单原则(简单优于复杂,KISS)、演化原则(演化优于一步到位,遇到问题再演进)。
Q2:你是怎么做架构设计的?
四步法:1) 识别核心复杂度(高性能/高可用/可扩展);2) 设计 3-5 个有差异性的备选方案;3) 多维度评估(性能、可用性、成本、复杂度),综合考虑团队能力;4) 细化落地,输出设计文档。
Q3:如何判断一个架构方案好不好?
从五个维度:是否解决核心问题、是否满足质量要求(性能/可用性/可扩展)、是否合适(匹配团队能力和资源约束)、是否简单(容易理解和维护)、是否可演进(便于后续升级)。
Q4:你做过的架构方案是怎么选型的?
用 STAR 法:Situation(背景规模)→ Task(核心复杂度)→ Action(设计 3 个方案、评估选择)→ Result(上线效果、经验教训)。
Q5:如何避免过度设计?
遵循三原则:1) 问自己"是当前需要还是未来可能需要",未来可能需要的先不做;2) 问自己"有没有更简单的方案";3) 问自己"这个问题现在必须解决吗"。具体方法:先做最小可行架构、用数据说话、让团队挑战你的设计。
六、练习题
练习 1:原则应用
判断以下场景违反了哪个原则:
场景 A: 3 人团队、日活 500,使用微服务架构拆分 15 个服务。
场景 B: 只在中国运营,一开始就做完整的多语言、多时区、多货币支持。
场景 C: 消息量每天 1 万条,因为竞品用了 Kafka 就决定也用 Kafka。
练习 2:复杂度识别
分析以下系统的核心复杂度:
系统 A: 在线考试系统 -- 10 万学生、1 万人同时在线、不能宕机、成绩不能错。
系统 B: 内部 OA 系统 -- 500 员工、日常办公、上班时间能用就行。
系统 C: 电商推荐系统 -- 1000 万用户、实时推荐、< 100ms。
练习 3:方案设计
为短链接服务设计 3 个备选方案:日均新增 100 万短链接、日均访问 1 亿次、短链接永久有效。
练习 4:架构文档
选择一个你熟悉的系统,按照本讲的架构设计文档模板,写一份简化版文档(至少包含背景、复杂度分析、备选方案、方案选择、系统架构图)。
下一讲预告
第 3 讲:高性能架构模式(上)-- 单机高性能
- I/O 模型:PPC、TPC、Reactor、Proactor
- Reactor 的三种变体
- Nginx、Redis、Netty 的 I/O 模型分析
- 各模型的适用场景和选型建议