软件架构演进¶
核心问题:软件架构经历了哪些演进阶段?每种架构解决了什么问题、引入了什么新问题?如何根据业务阶段选择合适的架构?
它解决了什么问题?¶
架构不是一成不变的,而是随着业务规模、团队规模、技术能力的变化而演进的。理解架构演进的脉络,能帮助你:
- 在正确的时间点做出正确的架构决策(不过度设计,也不欠设计)
- 理解每种架构的适用场景和局限性
- 避免"为了微服务而微服务"的常见陷阱
一、架构演进全景¶
flowchart LR
subgraph 架构演进路径
A["单体架构<br>Monolith<br>👥 1-5人"] -->|"业务模块增多<br>代码耦合严重"| B["垂直拆分<br>按业务线拆分<br>👥 5-15人"]
B -->|"公共能力重复建设<br>需要服务复用"| C["SOA<br>面向服务架构<br>👥 15-50人"]
C -->|"ESB 成为瓶颈<br>需要更轻量的通信"| D["微服务架构<br>Microservices<br>👥 50+人"]
D -->|"运维复杂度高<br>追求极致弹性"| E["云原生/Serverless<br>FaaS<br>👥 按需"]
end 二、各阶段架构详解¶
2.1 单体架构(Monolith)¶
所有功能模块打包在一个应用中,共享一个数据库,一次部署。
┌─────────────────────────────────┐
│ 单体应用 │
│ ┌─────┐ ┌─────┐ ┌─────┐ │
│ │用户 │ │订单 │ │商品 │ │
│ │模块 │ │模块 │ │模块 │ │
│ └──┬──┘ └──┬──┘ └──┬──┘ │
│ └───────┼───────┘ │
│ ┌──┴──┐ │
│ │ DB │ │
│ └─────┘ │
└─────────────────────────────────┘
| 优势 | 劣势 |
|---|---|
| 开发简单,IDE 直接调试 | 代码耦合,改一处影响全局 |
| 部署简单,一个 JAR/WAR | 启动慢,编译慢(代码量大时) |
| 事务简单,本地事务即可 | 无法按模块独立扩展 |
| 适合快速验证业务 | 技术栈绑定,无法混合使用 |
适用场景:初创项目、MVP 验证、团队 1-5 人、业务逻辑简单。
2.2 垂直拆分架构¶
按业务线将单体拆分为多个独立应用,每个应用有自己的数据库。
┌──────────┐ ┌──────────┐ ┌──────────┐
│ 用户系统 │ │ 订单系统 │ │ 商品系统 │
│ │ │ │ │ │
│ ┌────┐ │ │ ┌────┐ │ │ ┌────┐ │
│ │ DB │ │ │ │ DB │ │ │ │ DB │ │
│ └────┘ │ │ └────┘ │ │ └────┘ │
└──────────┘ └──────────┘ └──────────┘
| 优势 | 劣势 |
|---|---|
| 各业务线独立开发部署 | 公共功能重复建设(如用户认证) |
| 故障隔离,一个系统挂了不影响其他 | 系统间调用方式不统一 |
| 可以按业务线独立扩展 | 数据冗余,跨系统查询困难 |
适用场景:业务线明确分离、团队 5-15 人、各业务线相对独立。
2.3 SOA(面向服务架构)¶
将公共能力抽取为独立服务,通过 ESB(企业服务总线)统一通信。
flowchart TB
App1["应用A"] --> ESB["ESB 企业服务总线<br>协议转换/路由/编排"]
App2["应用B"] --> ESB
ESB --> S1["用户服务"]
ESB --> S2["支付服务"]
ESB --> S3["消息服务"] | 优势 | 劣势 |
|---|---|
| 服务复用,避免重复建设 | ESB 是单点瓶颈和故障点 |
| 统一的服务治理 | ESB 配置复杂,学习成本高 |
| 支持异构系统集成 | 服务粒度粗,仍然偏重量级 |
适用场景:大型企业内部系统集成、异构系统互通。
2.4 微服务架构(Microservices)¶
每个服务围绕一个业务能力构建,独立开发、部署、扩展,服务间通过轻量级协议(HTTP/gRPC)通信。
flowchart TB
Client["客户端"] --> GW["API Gateway<br>统一入口/鉴权/限流"]
GW --> S1["用户服务"]
GW --> S2["订单服务"]
GW --> S3["商品服务"]
S1 --> SD["Service Discovery<br>Nacos/Eureka"]
S2 --> SD
S3 --> SD
S2 --> CB["Circuit Breaker<br>Sentinel/Hystrix<br>熔断降级"]
S2 --> MQ["Message Queue<br>Kafka/RocketMQ<br>异步解耦"]
subgraph 可观测性
LT["链路追踪<br>SkyWalking/Zipkin"]
LOG["日志聚合<br>ELK Stack"]
MT["指标监控<br>Prometheus+Grafana"]
end | 优势 | 劣势 |
|---|---|
| 独立部署,快速迭代 | 分布式事务复杂 |
| 按需扩展,资源利用率高 | 服务间通信有网络开销 |
| 技术栈自由,各服务可选不同语言 | 需要完善的基础设施(注册发现、链路追踪等) |
| 故障隔离,熔断降级 | 运维复杂度高,需要 DevOps 能力 |
适用场景:大型系统、多团队协作(50+ 人)、需要独立扩展和快速迭代。
与 Spring 微服务文档的分工:本文聚焦架构理论和选型决策,具体的 Spring Cloud 组件原理和落地实践请参考 Spring Cloud 核心组件 和 微服务架构深度实践。
2.5 云原生与 Serverless¶
flowchart LR
subgraph 云原生技术栈
Container["容器化<br>Docker"] --> Orchestration["编排调度<br>Kubernetes"]
Orchestration --> Mesh["服务网格<br>Istio/Linkerd"]
Mesh --> Serverless["Serverless<br>AWS Lambda / 阿里云函数计算"]
end | 特性 | 说明 |
|---|---|
| 容器化 | 应用打包为容器镜像,环境一致性,秒级启动 |
| Kubernetes | 自动化部署、扩缩容、自愈,声明式管理 |
| 服务网格 | 将服务治理(熔断、限流、重试)下沉到基础设施层,业务代码无感知 |
| Serverless | 按调用次数计费,无需管理服务器,极致弹性 |
三、架构选型决策框架¶
选型决策树¶
flowchart TD
Start["项目启动"] --> Q1{"团队规模?"}
Q1 -->|"< 5人"| Mono["单体架构<br>快速验证"]
Q1 -->|"5-15人"| Q2{"业务线是否独立?"}
Q2 -->|"是"| Vertical["垂直拆分"]
Q2 -->|"否"| Mono
Q1 -->|"> 15人"| Q3{"是否有 DevOps 能力?"}
Q3 -->|"是"| Micro["微服务架构"]
Q3 -->|"否"| Q4["先建设基础设施<br>再逐步拆分"] 关键决策因素¶
| 决策因素 | 倾向单体 | 倾向微服务 |
|---|---|---|
| 团队规模 | < 10 人 | > 10 人,多团队 |
| 业务复杂度 | CRUD 为主 | 复杂业务逻辑,多业务域 |
| 发布频率 | 每周/每月 | 每天多次 |
| 扩展需求 | 各模块负载均匀 | 各模块负载差异大 |
| 技术栈 | 统一技术栈 | 需要混合技术栈 |
| 基础设施 | 无 K8s/DevOps | 有完善的 CI/CD 和监控 |
核心原则:先单体,再拆分。不要一开始就用微服务,微服务需要服务注册发现、分布式追踪、分布式事务等基础设施,运维复杂度极高。初创项目业务不稳定,过早拆分会导致频繁的跨服务重构。
四、分层架构模式¶
无论选择哪种部署架构,应用内部的分层设计都很重要。
传统三层架构¶
问题:业务逻辑全部堆在 Service 层,Entity 只有 getter/setter(贫血模型),Service 越来越臃肿。
六边形架构(端口与适配器)¶
flowchart LR
subgraph 外部
HTTP["HTTP 请求"]
MQ["消息队列"]
DB["数据库"]
Cache["缓存"]
end
subgraph 适配器层
HA["HTTP Adapter<br>Controller"]
MA["MQ Adapter<br>Consumer"]
DA["DB Adapter<br>Repository 实现"]
CA["Cache Adapter"]
end
subgraph 核心域
Port["端口(接口)"]
Domain["领域模型<br>业务逻辑"]
end
HTTP --> HA --> Port
MQ --> MA --> Port
Port --> Domain
Domain --> Port
Port --> DA --> DB
Port --> CA --> Cache 核心思想:业务逻辑在中心,通过端口(接口)与外部交互,适配器负责技术细节。更换数据库、消息队列等只需替换适配器,不影响核心业务。
整洁架构(Clean Architecture)¶
依赖规则:依赖方向只能从外向内,内层不知道外层的存在。
| 层次 | 职责 | 示例 |
|---|---|---|
| 实体层 | 核心业务规则,与框架无关 | Order、User 领域对象 |
| 用例层 | 应用业务规则,编排领域对象 | CreateOrderUseCase |
| 接口适配器 | 转换数据格式 | Controller、Repository |
| 框架层 | 技术细节 | Spring、MyBatis、Redis |
五、架构反模式¶
| 反模式 | 描述 | 后果 | 正确做法 |
|---|---|---|---|
| 分布式单体 | 拆成了微服务,但服务间强耦合,必须一起部署 | 兼具单体和微服务的缺点 | 按业务域拆分,保持高内聚低耦合 |
| 过早优化 | 业务还没验证就搭建复杂架构 | 浪费时间,增加维护成本 | 先用最简单的方案,遇到瓶颈再优化 |
| 简历驱动开发 | 为了用新技术而引入不必要的复杂度 | 团队学习成本高,稳定性差 | 技术选型以解决问题为导向 |
| 大泥球 | 没有清晰的模块边界,代码随意调用 | 牵一发动全身,无法维护 | 明确模块边界,通过接口通信 |
| 拆分过细 | 每个接口都是一个服务 | 网络开销大,分布式事务多 | 按业务域拆分,一个域一个服务 |
六、常见问题¶
Q:微服务和单体架构如何选择?
初创项目优先单体,快速验证业务。当团队超过 10 人、模块间耦合严重、需要独立扩展时,再考虑微服务拆分。不要为了微服务而微服务,微服务的运维复杂度远高于单体。
Q:服务拆分的常见错误是什么?
① 拆分过细,每个接口都跨服务调用,导致网络开销和分布式事务问题;② 拆分后服务间仍然强耦合,必须一起部署(分布式单体);③ 没有建设好基础设施(注册发现、链路追踪、CI/CD)就急于拆分。应按业务域拆分,保持高内聚低耦合。
Q:SOA 和微服务的区别是什么?
SOA 通过重量级的 ESB 集中管理服务通信,服务粒度较粗;微服务去掉了 ESB,服务间直接通过轻量级协议(HTTP/gRPC)通信,服务粒度更细,每个服务独立部署。微服务可以看作是 SOA 的轻量化演进。
Q:什么是六边形架构?它和传统三层架构有什么区别?
六边形架构将业务逻辑放在中心,通过端口(接口)与外部交互,适配器负责技术细节。与三层架构的区别在于:三层架构的依赖方向是从上到下(Controller → Service → DAO),业务层依赖数据层;六边形架构通过依赖倒置,核心域不依赖任何外部技术,更容易测试和替换技术组件。
Q:如何判断是否需要从单体迁移到微服务?
出现以下信号时考虑迁移:① 团队超过 10 人,代码合并冲突频繁;② 某个模块需要独立扩展(如秒杀模块需要 10 倍资源,其他模块不需要);③ 发布频率受限,一个模块的变更需要等待整体发布;④ 技术栈需要多样化(如 AI 模块用 Python,其他用 Java)。