软件架构特点及风格
1.软件架构解决的根本问题
软件架构 = 复杂性管理
核心矛盾:
| 矛盾 | 表现 |
|---|---|
| 复杂性 vs 可管理性 | 系统规模增长导致难以理解 |
| 可伸缩性 vs 性能 | 扩展能力与响应速度权衡 |
| 灵活性 vs 稳定性 | 变更能力与系统可靠性的平衡 |
| 可重用性 vs 特定需求 | 通用方案与定制功能的冲突 |
2.架构风格分类总览
按通信模式划分
| 分类 | 代表风格 | 核心思想 |
|---|---|---|
| 数据流 | 管道-过滤器、批处理 | 数据在组件间流动并被转换 |
| 调用 | 客户-服务器、RPC、REST | 一方请求,另一方响应 |
| 事件 | EBI、C2、消息队列 | 发布-订阅,异步通信 |
| 虚拟化 | 虚拟机、容器 | 隔离执行环境 |
| 移动代码 | REV、COD、移动代理 | 代码作为数据元素移动 |
| 复制 | 复制仓库、缓存 | 数据多副本提高可用性 |
3.主要架构风格详解
3.1 管道-过滤器(Pipe and Filter)
解决的问题:
- 数据处理流水线
- 组件独立开发、测试、替换
- 增量处理支持并行
示例:
1 | # Unix管道是经典案例 |
| 优点 | 缺点 |
|---|---|
| 组件高度可重用 | 不适合交互式处理 |
| 增量处理 | 性能随管道长度递减 |
| 易于维护 | 数据格式耦合 |
3.2 客户-服务器架构(Client-Server)
解决的问题:
- 集中式资源管理
- 安全边界控制
- 负载均衡
变体演进:
| 变体 | 约束 | 解决的问题 |
|---|---|---|
| CS | 分离关注点 | UI与逻辑分离 |
| CSS | +无状态 | 可伸缩性、故障恢复 |
| C$SS | +缓存 | 减少网络交互 |
| LCS | +分层 | 安全、中间件注入 |
| RS | 会话在服务器 | 简化客户端 |
无状态为什么重要:
- 服务器无需保存会话 → 可随意增减实例
- 故障恢复简单 → 重启即可继续
- 负载均衡容易 → 请求可路由到任意服务器
3.3 事件驱动架构(Event-Based)
解决的问题:
- 松耦合组件通信
- 异步处理
- 实时事件响应
架构示意:
Publisher A ──┐
├──→ Event Bus ──→ Subscriber B
Publisher C ──┘ ──→ Subscriber D
特点:
| 特性 | 说明 |
|---|---|
| 可扩展性 | 新增监听者不影响发布者 |
| 可进化性 | 组件替换不影响其他组件 |
| 缺点 | 难以调试、事件风暴风险 |
典型技术: RabbitMQ、Kafka、Node.js事件循环
3.4 移动代码架构
解决的问题:
- 动态功能扩展
- 平台无关性
- 减少网络往返
| 风格 | 移动什么 | 执行位置 | 应用场景 |
|---|---|---|---|
| VM | 字节码 | 本地虚拟机 | Java Applet、WebAssembly |
| REV | 代码 → 远程执行 | 服务器 | Webhooks、Serverless |
| COD | 代码 → 本地执行 | 客户端 | JavaScript、动态模块 |
| MA | 组件+状态+数据 | 远程站点 | 智能爬虫、网络代理 |
3.5 复制与缓存架构
解决的问题:
- 单点故障容错
- 就近访问降低延迟
- 支持离线操作
复制仓库(RR): 缓存(Cache):
Client → Replica A ──┐ Client → [Cache] → Server
Replica B ──┤ ↖_________↓
|────────── Hit:快速返回
Miss:获取并缓存
缓存策略对比:
| 策略 | 一致性 | 性能 | 适用场景 |
|---|---|---|---|
| 写直达 | 强 | 低 | 金融系统 |
| 写回 | 最终 | 高 | Web应用 |
| TTL | 时间窗 | 中 | 临时数据 |
3.6 分层架构
解决的问题:
- 复杂性隔离
- 关注点分离
- 中间件能力注入
典型层次:
应用层 → HTTP、FTP、SMTP
传输层 → TCP、UDP
网络层 → IP
网络接口 → Ethernet、WiFi
代价: 每增加一层,增加延迟和处理开销
4.现代架构模式
4.1 微服务架构
解决的问题:
- 单体应用复杂性
- 团队规模扩展
- 技术栈异构
- 独立部署和扩展
┌──────────┐ ┌──────────┐ ┌──────────┐
│ Service │ │ Service │ │ Service │
│ A │ │ B │ │ C │
└────┬─────┘ └────┬─────┘ └────┬─────┘
└─────────────┼─────────────┘
↓
┌─────────────┐
API网关
└─────────────┘
与REST的关系: 微服务通常遵循REST约束(无状态、统一接口、资源导向)
4.2 服务网格(Service Mesh)
解决的问题:
- 服务间通信的横切关注点
- 流量管理、熔断、限流
- 可观测性(监控、日志、追踪)
- 安全(mTLS)
机制: Sidecar代理模式,业务代码无需感知网络细节
4.3 事件溯源(Event Sourcing)
解决的问题:
- 审计追踪
- 时间旅行调试
- 系统重组能力
Command → [Event Store] → Projections
↓
不可变事件日志
4.4 CQRS(命令查询职责分离)
解决的问题:
- 读写性能优化
- 模型复杂度分离
- 独立扩展
5.架构选择决策矩阵
根据问题域选择
| 问题特征 | 推荐架构 | 原因 |
|---|---|---|
| 数据处理流水线 | 管道-过滤器 | 模块化、可重用 |
| 集中式资源管理 | 客户-服务器 | 安全、控制 |
| 实时事件响应 | 事件驱动 | 松耦合、异步 |
| 跨组织协作 | REST/HTTP | 标准化、防火墙穿透 |
| 互联网规模 | REST + CDN + 缓存 | 可伸缩 |
| 分布式一致性 | 复制仓库+共识算法 | 容错、可用 |
| 动态功能扩展 | 移动代码 | 灵活性 |
架构演进路径
单体架构
↓ 规模增长、团队扩展
模块化单体
↓ 部署频率、技术栈差异
微服务
↓ 网络延迟、一致性要求
服务网格 + 边车模式
↓ 基础设施复杂性
Serverless + 事件驱动
6.核心洞见
架构风格是一组协作的约束,通过施加这些约束来获得期望的架构属性。
- 没有”最佳”架构,只有”最适合问题域”的架构
- 架构决策应基于需求(功能+非功能),而非时尚
- Internet规模的系统需要特殊考虑:无法控制的可伸缩性、独立部署、多信任边界