单体架构与微服务架构如何选择?

面试场景

面试官:”你们项目用的是微服务还是单体?为什么这么选?”

这道题考察架构选型能力技术判断力。不是微服务就一定好,关键是适合


两种架构对比

单体架构

┌─────────────────────────────────────┐
│            单体应用                  │
├─────────────────────────────────────┤
│  用户模块 │ 订单模块 │ 商品模块 │ ...│
├─────────────────────────────────────┤
│              公共代码               │
├─────────────────────────────────────┤
│            单一数据库               │
└─────────────────────────────────────┘

微服务架构

┌──────────┐  ┌──────────┐  ┌──────────┐
│ 用户服务  │  │ 订单服务  │  │ 商品服务  │
└────┬─────┘  └────┬─────┘  └────┬─────┘
     │             │             │
     └──────┬──────┴──────┬──────┘
            │             │
     ┌──────┴─────┐ ┌─────┴──────┐
     │   网关      │ │ 注册中心   │
     └────────────┘ └────────────┘

维度对比

维度 单体 微服务
开发复杂度
部署复杂度
技术栈 单一 多样
团队协作 代码冲突多 独立开发
扩展性 整体扩容 按服务扩容
容错性 单点故障 隔离性好
性能 进程内调用 网络调用开销
运维成本

单体架构的优势

1. 简单直接

// 直接方法调用,无需RPC
@Service
public class OrderService {
    @Autowired
    private UserService userService;
    
    public Order createOrder(OrderRequest request) {
        User user = userService.getUser(request.getUserId());  // 本地调用
        // ...
    }
}

2. 开发效率高

  • 无需考虑分布式问题
  • 调试方便
  • 事务简单

3. 部署简单

# 一个jar搞定
java -jar app.jar

4. 性能好

  • 无网络开销
  • 无序列化开销
  • 无服务发现延迟

微服务的优势

1. 独立部署

订单服务升级 → 只部署订单服务
用户服务不受影响

2. 技术栈灵活

用户服务:Java + MySQL
推荐服务:Python + Redis
搜索服务:Go + Elasticsearch

3. 团队独立

团队A → 负责用户服务 → 独立迭代
团队B → 负责订单服务 → 独立迭代

4. 按需扩容

大促期间:
- 订单服务:10实例 → 50实例
- 用户服务:保持10实例

选型决策树

团队规模?
  │
  ├── < 10人 → 单体
  │
  └── >= 10人 → 业务复杂度?
                    │
                    ├── 简单 → 单体
                    │
                    └── 复杂 → 扩展性要求?
                                │
                                ├── 低 → 单体
                                │
                                └── 高 → 微服务

适合单体的场景

  • 创业公司/小团队(< 10人)
  • MVP/快速验证阶段
  • 业务逻辑简单
  • 预算有限

适合微服务的场景

  • 大型团队(> 50人)
  • 业务复杂,模块边界清晰
  • 需要独立扩缩容
  • 多语言技术栈需求

演进路径

不要一开始就微服务

错误路径:
  启动项目 → 直接微服务 → 踩坑无数 → 项目失败

正确路径:
  启动项目 → 单体 → 业务增长 → 逐步拆分 → 微服务

渐进式拆分

阶段1:单体
┌─────────────────────┐
│  所有业务 in 一个服务 │
└─────────────────────┘

阶段2:模块化单体
┌─────────────────────┐
│  用户模块 │ 订单模块  │  ← 代码层面模块化
└─────────────────────┘

阶段3:部分微服务
┌────────┐  ┌─────────┐
│单体应用 │  │订单服务  │  ← 核心服务先拆
└────────┘  └─────────┘

阶段4:全面微服务
┌────┐ ┌────┐ ┌────┐
│用户│ │订单│ │商品│
└────┘ └────┘ └────┘

微服务的代价

1. 分布式事务

// 单体:简单的@Transactional
@Transactional
public void create() {
    orderMapper.insert(order);
    stockMapper.deduct(stock);
}

// 微服务:需要Seata/TCC
@GlobalTransactional
public void create() {
    orderService.create(order);
    stockService.deduct(stock);  // RPC调用
}

2. 运维复杂度

需要:

  • 服务注册发现(Nacos/Consul)
  • 配置中心
  • 链路追踪(Skywalking)
  • 日志聚合(ELK)
  • 容器编排(K8s)

3. 网络开销

单体:0ms(进程内调用)
微服务:1-5ms/次RPC(调用链越长越慢)

面试答题框架

选型原则:适合 > 先进

考虑因素:
1. 团队规模:小团队选单体
2. 业务复杂度:简单业务选单体
3. 扩展需求:按需扩容选微服务
4. 运维能力:能力不足选单体

演进策略:
- 先单体,再拆分
- 核心服务先拆
- 渐进式演进

微服务代价:
- 分布式事务
- 运维复杂度
- 网络开销

总结

场景 推荐架构
创业公司 单体
小团队(<10人) 单体
MVP阶段 单体
大型团队(50+) 微服务
独立扩缩容需求 微服务
多语言技术栈 微服务

核心原则:不要为了微服务而微服务,架构是为业务服务的。