8.2 架构思维与系统设计
从功能到架构
新手的误区
❌ 错误思路:
"用户需要注册 → 创建用户表 → 实现注册功能"
"用户需要登录 → 创建session → 实现登录功能"
问题:只看到表面需求,没有考虑整体架构✅ 正确思路:
"用户系统是核心基础设施,需要考虑:
- 认证 vs 授权
- 单点登录 (SSO)
- 安全策略
- 扩展性
- 性能要求
- 数据一致性"架构思维的核心
4个维度:
1. 功能维度
├─ 核心功能:必须有的
├─ 辅助功能:提升体验的
└─ 扩展功能:未来可能加的
2. 数据维度
├─ 数据模型:实体关系
├─ 数据流向:业务流程
└─ 数据存储:选择数据库
3. 技术维度
├─ 前端架构:单页/多页/SSR/SSG
├─ 后端架构:单体/微服务/无服务器
└─ 部署架构:云/容器/边缘
4. 业务维度
├─ 用户画像:谁在使用
├─ 使用场景:何时何地使用
└─ 商业目标:如何盈利架构决策框架 (ADR)
ADR 模板
架构决策记录 (Architecture Decision Record):
# ADR-001: 选择 Next.js 作为前端框架
## 背景
我们需要为 SaaS 产品选择前端框架,团队有 React 经验,产品需要 SEO 友好。
## 决策
选择 Next.js 14 (App Router)
## 理由
✅ SSR/SSG 支持,SEO友好
✅ 团队已有 React 经验
✅ 丰富的生态系统
✅ Vercel 原生支持,部署简单
✅ 混合渲染模式灵活
## 备选方案
- Remix:更注重 Web 标准,但生态较小
- Nuxt.js:Vue 生态,团队不熟悉
- Astro:静态站点强,但交互性一般
## 后果
✅ 收益:开发效率高,SEO好,部署简单
⚠️ 注意:需要学习 Next.js 特有概念决策记录模板
编号:ADR-[序号]
标题:[简洁描述]
状态:[已提议/已接受/已废弃/已替代]
## 背景
[问题的上下文]
## 决策
[我们决定做什么]
## 理由
[为什么做这个决定]
## 备选方案
[考虑过的其他方案]
## 后果
[正面影响/负面影响/未知]系统分层架构
三层架构模型
表示层 (Presentation Layer)
├─ 前端应用 (React/Vue)
├─ 移动端 (React Native/Flutter)
├─ 管理后台 (Admin Panel)
└─ API 文档 (Swagger/OpenAPI)
业务逻辑层 (Business Logic Layer)
├─ 用户服务 (User Service)
├─ 订单服务 (Order Service)
├─ 支付服务 (Payment Service)
└─ 通知服务 (Notification Service)
数据访问层 (Data Access Layer)
├─ ORM/ODM (Prisma/TypeORM)
├─ 数据库 (PostgreSQL/MySQL)
├─ 缓存 (Redis/Memcached)
└─ 文件存储 (S3/Cloudinary)分层设计原则
依赖倒置:
// ❌ 错误:上层依赖下层
class UserService {
private db = new PostgreSQLDatabase()
private redis = new RedisCache()
}
// ✅ 正确:依赖抽象
interface DatabaseInterface {
query(sql: string): Promise<any>
}
interface CacheInterface {
get(key: string): Promise<string>
set(key: string, value: string): Promise<void>
}
class UserService {
constructor(
private db: DatabaseInterface,
private cache: CacheInterface
) {}
}微服务 vs 单体
选择指南
小型产品 (1-3人团队):
推荐:单体架构
技术栈:Next.js + PostgreSQL + Prisma
优点:
✅ 开发简单
✅ 部署容易
✅ 调试方便
✅ 团队学习成本低
适用场景:
- MVP阶段
- 简单业务逻辑
- 有限用户量 (< 10万)中型产品 (5-15人团队):
推荐:模块化单体
技术栈:Next.js + NestJS + PostgreSQL
优点:
✅ 保持单体简单性
✅ 内部模块化
✅ 未来可平滑迁移
架构:
src/
├─ modules/
│ ├─ users/
│ ├─ orders/
│ └─ payments/
├─ shared/
│ ├─ database/
│ ├─ auth/
│ └─ utils/大型产品 (15人+团队):
推荐:微服务架构
技术栈:Node.js/Python/Go + Kubernetes
优点:
✅ 独立部署
✅ 技术栈灵活
✅ 团队自治
✅ 故障隔离
挑战:
⚠️ 运维复杂
⚠️ 数据一致性
⚠️ 调试困难数据架构设计
数据库设计流程
第1步:实体建模
第2步:关系分析
1:1 关系
- 用户 ↔ 用户资料
1:N 关系
- 项目 → 任务
- 用户 → 订单
N:M 关系
- 用户 ↔ 项目 (通过成员表)
- 项目 ↔ 标签 (通过关联表)第3步:性能优化
-- 索引设计
CREATE INDEX idx_tasks_project_id ON tasks(project_id);
CREATE INDEX idx_tasks_assignee_id ON tasks(assignee_id);
CREATE INDEX idx_tasks_status ON tasks(status);
-- 复合索引
CREATE INDEX idx_tasks_project_status ON tasks(project_id, status);
-- 部分索引
CREATE INDEX idx_active_projects ON projects(id) WHERE status = 'active';缓存策略
多级缓存:
L1: 浏览器缓存
├─ 静态资源 (CSS/JS/图片)
│ └─ 缓存时间:1年
└─ HTML页面
└─ 缓存时间:5分钟
L2: CDN缓存
├─ 静态资源
│ └─ 缓存时间:1年
└─ API响应 (GET请求)
└─ 缓存时间:1小时
L3: 服务器缓存
├─ Redis
│ ├─ 用户会话:24小时
│ ├─ API响应:1小时
│ └─ 数据库查询:30分钟
└─ 应用内存
├─ 配置信息:永不过期
└─ 热门数据:10分钟
L4: 数据库缓存
├─ 查询缓存
└─ 缓冲池缓存失效策略:
// 写透策略 (Write-Through)
async updateUser(id: string, data: UserData) {
// 1. 更新数据库
await db.users.update(id, data)
// 2. 更新缓存
await cache.set(`user:${id}`, data)
}
// 写回策略 (Write-Back)
async updateUser(id: string, data: UserData) {
// 1. 只更新缓存
await cache.set(`user:${id}`, data)
// 2. 异步写入数据库
queue.add(async () => {
await db.users.update(id, data)
})
}
// 失效策略 (Write-Around)
async updateUser(id: string, data: UserData) {
// 1. 更新数据库
await db.users.update(id, data)
// 2. 删除缓存
await cache.delete(`user:${id}`)
}API设计最佳实践
RESTful设计
资源命名:
✅ 正确:
GET /api/users // 获取用户列表
GET /api/users/:id // 获取特定用户
POST /api/users // 创建用户
PUT /api/users/:id // 更新用户
DELETE /api/users/:id // 删除用户
❌ 错误:
GET /api/getUsers
POST /api/createUser
GET /api/user/:id/delete状态码使用:
2xx - 成功
200 OK - 请求成功
201 Created - 资源创建成功
204 No Content - 删除成功
4xx - 客户端错误
400 Bad Request - 请求参数错误
401 Unauthorized - 未认证
403 Forbidden - 无权限
404 Not Found - 资源不存在
409 Conflict - 资源冲突
5xx - 服务器错误
500 Internal Server Error - 服务器错误
503 Service Unavailable - 服务不可用GraphQL vs REST
REST 适用场景:
✅ 简单CRUD操作
✅ 静态数据展示
✅ 缓存友好
✅ HTTP语义清晰
示例:
GET /api/products
GET /api/products/:id
POST /api/productsGraphQL 适用场景:
✅ 复杂数据查询
✅ 客户端灵活获取数据
✅ 减少网络请求
✅ 强类型系统
示例:
query {
product(id: "123") {
name
price
reviews {
author
content
rating
}
}
}事件驱动架构
事件模式
简单事件:
// 事件定义
interface UserRegisteredEvent {
type: 'user.registered'
payload: {
userId: string
email: string
timestamp: Date
}
}
// 事件发布
class UserService {
async register(data: RegisterData) {
const user = await db.users.create(data)
// 发布事件
eventBus.publish({
type: 'user.registered',
payload: {
userId: user.id,
email: user.email,
timestamp: new Date()
}
})
return user
}
}
// 事件订阅
eventBus.subscribe('user.registered', async (event) => {
// 发送欢迎邮件
await emailService.sendWelcomeEmail(event.payload.email)
// 创建默认设置
await settingsService.createDefault(event.payload.userId)
// 记录分析事件
await analytics.track('user_registered', event.payload)
})CQRS模式
命令查询职责分离:
// 命令 (写操作)
class CreateOrderCommand {
constructor(
public readonly userId: string,
public readonly items: OrderItem[],
public readonly total: number
) {}
}
class CreateOrderHandler {
async handle(command: CreateOrderCommand) {
// 1. 验证
await this.validator.validate(command)
// 2. 创建订单
const order = await db.orders.create({
userId: command.userId,
items: command.items,
total: command.total,
status: 'pending'
})
// 3. 发布事件
eventBus.publish(new OrderCreatedEvent(order))
return order
}
}
// 查询 (读操作)
class GetOrderQuery {
constructor(
public readonly orderId: string
) {}
}
class GetOrderHandler {
async handle(query: GetOrderQuery) {
// 从读模型 (优化后的视图) 获取
return await readDb.orders.findOne(query.orderId)
}
}安全架构
安全层级
第1层:网络安全
├─ HTTPS (SSL/TLS)
├─ CORS 配置
├─ DDoS 防护
└─ WAF (Web应用防火墙)
第2层:应用安全
├─ 身份认证 (OAuth/JWT)
├─ 授权控制 (RBAC)
├─ 输入验证
├─ 输出编码
└─ CSRF 防护
第3层:数据安全
├─ 敏感数据加密
├─ 密码哈希 (bcrypt)
├─ 数据库加密
├─ 备份加密
└─ 审计日志
第4层:运维安全
├─ 访问控制
├─ 密钥管理
├─ 漏洞扫描
├─ 安全审计
└─ 应急响应安全检查清单
## 认证安全
- [ ] 所有API都需要认证 (除了公开接口)
- [ ] 密码使用强哈希算法 (bcrypt/argon2)
- [ ] JWT使用强密钥和合理过期时间
- [ ] 多因素认证 (2FA) 支持
## 授权安全
- [ ] 最小权限原则
- [ ] 基于角色的访问控制 (RBAC)
- [ ] 资源级权限检查
- [ ] 避免水平越权
## 输入验证
- [ ] 服务端验证所有输入
- [ ] 使用白名单验证
- [ ] 限制输入长度
- [ ] SQL注入防护 (参数化查询)
## 数据保护
- [ ] 敏感数据加密存储
- [ ] API响应过滤敏感字段
- [ ] 日志不记录敏感信息
- [ ] 定期备份和恢复测试架构演进策略
渐进式架构
阶段1:MVP (Month 1-2)
简单单体
Next.js + PostgreSQL
- 核心功能
- 用户认证
- 基础管理阶段2:增长 (Month 3-6)
模块化单体
- 模块拆分
- 缓存引入
- 数据库优化
- CDN部署阶段3:扩展 (Month 6-12)
服务化
- 独立服务
- 事件驱动
- 异步处理
- 监控完善重构时机
需要重构的信号:
🔴 红色警告
- 代码耦合严重,难以修改
- 性能问题持续恶化
- 部署时间超过30分钟
- 团队开发速度明显下降
- 线上bug频繁出现
🟡 黄色注意
- 新功能开发时间变长
- 技术债务积累过多
- 测试覆盖率低于60%
- 文档严重滞后
🟢 绿色正常
- 新功能1-2天交付
- 测试覆盖率>80%
- 性能稳定
- 部署自动化架构决策原则
原则1:简单性优先
优先选择简单的解决方案
直到复杂度不可避免
简单 = 容易理解 + 容易维护 + 容易扩展原则2:可观测性
设计时考虑监控和调试
- 日志记录
- 性能指标
- 错误追踪
- 链路追踪原则3:渐进式演进
不要过度设计
从简单开始
根据需求演进
"优雅的退化" > "过早的优化"原则4:人本主义
技术服务于人
考虑团队能力和认知负担
最好的架构是团队能理解和维护的架构记住:架构设计不是一次性决策,而是一个持续演进的过程。保持灵活性,拥抱变化。
Last updated on