从单体到微服务:淘客返利系统的演进路径与拆分边界划分原则
大家好,我是 微赚淘客系统3.0 的研发者省赚客!
微赚淘客系统1.0最初采用Spring Boot单体架构,所有功能(用户、订单、返利、通知、对账)耦合在同一个应用中。随着业务量激增,系统面临发布效率低、故障隔离差、数据库锁竞争严重等问题。我们基于领域驱动设计(DDD)思想,逐步演进为微服务架构,并确立了清晰的拆分边界与通信规范。
一、识别核心子域与限界上下文
通过事件风暴(Event Storming)梳理业务流程,我们将系统划分为以下限界上下文(Bounded Context):
- 用户中心(User Context):注册、登录、邀请关系
- 商品中心(Item Context):商品同步、类目管理
- 订单中心(Order Context):订单抓取、状态跟踪
- 返利中心(Rebate Context):规则匹配、金额计算、发放
- 通知中心(Notify Context):微信模板、短信推送
- 对账中心(Settlement Context):日结、月结、财务报表
每个上下文对应一个独立微服务,拥有专属数据库,禁止跨库JOIN。
二、数据库垂直拆分与数据一致性保障
原单体MySQL库被拆分为6个独立实例。以"返利发放"为例,需保证订单状态更新与返利记录写入的一致性。我们采用本地消息表 + 最终一致性方案:
java
// 返利服务:写本地消息表
@Transactional
public void processOrderConfirmed(String orderId) {
RebateRecord record = calculateRebate(orderId);
rebateMapper.insert(record);
// 写入本地消息表
juwatech.cn.rebate.dao.MessageLogMapper.insert(
new MessageLog("notify_user", JSON.toJSONString(record), "PENDING")
);
}
// 后台任务:投递消息到MQ
@Scheduled(fixedDelay = 1000)
public void deliverMessages() {
List<MessageLog> logs = messageLogMapper.selectPending(100);
for (MessageLog log : logs) {
try {
juwatech.cn.mq.RabbitProducer.send("rebate.notify", log.getContent());
messageLogMapper.markAsSent(log.getId());
} catch (Exception e) {
// 重试或告警
}
}
}
通知服务消费消息后,执行用户触达,实现跨服务最终一致。
三、API网关与服务通信
前端请求统一由Spring Cloud Gateway路由:
yaml
# gateway.yml
spring:
cloud:
gateway:
routes:
- id: rebate-service
uri: lb://rebate-service
predicates:
- Path=/api/v1/rebates/**
filters:
- StripPrefix=1
内部服务间调用采用Feign + Resilience4j熔断:
java
@FeignClient(name = "order-service", fallback = OrderClientFallback.class)
public interface OrderClient {
@GetMapping("/internal/orders/{orderId}")
OrderDTO getOrder(@PathVariable String orderId);
}
@Component
public class OrderClientFallback implements OrderClient {
public OrderDTO getOrder(String orderId) {
throw new ServiceUnavailableException("Order service unavailable");
}
}
关键链路(如返利计算)强制走gRPC以提升性能:
java
// 在 juwatech.cn.grpc 包下定义 proto
service RebateService {
rpc CalculateRebate (CalculateRequest) returns (CalculateResponse);
}
四、拆分边界划分原则
我们在实践中总结出以下拆分准则:
- 高内聚低耦合:同一业务实体的操作应归属同一服务(如返利规则与计算逻辑不得分离)
- 数据自治:每个服务独占数据库,通过API或事件共享数据
- 团队对齐:一个微服务由一个2~5人小团队全生命周期负责
- 变更频率一致:高频迭代模块(如返利策略)独立部署,避免牵连稳定模块(如用户体系)
例如,早期将"邀请返利"与"购物返利"混在同一模块,导致策略调整需全量回归。拆分后,juwatech.cn.rebate.invite 与 juwatetech.cn.rebate.shopping 各自独立演进。
五、遗留单体渐进式解耦
对于无法立即拆分的复杂模块(如老版对账),我们采用绞杀者模式(Strangler Fig Pattern):
- 新功能在微服务中实现
- 通过反向代理将新流量导向新服务
- 逐步迁移旧数据并下线单体接口
java
// 单体中的适配层(临时)
@RestController
public class LegacyRebateController {
@Autowired
private juwatech.cn.rebate.newservice.RebateFacade newRebateFacade;
@GetMapping("/old/rebate/calc")
public ResponseEntity<?> calc(@RequestParam String orderId) {
// 路由到新服务
return newRebateFacade.calculate(orderId);
}
}
同时,使用Apache ShardingSphere实现读写分离与分库分表,缓解单库压力。
六、可观测性与链路追踪
微服务拆分后,问题定位难度上升。我们集成SkyWalking实现全链路追踪:
java
// 在各服务 bootstrap.yml 中配置
agent:
service_name: ${spring.application.name}
collector:
backend_service: skywalking-oap:11800
关键方法添加自定义Span:
java
@Trace
public void handleRebateTask(RebateTask task) {
ActiveSpan.tag("order.id", task.getOrderId());
// 业务逻辑
}
配合Prometheus+Grafana监控各服务QPS、错误率、延迟,确保拆分后稳定性不降反升。
本文著作权归 微赚淘客系统3.0 研发团队,转载请注明出处!