怎么做服务拆分?拆到什么粒度算合理?

1. 概述

1.1 服务拆分的重要性

服务拆分是微服务架构设计的核心问题,合理的服务拆分能够:

  • 提高系统可维护性:服务职责清晰,易于维护
  • 提高系统可扩展性:服务独立扩展,互不影响
  • 提高团队协作效率:团队独立开发,减少冲突
  • 提高系统可靠性:服务故障隔离,不影响整体

服务拆分的挑战

  • 拆分粒度:拆得太细增加复杂度,拆得太粗失去微服务优势
  • 服务边界:如何确定服务的边界
  • 数据一致性:拆分后如何保证数据一致性
  • 服务治理:拆分后如何治理服务

1.2 本文内容结构

本文将从以下几个方面全面解析服务拆分:

  1. 服务拆分原则:拆分的基本原则和指导思想
  2. 拆分方法:DDD、业务功能、数据模型等拆分方法
  3. 粒度判断:如何判断拆分粒度是否合理
  4. 拆分策略:渐进式拆分、一次性拆分等策略
  5. 拆分模式:常见拆分模式和实践
  6. 实战案例:实际项目中的服务拆分

2. 服务拆分原则

2.1 单一职责原则

2.1.1 原则定义

单一职责原则:每个服务只负责一个业务领域或功能模块。

判断标准

  • 服务是否有明确的业务边界
  • 服务是否只做一件事
  • 服务是否可以被独立理解

2.1.2 示例

错误示例

1
2
3
4
5
用户服务(UserService)
- 用户管理
- 订单管理
- 支付管理
- 库存管理

问题:职责过多,边界不清

正确示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
用户服务(UserService)
- 用户注册
- 用户登录
- 用户信息管理

订单服务(OrderService)
- 订单创建
- 订单查询
- 订单状态管理

支付服务(PaymentService)
- 支付处理
- 支付查询
- 支付回调

库存服务(InventoryService)
- 库存查询
- 库存扣减
- 库存回滚

2.2 高内聚低耦合

2.2.1 高内聚

高内聚:服务内部功能紧密相关,共同完成一个业务目标。

判断标准

  • 服务内部功能是否紧密相关
  • 服务内部数据是否高度相关
  • 服务内部变更是否经常一起发生

2.2.2 低耦合

低耦合:服务之间依赖关系简单,相互影响小。

判断标准

  • 服务之间调用是否频繁
  • 服务之间数据是否共享
  • 服务之间变更是否相互影响

2.2.3 示例

高内聚示例

1
2
3
4
5
订单服务(OrderService)
- 订单创建(高内聚:都围绕订单)
- 订单查询
- 订单状态管理
- 订单取消

低耦合示例

1
2
3
订单服务 -> 用户服务(只查询用户信息,不修改)
订单服务 -> 商品服务(只查询商品信息,不修改)
订单服务 -> 库存服务(调用扣减库存,异步通知)

2.3 业务边界清晰

2.3.1 业务边界

业务边界:服务应该按照业务领域划分,而不是技术层次。

判断标准

  • 服务是否对应一个业务领域
  • 服务是否可以被业务人员理解
  • 服务是否可以被独立运营

2.3.2 示例

错误示例(按技术层次拆分)

1
2
3
Controller服务
Service服务
DAO服务

正确示例(按业务领域拆分)

1
2
3
4
用户服务(用户领域)
订单服务(订单领域)
支付服务(支付领域)
商品服务(商品领域)

2.4 数据独立

2.4.1 数据独立性

数据独立:每个服务有自己独立的数据库,不直接访问其他服务的数据库。

判断标准

  • 服务是否有独立的数据库
  • 服务是否直接访问其他服务的数据库
  • 服务数据是否可以被独立管理

2.4.2 示例

错误示例

1
2
订单服务直接访问用户数据库
支付服务直接访问订单数据库

正确示例

1
2
3
4
5
订单服务 -> 订单数据库
用户服务 -> 用户数据库
支付服务 -> 支付数据库

服务间通过API调用,不直接访问数据库

3. 服务拆分方法

3.1 DDD领域驱动设计

3.1.1 DDD核心概念

DDD(Domain-Driven Design):通过领域模型驱动服务拆分。

核心概念

  • 领域(Domain):业务领域
  • 限界上下文(Bounded Context):领域边界
  • 聚合(Aggregate):数据一致性边界
  • 实体(Entity):有唯一标识的对象
  • 值对象(Value Object):没有唯一标识的对象

3.1.2 限界上下文识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 识别限界上下文
*
* 1. 用户上下文(User Context)
* - 用户注册、登录、信息管理
* - 用户认证、授权
*
* 2. 订单上下文(Order Context)
* - 订单创建、查询、状态管理
* - 订单取消、退款
*
* 3. 支付上下文(Payment Context)
* - 支付处理、查询
* - 支付回调、对账
*
* 4. 商品上下文(Product Context)
* - 商品信息管理
* - 商品分类、搜索
*
* 5. 库存上下文(Inventory Context)
* - 库存查询、扣减
* - 库存回滚、预警
*/

3.1.3 聚合识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 识别聚合
*
* 订单聚合(Order Aggregate)
* - 聚合根:Order
* - 实体:OrderItem
* - 值对象:Address, Money
* - 一致性边界:订单及其订单项
*
* 用户聚合(User Aggregate)
* - 聚合根:User
* - 实体:UserProfile
* - 值对象:Email, Phone
* - 一致性边界:用户及其个人信息
*/

3.1.4 服务拆分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 基于DDD的服务拆分
*
* 1. 用户服务(User Service)
* - 限界上下文:用户上下文
* - 聚合:用户聚合
* - 职责:用户管理、认证、授权
*
* 2. 订单服务(Order Service)
* - 限界上下文:订单上下文
* - 聚合:订单聚合
* - 职责:订单管理、状态流转
*
* 3. 支付服务(Payment Service)
* - 限界上下文:支付上下文
* - 聚合:支付聚合
* - 职责:支付处理、对账
*
* 4. 商品服务(Product Service)
* - 限界上下文:商品上下文
* - 聚合:商品聚合
* - 职责:商品管理、搜索
*
* 5. 库存服务(Inventory Service)
* - 限界上下文:库存上下文
* - 聚合:库存聚合
* - 职责:库存管理、预警
*/

3.2 业务功能拆分

3.2.1 功能识别

业务功能拆分:按照业务功能模块拆分服务。

步骤

  1. 识别核心业务功能
  2. 识别辅助业务功能
  3. 识别通用功能
  4. 按功能模块拆分服务

3.2.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/**
* 电商系统功能拆分
*
* 核心业务功能:
* 1. 用户服务(User Service)
* - 用户注册、登录
* - 用户信息管理
*
* 2. 商品服务(Product Service)
* - 商品信息管理
* - 商品搜索
*
* 3. 订单服务(Order Service)
* - 订单创建、查询
* - 订单状态管理
*
* 4. 支付服务(Payment Service)
* - 支付处理
* - 支付查询
*
* 5. 库存服务(Inventory Service)
* - 库存查询、扣减
* - 库存预警
*
* 辅助业务功能:
* 6. 物流服务(Logistics Service)
* - 物流信息查询
* - 物流跟踪
*
* 7. 评价服务(Review Service)
* - 商品评价
* - 评价查询
*
* 通用功能:
* 8. 通知服务(Notification Service)
* - 短信通知
* - 邮件通知
*
* 9. 配置服务(Config Service)
* - 系统配置
* - 参数管理
*/

3.3 数据模型拆分

3.3.1 数据模型分析

数据模型拆分:按照数据模型拆分服务。

步骤

  1. 分析数据模型
  2. 识别数据依赖关系
  3. 按数据模型拆分服务

3.3.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/**
* 数据模型拆分
*
* 用户数据模型:
* - users(用户表)
* - user_profiles(用户信息表)
* - user_addresses(用户地址表)
* -> 用户服务
*
* 订单数据模型:
* - orders(订单表)
* - order_items(订单项表)
* - order_logs(订单日志表)
* -> 订单服务
*
* 支付数据模型:
* - payments(支付表)
* - payment_records(支付记录表)
* - payment_refunds(退款表)
* -> 支付服务
*
* 商品数据模型:
* - products(商品表)
* - product_categories(商品分类表)
* - product_images(商品图片表)
* -> 商品服务
*
* 库存数据模型:
* - inventories(库存表)
* - inventory_logs(库存日志表)
* -> 库存服务
*/

3.4 团队结构拆分

3.4.1 康威定律

康威定律(Conway’s Law):系统架构反映组织架构。

含义

  • 团队结构影响系统架构
  • 系统架构应该匹配团队结构
  • 按团队拆分服务可以提高效率

3.4.2 示例

1
2
3
4
5
6
7
8
9
/**
* 按团队拆分服务
*
* 用户团队 -> 用户服务
* 订单团队 -> 订单服务
* 支付团队 -> 支付服务
* 商品团队 -> 商品服务
* 库存团队 -> 库存服务
*/

4. 粒度判断

4.1 粒度判断标准

4.1.1 服务大小

服务大小判断

  • 太小:服务过多,管理复杂,网络开销大
  • 太大:服务臃肿,职责不清,难以维护
  • 合适:职责清晰,易于管理,性能合理

4.1.2 判断指标

判断指标

  1. 代码量:单个服务代码量在5000-50000行
  2. 团队规模:单个服务由2-8人维护
  3. 数据库表数:单个服务数据库表数在5-20张
  4. 接口数量:单个服务接口数在10-50个
  5. 部署频率:单个服务可以独立部署

4.2 拆分过细的征兆

4.2.1 征兆

拆分过细的征兆

  • 服务间调用过于频繁
  • 服务间数据依赖复杂
  • 服务部署和运维成本高
  • 服务治理复杂
  • 团队协作困难

4.2.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 拆分过细的示例
*
* 用户服务
* 用户注册服务
* 用户登录服务
* 用户信息服务
* 用户地址服务
* 用户偏好服务
*
* 问题:
* - 服务过多,管理复杂
* - 服务间调用频繁
* - 部署和运维成本高
*/

4.3 拆分过粗的征兆

4.3.1 征兆

拆分过粗的征兆

  • 服务职责不清
  • 服务代码量大(>10万行)
  • 服务难以独立部署
  • 服务变更影响范围大
  • 团队协作冲突多

4.3.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 拆分过粗的示例
*
* 业务服务(包含所有业务逻辑)
* - 用户管理
* - 订单管理
* - 支付管理
* - 商品管理
* - 库存管理
*
* 问题:
* - 服务职责不清
* - 代码量大,难以维护
* - 难以独立部署和扩展
*/

4.4 合理粒度示例

4.4.1 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 合理粒度示例
*
* 1. 用户服务(User Service)
* - 代码量:约2万行
* - 团队:3人
* - 数据库表:8张
* - 接口数:20个
* - 职责:用户管理、认证、授权
*
* 2. 订单服务(Order Service)
* - 代码量:约3万行
* - 团队:4人
* - 数据库表:12张
* - 接口数:25个
* - 职责:订单管理、状态流转
*
* 3. 支付服务(Payment Service)
* - 代码量:约2.5万行
* - 团队:3人
* - 数据库表:10张
* - 接口数:18个
* - 职责:支付处理、对账
*/

5. 拆分策略

5.1 渐进式拆分

5.1.1 策略

渐进式拆分:逐步拆分,不一次性拆分。

步骤

  1. 识别核心服务,优先拆分
  2. 拆分一个服务,验证效果
  3. 逐步拆分其他服务
  4. 持续优化

5.1.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* 渐进式拆分示例
*
* 阶段1:拆分核心服务
* - 用户服务(独立)
* - 其他服务(单体)
*
* 阶段2:拆分订单服务
* - 用户服务(独立)
* - 订单服务(独立)
* - 其他服务(单体)
*
* 阶段3:拆分支付服务
* - 用户服务(独立)
* - 订单服务(独立)
* - 支付服务(独立)
* - 其他服务(单体)
*
* 阶段4:继续拆分其他服务
*/

5.2 一次性拆分

5.2.1 策略

一次性拆分:一次性拆分所有服务。

适用场景

  • 新系统设计
  • 系统重构
  • 有充足时间和资源

5.2.2 风险

风险

  • 风险高,影响范围大
  • 需要充足的时间
  • 需要完善的规划

5.3 按优先级拆分

5.3.1 策略

按优先级拆分:按业务优先级拆分服务。

优先级判断

  • 核心业务优先
  • 高频业务优先
  • 独立业务优先

5.3.2 示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 按优先级拆分
*
* 高优先级(核心业务):
* 1. 用户服务
* 2. 订单服务
* 3. 支付服务
*
* 中优先级(重要业务):
* 4. 商品服务
* 5. 库存服务
*
* 低优先级(辅助业务):
* 6. 物流服务
* 7. 评价服务
*/

6. 拆分模式

6.1 按业务领域拆分

6.1.1 模式

按业务领域拆分:按照业务领域拆分服务。

示例

1
2
3
4
5
用户领域 -> 用户服务
订单领域 -> 订单服务
支付领域 -> 支付服务
商品领域 -> 商品服务
库存领域 -> 库存服务

6.2 按数据模型拆分

6.2.1 模式

按数据模型拆分:按照数据模型拆分服务。

示例

1
2
3
用户数据 -> 用户服务
订单数据 -> 订单服务
支付数据 -> 支付服务

6.3 按功能模块拆分

6.3.1 模式

按功能模块拆分:按照功能模块拆分服务。

示例

1
2
3
用户管理 -> 用户服务
订单管理 -> 订单服务
支付管理 -> 支付服务

6.4 按读写拆分

6.4.1 模式

按读写拆分:将读操作和写操作拆分为不同服务。

示例

1
2
3
4
5
6
7
8
9
订单写服务(Order Write Service)
- 订单创建
- 订单更新
- 订单删除

订单读服务(Order Read Service)
- 订单查询
- 订单列表
- 订单统计

6.5 按CQRS拆分

6.5.1 模式

CQRS(Command Query Responsibility Segregation):命令查询职责分离。

示例

1
2
3
4
5
6
7
8
9
订单命令服务(Order Command Service)
- 创建订单(Command)
- 更新订单(Command)
- 取消订单(Command)

订单查询服务(Order Query Service)
- 查询订单(Query)
- 订单列表(Query)
- 订单统计(Query)

7. 拆分后的治理

7.1 服务注册与发现

7.1.1 服务注册

1
2
3
4
5
6
7
8
9
10
/**
* 服务注册(使用Nacos)
*/
@SpringBootApplication
@EnableDiscoveryClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}

7.1.2 服务发现

1
2
3
4
5
6
7
8
/**
* 服务发现(使用Feign)
*/
@FeignClient(name = "user-service")
public interface UserServiceClient {
@GetMapping("/api/users/{userId}")
User getUser(@PathVariable Long userId);
}

7.2 服务网关

7.2.1 API网关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* API网关配置(使用Spring Cloud Gateway)
*/
@Configuration
public class GatewayConfig {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("user-service", r -> r.path("/api/users/**")
.uri("lb://user-service"))
.route("order-service", r -> r.path("/api/orders/**")
.uri("lb://order-service"))
.route("payment-service", r -> r.path("/api/payments/**")
.uri("lb://payment-service"))
.build();
}
}

7.3 服务监控

7.3.1 监控指标

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* 服务监控(使用Prometheus)
*/
@Component
public class ServiceMetrics {
private final Counter orderCreatedCounter;
private final Timer orderProcessTimer;

public ServiceMetrics(MeterRegistry meterRegistry) {
this.orderCreatedCounter = Counter.builder("order.created")
.description("订单创建次数")
.register(meterRegistry);

this.orderProcessTimer = Timer.builder("order.process.time")
.description("订单处理时间")
.register(meterRegistry);
}
}

7.4 服务限流

7.4.1 限流配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 服务限流(使用Sentinel)
*/
@RestController
public class OrderController {

@GetMapping("/api/orders/{orderId}")
@SentinelResource(value = "getOrder", blockHandler = "handleBlock")
public Order getOrder(@PathVariable Long orderId) {
return orderService.getOrder(orderId);
}

public Order handleBlock(Long orderId, BlockException e) {
throw new BusinessException("服务限流,请稍后再试");
}
}

8. 实战案例

8.1 案例:电商系统服务拆分

8.1.1 拆分前

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 单体应用(Monolith)
*
* 电商系统(ECommerceSystem)
* - 用户管理
* - 商品管理
* - 订单管理
* - 支付管理
* - 库存管理
* - 物流管理
* - 评价管理
*
* 问题:
* - 代码量大(>50万行)
* - 团队协作困难
* - 部署和扩展困难
*/

8.1.2 拆分后

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
/**
* 微服务架构
*
* 1. 用户服务(User Service)
* - 用户注册、登录
* - 用户信息管理
* - 用户认证、授权
*
* 2. 商品服务(Product Service)
* - 商品信息管理
* - 商品搜索
* - 商品分类
*
* 3. 订单服务(Order Service)
* - 订单创建、查询
* - 订单状态管理
* - 订单取消、退款
*
* 4. 支付服务(Payment Service)
* - 支付处理
* - 支付查询
* - 支付回调、对账
*
* 5. 库存服务(Inventory Service)
* - 库存查询、扣减
* - 库存回滚
* - 库存预警
*
* 6. 物流服务(Logistics Service)
* - 物流信息查询
* - 物流跟踪
*
* 7. 评价服务(Review Service)
* - 商品评价
* - 评价查询
*
* 8. 通知服务(Notification Service)
* - 短信通知
* - 邮件通知
* - 推送通知
*/

8.1.3 服务依赖关系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 服务依赖关系
*
* 订单服务 -> 用户服务(查询用户信息)
* 订单服务 -> 商品服务(查询商品信息)
* 订单服务 -> 库存服务(扣减库存)
*
* 支付服务 -> 订单服务(查询订单信息)
* 支付服务 -> 用户服务(查询用户信息)
*
* 物流服务 -> 订单服务(查询订单信息)
*
* 评价服务 -> 订单服务(查询订单信息)
* 评价服务 -> 商品服务(查询商品信息)
* 评价服务 -> 用户服务(查询用户信息)
*/

8.2 案例:拆分粒度判断

8.2.1 用户服务拆分

1
2
3
4
5
6
7
8
9
10
11
/**
* 用户服务拆分判断
*
* 代码量:2万行 ✓(合理)
* 团队:3人 ✓(合理)
* 数据库表:8张 ✓(合理)
* 接口数:20个 ✓(合理)
* 职责:用户管理、认证、授权 ✓(清晰)
*
* 结论:拆分粒度合理
*/

8.2.2 订单服务拆分

1
2
3
4
5
6
7
8
9
10
11
/**
* 订单服务拆分判断
*
* 代码量:3万行 ✓(合理)
* 团队:4人 ✓(合理)
* 数据库表:12张 ✓(合理)
* 接口数:25个 ✓(合理)
* 职责:订单管理、状态流转 ✓(清晰)
*
* 结论:拆分粒度合理
*/

9. 总结

9.1 核心要点

  1. 服务拆分原则:单一职责、高内聚低耦合、业务边界清晰、数据独立
  2. 拆分方法:DDD、业务功能、数据模型、团队结构
  3. 粒度判断:代码量、团队规模、数据库表数、接口数量、部署频率
  4. 拆分策略:渐进式拆分、一次性拆分、按优先级拆分
  5. 拆分模式:按业务领域、数据模型、功能模块、读写、CQRS拆分

9.2 关键理解

  1. 服务拆分不是目的:拆分是为了提高系统的可维护性、可扩展性
  2. 粒度要合适:不能太细,也不能太粗
  3. 业务驱动:按业务领域拆分,而不是技术层次
  4. 渐进式拆分:逐步拆分,持续优化
  5. 拆分后治理:服务注册发现、网关、监控、限流

9.3 最佳实践

  1. 使用DDD:通过领域驱动设计识别服务边界
  2. 单一职责:每个服务只负责一个业务领域
  3. 数据独立:每个服务有独立的数据库
  4. 合理粒度:代码量5000-50000行,团队2-8人
  5. 渐进式拆分:逐步拆分,持续优化

相关文章