07-系统设计与架构
核心理念
好的架构不是设计出来的,是演进出来的。
1x工程师: 实现功能
10x工程师: 设计良好的架构
100x工程师: 构建可演进的平台
系统设计的三个境界
境界1: 功能实现(1x)
特征:
需求 → 实现 → 交付
思维模式:
- 关注: 功能完整性
- 目标: 能work就行
- 问题: 难以扩展、难以维护
典型表现:
// 所有代码都在一个文件
// 所有逻辑都在一个函数
function handleUserLogin(req, res) {
// 参数验证
// 数据库查询
// 密码验证
// Session管理
// 日志记录
// 返回响应
// ... 200行代码
}
境界2: 架构设计(10x)
特征:
需求分析 → 架构设计 → 模块划分 → 实现
思维模式:
- 关注: 系统质量属性(性能、可维护性、可扩展性)
- 目标: 长期可维护
- 价值: 降低维护成本,支撑业务增长
典型架构模式:
分层架构(Layered Architecture)
┌─────────────────────┐
│ Presentation │ 表现层(API/UI)
├─────────────────────┤
│ Business Logic │ 业务逻辑层
├─────────────────────┤
│ Data Access │ 数据访问层
├─────────────────────┤
│ Database │ 数据存储层
└─────────────────────┘
优势:
- 职责清晰
- 易于理解
- 便于测试
劣势:
- 层级过多时性能损失
- 跨层依赖复杂
境界3: 平台思维(100x)
特征:
业务抽象 → 平台设计 → 能力开放 → 生态构建
思维模式:
- 关注: 可复用性、可扩展性、生态
- 目标: 一次建设,多次复用,赋能他人
- 价值: 组织级影响
平台化架构:
业务A 业务B 业务C
↓ ↓ ↓
┌──────────────────────────┐
│ 业务能力层 │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │用户│ │订单│ │商品│ │
│ └────┘ └────┘ └────┘ │
├──────────────────────────┤
│ 平台能力层 │
│ ┌────┐ ┌────┐ ┌────┐ │
│ │认证│ │支付│ │消息│ │
│ └────┘ └────┘ └────┘ │
├──────────────────────────┤
│ 基础设施层 │
│ 数据库 缓存 消息队列 │
└──────────────────────────┘
特点:
- 通用能力平台化
- 业务能力可组合
- 系统高度可复用
架构设计原则
原则1: 高内聚、低耦合
高内聚: 相关功能聚集在一起
❌ 低内聚示例:
User模块包含: 用户管理、订单处理、支付逻辑
✓ 高内聚示例:
User模块: 用户CRUD、认证授权
Order模块: 订单管理
Payment模块: 支付逻辑
低耦合: 模块间依赖最小化
❌ 高耦合示例:
OrderService直接访问UserRepository
OrderService直接调用PaymentService的私有方法
✓ 低耦合示例:
OrderService通过接口依赖UserService
OrderService通过事件通知PaymentService
原则2: 单一职责原则(SRP)
定义: 一个模块只负责一件事。
// ❌ 违反SRP
class UserService {
createUser() { }
updateUser() { }
deleteUser() { }
sendEmail() { } // 邮件发送不是用户管理的职责
generateReport() { } // 报表生成不是用户管理的职责
}
// ✓ 符合SRP
class UserService {
createUser() { }
updateUser() { }
deleteUser() { }
}
class EmailService {
sendEmail() { }
}
class ReportService {
generateReport() { }
}
原则3: 开闭原则(OCP)
定义: 对扩展开放,对修改关闭。
// ❌ 违反OCP
class PaymentProcessor {
process(type) {
if (type === 'alipay') {
// 支付宝逻辑
} else if (type === 'wechat') {
// 微信逻辑
}
// 新增支付方式需要修改这里
}
}
// ✓ 符合OCP
interface PaymentMethod {
pay(amount: number): Promise<void>;
}
class AlipayPayment implements PaymentMethod {
async pay(amount: number) { /* ... */ }
}
class WechatPayment implements PaymentMethod {
async pay(amount: number) { /* ... */ }
}
class PaymentProcessor {
constructor(private method: PaymentMethod) {}
async process(amount: number) {
await this.method.pay(amount);
}
}
// 新增支付方式只需添加新类,不需要修改现有代码
class StripePayment implements PaymentMethod {
async pay(amount: number) { /* ... */ }
}
原则4: 依赖倒置原则(DIP)
定义: 依赖抽象而非具体实现。
// ❌ 依赖具体实现
class UserService {
private mysql: MySQL; // 直接依赖MySQL
constructor() {
this.mysql = new MySQL();
}
getUser(id: string) {
return this.mysql.query(`SELECT * FROM users WHERE id = ${id}`);
}
}
// ✓ 依赖抽象
interface Database {
query(sql: string): Promise<any>;
}
class MySQL implements Database {
async query(sql: string) { /* ... */ }
}
class PostgreSQL implements Database {
async query(sql: string) { /* ... */ }
}
class UserService {
constructor(private db: Database) {} // 依赖接口
getUser(id: string) {
return this.db.query(`SELECT * FROM users WHERE id = ${id}`);
}
}
// 可以灵活切换数据库
const userService = new UserService(new PostgreSQL());
常见架构模式
模式1: 分层架构(Layered Architecture)
┌──────────────────┐
│ Controller │ ← 接收请求,返回响应
├──────────────────┤
│ Service │ ← 业务逻辑
├──────────────────┤
│ Repository │ ← 数据访问
├──────────────────┤
│ Database │ ← 数据存储
└──────────────────┘
适用场景:
- 中小型应用
- 业务逻辑清晰
- 团队规模小
优势:
- 简单易懂
- 便于测试
- 职责清晰
示例:
// Controller层
class UserController {
constructor(private userService: UserService) {}
async createUser(req, res) {
const user = await this.userService.create(req.body);
res.json(user);
}
}
// Service层
class UserService {
constructor(private userRepo: UserRepository) {}
async create(data: UserDTO) {
// 业务逻辑验证
if (!data.email) throw new Error('Email required');
// 调用Repository
return await this.userRepo.save(data);
}
}
// Repository层
class UserRepository {
async save(data: UserDTO) {
// 数据库操作
return await db.insert('users', data);
}
}
模式2: 六边形架构(Hexagonal Architecture)
也称为"端口和适配器架构"。
┌─────────────┐
│ 外部系统 │
└──────┬──────┘
│ 适配器
┌──────▼──────────┐
│ Port (接口) │
├─────────────────┤
│ 核心业务逻辑 │
├─────────────────┤
│ Port (接口) │
└──────┬──────────┘
│ 适配器
┌──────▼──────┐
│ 数据库 │
└─────────────┘
核心思想: 业务逻辑独立于外部依赖。
优势:
- 业务逻辑可独立测试
- 易于替换外部依赖
- 清晰的边界
示例:
// 核心业务逻辑(领域层)
class User {
constructor(
private id: string,
private email: string,
private password: string
) {}
changePassword(newPassword: string) {
// 业务规则
if (newPassword.length < 8) {
throw new Error('Password too short');
}
this.password = newPassword;
}
}
// 端口(接口)
interface UserRepository {
save(user: User): Promise<void>;
findById(id: string): Promise<User | null>;
}
interface EmailService {
send(to: string, subject: string, body: string): Promise<void>;
}
// 业务服务(应用层)
class UserService {
constructor(
private userRepo: UserRepository,
private emailService: EmailService
) {}
async changePassword(userId: string, newPassword: string) {
const user = await this.userRepo.findById(userId);
if (!user) throw new Error('User not found');
user.changePassword(newPassword);
await this.userRepo.save(user);
await this.emailService.send(
user.email,
'Password Changed',
'Your password has been changed'
);
}
}
// 适配器(基础设施层)
class MongoUserRepository implements UserRepository {
async save(user: User) {
// MongoDB实现
}
async findById(id: string) {
// MongoDB实现
}
}
class SendGridEmailService implements EmailService {
async send(to: string, subject: string, body: string) {
// SendGrid实现
}
}
// 组装
const userService = new UserService(
new MongoUserRepository(),
new SendGridEmailService()
);
模式3: 微服务架构
API Gateway
↓
┌──────────────┼──────────────┐
↓ ↓ ↓
用户服务 订单服务 商品服务
↓ ↓ ↓
用户DB 订单DB 商品DB
特点:
- 服务独立部署
- 数据库独立
- 技术栈可异构
适用场景:
- 大型应用
- 团队规模大
- 业务复杂
优势:
- 独立扩展
- 技术多样性
- 故障隔离
挑战:
- 分布式复杂性
- 数据一致性
- 服务治理
可扩展性设计
维度1: 垂直扩展(Scale Up)
定义: 增加单个服务器的资源(CPU、内存)。
单机 4核8G
↓
单机 16核32G
↓
单机 64核128G
优势:
- 简单直接
- 无需改代码
局限:
- 有物理上限
- 成本指数增长
- 单点故障风险
维度2: 水平扩展(Scale Out)
定义: 增加服务器数量。
1台服务器
↓
3台服务器(负载均衡)
↓
10台服务器(分布式)
优势:
- 理论无上限
- 成本线性增长
- 高可用
设计要点:
1. 无状态服务
// ❌ 有状态(无法水平扩展)
let requestCount = 0;
app.get('/api', (req, res) => {
requestCount++; // 状态存在内存中
res.json({ count: requestCount });
});
// ✓ 无状态(可水平扩展)
app.get('/api', async (req, res) => {
const count = await redis.incr('request_count'); // 状态存储在外部
res.json({ count });
});
2. 负载均衡
Load Balancer
↓
┌─────────┼─────────┐
↓ ↓ ↓
Server1 Server2 Server3
常见算法:
- Round Robin: 轮询
- Least Connections: 最少连接
- IP Hash: IP哈希(会话保持)
3. 数据分片(Sharding)
用户数据
Hash(user_id) % 3
Shard 0: user 0, 3, 6, 9...
Shard 1: user 1, 4, 7, 10...
Shard 2: user 2, 5, 8, 11...
高可用设计
策略1: 冗余
单点消除:
❌ 单点故障:
App → DB → 如果DB挂了,整个系统不可用
✓ 主从复制:
┌→ DB Master (读写)
App → ─┤
└→ DB Slave (只读)
✓ 多主复制:
┌→ DB Master 1 ←─┐
App ─┤ │ 双向复制
└→ DB Master 2 ←─┘
策略2: 熔断
防止雪崩效应:
class CircuitBreaker {
private failureCount = 0;
private lastFailureTime = 0;
private state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
async call(fn: Function) {
if (this.state === 'OPEN') {
if (Date.now() - this.lastFailureTime > 60000) {
this.state = 'HALF_OPEN';
} else {
throw new Error('Circuit breaker is OPEN');
}
}
try {
const result = await fn();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
private onSuccess() {
this.failureCount = 0;
this.state = 'CLOSED';
}
private onFailure() {
this.failureCount++;
this.lastFailureTime = Date.now();
if (this.failureCount >= 5) {
this.state = 'OPEN';
}
}
}
// 使用
const breaker = new CircuitBreaker();
await breaker.call(() => externalAPI.call());
策略3: 限流
保护系统不被压垮:
// 令牌桶算法
class RateLimiter {
private tokens: number;
private lastRefillTime: number;
constructor(
private capacity: number, // 桶容量
private refillRate: number // 每秒补充的令牌数
) {
this.tokens = capacity;
this.lastRefillTime = Date.now();
}
async acquire(): Promise<boolean> {
this.refill();
if (this.tokens >= 1) {
this.tokens -= 1;
return true;
}
return false;
}
private refill() {
const now = Date.now();
const timePassed = (now - this.lastRefillTime) / 1000;
const tokensToAdd = timePassed * this.refillRate;
this.tokens = Math.min(this.capacity, this.tokens + tokensToAdd);
this.lastRefillTime = now;
}
}
// 使用
const limiter = new RateLimiter(100, 10); // 容量100,每秒补充10个
app.get('/api', async (req, res) => {
if (!await limiter.acquire()) {
return res.status(429).send('Too Many Requests');
}
// 处理请求
});
演进式架构
核心思想
不要大爆炸重写,要渐进式演进。
❌ 大爆炸重写:
老系统 → 停止开发 → 重写3个月 → 切换 → 失败风险高
✓ 渐进式演进:
老系统 → 逐步抽取模块 → 新老共存 → 逐步迁移 → 风险可控
演进策略
策略1: 绞杀者模式(Strangler Pattern)
阶段1: 新老系统共存
Router
↓
┌────┴────┐
↓ ↓
新系统A 老系统
(10%流量) (90%流量)
阶段2: 逐步迁移
Router
↓
┌────┴────┐
↓ ↓
新系统A+B 老系统
(50%流量) (50%流量)
阶段3: 完全迁移
新系统A+B+C
(100%流量)
老系统下线
策略2: 分支抽象(Branch by Abstraction)
// 步骤1: 创建抽象层
interface PaymentService {
pay(amount: number): Promise<void>;
}
// 步骤2: 老实现适配抽象
class OldPaymentService implements PaymentService {
async pay(amount: number) {
// 老逻辑
}
}
// 步骤3: 新实现
class NewPaymentService implements PaymentService {
async pay(amount: number) {
// 新逻辑
}
}
// 步骤4: 功能开关控制
class PaymentServiceFactory {
static create(): PaymentService {
if (featureFlag.isEnabled('new_payment')) {
return new NewPaymentService();
}
return new OldPaymentService();
}
}
// 使用
const paymentService = PaymentServiceFactory.create();
await paymentService.pay(100);
// 步骤5: 逐步切换 → 完全切换 → 删除老代码
架构决策记录(ADR)
为什么需要ADR
问题: 6个月后,没人记得为什么这样设计。
解决: 记录重要的架构决策。
ADR模板
# ADR-001: 使用PostgreSQL作为主数据库
## 状态
已采纳 (Accepted)
## 背景
我们需要选择一个关系型数据库来存储用户和订单数据。
## 决策
选择PostgreSQL作为主数据库。
## 理由
1. 支持JSON类型,灵活性好
2. 支持全文搜索
3. 社区活跃,生态成熟
4. 团队有使用经验
5. 开源免费
## 备选方案
- MySQL: 更流行,但JSON支持较弱
- MongoDB: 灵活性最好,但缺少事务支持
## 后果
### 正面影响
- 支持复杂查询
- 数据一致性强
### 负面影响
- 学习曲线比MySQL陡
- 性能调优需要经验
## 相关决策
- ADR-002: 使用Redis作为缓存
## 更新记录
- 2025-12-01: 初始决策
架构设计实践清单
需求阶段
- 明确功能需求和非功能需求
- 识别核心业务流程
- 估算规模(用户数、数据量、QPS)
- 明确约束条件(预算、时间、技术栈)
设计阶段
- 选择合适的架构模式
- 模块划分和职责定义
- 定义接口和数据模型
- 识别风险点
评审阶段
- 可行性评估
- 性能评估
- 可扩展性评估
- 成本评估
- 记录ADR
实施阶段
- MVP优先
- 增量开发
- 持续集成
- 监控和日志
演进阶段
- 收集反馈
- 性能优化
- 架构重构
- 技术债偿还
关键要点总结
- 演进思维: 架构是演进的,不是一次设计完美
- 权衡取舍: 没有最好的架构,只有最合适的
- 简单优先: 从简单开始,需要时再复杂化
- 文档化: 记录重要的架构决策(ADR)
- 可测试性: 好的架构是易于测试的
核心公式:
好架构 = 满足需求 + 可扩展 + 可维护 + 合理成本
100x架构 = 平台化思维 + 演进能力 + 生态赋能