从单体到微服务:淘客返利系统的演进路径与拆分边界划分原则

从单体到微服务:淘客返利系统的演进路径与拆分边界划分原则

大家好,我是 微赚淘客系统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);
}

四、拆分边界划分原则

我们在实践中总结出以下拆分准则:

  1. 高内聚低耦合:同一业务实体的操作应归属同一服务(如返利规则与计算逻辑不得分离)
  2. 数据自治:每个服务独占数据库,通过API或事件共享数据
  3. 团队对齐:一个微服务由一个2~5人小团队全生命周期负责
  4. 变更频率一致:高频迭代模块(如返利策略)独立部署,避免牵连稳定模块(如用户体系)

例如,早期将"邀请返利"与"购物返利"混在同一模块,导致策略调整需全量回归。拆分后,juwatech.cn.rebate.invitejuwatetech.cn.rebate.shopping 各自独立演进。

五、遗留单体渐进式解耦

对于无法立即拆分的复杂模块(如老版对账),我们采用绞杀者模式(Strangler Fig Pattern)

  1. 新功能在微服务中实现
  2. 通过反向代理将新流量导向新服务
  3. 逐步迁移旧数据并下线单体接口
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 研发团队,转载请注明出处!

相关推荐
行乾1 天前
鸿蒙端 IMSDK 架构探索
架构·harmonyos
石小石Orz1 天前
油猴脚本实现生产环境加载本地qiankun子应用
前端·架构
AI攻城狮1 天前
用 Obsidian CLI + LLM 构建本地 RAG:让你的笔记真正「活」起来
人工智能·云原生·aigc
若风的雨1 天前
【deepseek】RISC-V 的CSR寄存器详解
架构
科技小花1 天前
AI重塑数据治理:2026年核心方案评估与场景适配
大数据·人工智能·云原生·ai原生
阿里云云原生1 天前
基于 HiClaw 的运维场景多智能体协同实践
云原生
ZHENGZJM1 天前
架构总览:Monorepo 结构与容器化部署
架构·go·react·全栈开发
搜佛说1 天前
比SQLite更快,比InfluxDB更轻:sfsDb的降维打击
jvm·数据库·物联网·架构·sqlite·边缘计算·iot
提子拌饭1331 天前
昼夜节律下的肝脏代谢清除率演算仪:基于鸿蒙Flutter的双路流场与酶解粒子对照架构
flutter·华为·架构·harmonyos·鸿蒙
SuperEugene1 天前
前端通用基础组件设计:按钮/输入框/弹窗,统一设计标准|组件化设计基础篇
前端·javascript·vue.js·架构