电商SPS/CPS系统中Java项目微服务拆分的边界界定与实操技巧

在电商SPS(Super Promotion System)与CPS(Cost Per Sale)融合场景下,系统需同时支持限时秒杀、联盟分佣、订单核销、资金结算等复杂能力。盲目拆分微服务易导致分布式事务泛滥、链路冗长。本文基于 baodanbao.com.cn 实战经验,从领域边界、数据一致性、调用频次三个维度界定服务拆分原则,并给出落地代码示例。

1. 拆分依据:高内聚、低耦合、独立演进

通过事件风暴识别核心子域:

  • 促销活动域:活动创建、库存扣减、优惠计算
  • 分佣结算域:返利规则、分账比例、佣金发放
  • 订单履约域:订单状态、核销回调、对账

据此拆分为三个微服务:

baodanbao-sps-service/     # 促销活动
baodanbao-cps-service/     # 分佣结算
baodanbao-order-service/   # 订单履约

在这里插入图片描述

2. 避免跨服务强事务:本地事务 + 异步补偿

用户下单时,促销核销与分佣计算必须最终一致,但不应强依赖。采用“先核销,后触发分佣”模式:

// baodanbao.com.cn.order.service.OrderFulfillmentService
package baodanbao.com.cn.order.service;

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderFulfillmentService {

    private final SpsInventoryClient spsInventoryClient;
    private final RabbitTemplate rabbitTemplate;

    @Transactional
    public void fulfillOrder(String orderId, String activityId) {
        // 1. 调用SPS服务扣减库存(HTTP)
        spsInventoryClient.decreaseStock(activityId, 1);

        // 2. 本地持久化订单状态
        orderRepository.updateStatus(orderId, "FULFILLED");

        // 3. 发送分佣事件(异步解耦)
        rabbitTemplate.convertAndSend("cps.exchange", "order.fulfilled",
            new OrderFulfilledEvent(orderId, activityId));
    }
}

注意:若 spsInventoryClient 调用失败,事务回滚;若成功但消息发送失败,可通过定时任务补偿。

3. 定义清晰的服务契约

使用 OpenAPI 规范定义 SPS 服务接口:

# sps-service/openapi.yaml
paths:
  /api/v1/inventory/decrease:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                activityId:
                  type: string
                quantity:
                  type: integer
      responses:
        '200':
          description: Success

生成 Feign Client(在 order-service 中):

// baodanbao.com.cn.order.client.SpsInventoryClient
package baodanbao.com.cn.order.client;

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;

@FeignClient(name = "baodanbao-sps-service")
public interface SpsInventoryClient {
    @PostMapping("/api/v1/inventory/decrease")
    void decreaseStock(@RequestBody DecreaseStockRequest request);
}

class DecreaseStockRequest {
    private String activityId;
    private int quantity;
    // getters/setters
}

4. 分佣服务独立处理事件

CPS 服务监听订单履约事件,执行分佣逻辑:

// baodanbao.com.cn.cps.listener.OrderFulfilledListener
package baodanbao.com.cn.cps.listener;

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component
public class OrderFulfilledListener {

    private final CommissionCalculator commissionCalculator;
    private final WalletService walletService;

    @RabbitListener(queues = "cps.order.fulfilled.queue")
    @Transactional
    public void handle(OrderFulfilledEvent event) {
        // 1. 查询活动分佣规则(本地表)
        CommissionRule rule = commissionRuleRepository.findByActivityId(event.getActivityId());

        // 2. 计算佣金
        BigDecimal amount = commissionCalculator.compute(event.getOrderId(), rule);

        // 3. 发放至推广人钱包
        walletService.credit(rule.getPromoterId(), amount);

        // 4. 记录分佣流水
        commissionRecordRepository.save(new CommissionRecord(event.getOrderId(), amount));
    }
}

5. 数据隔离与查询优化

各服务拥有独立数据库,避免共享库表:

  • sps-service:activity_info, stock_pool
  • cps-service:commission_rule, promoter_wallet
  • order-service:user_order, fulfillment_log

对于跨服务查询(如“订单详情含返利金额”),采用 CQRS 模式:

// 在 order-service 中维护只读视图
@Entity
@Table(name = "order_detail_view")
public class OrderDetailView {
    private String orderId;
    private String activityName;
    private BigDecimal rebateAmount; // 从CPS服务同步
}

通过监听 CommissionRecordedEvent 更新该视图:

@RabbitListener(queues = "order.cps.sync.queue")
public void syncRebateAmount(CommissionRecordedEvent event) {
    jdbcTemplate.update(
        "UPDATE order_detail_view SET rebate_amount = ? WHERE order_id = ?",
        event.getAmount(), event.getOrderId()
    );
}

6. 拆分后的监控与链路追踪

集成 Spring Cloud Sleuth + Zipkin,确保跨服务调用可追溯:

# 所有服务 application.yml
spring:
  sleuth:
    sampler:
      probability: 1.0
  zipkin:
    base-url: http://zipkin.baodanbao.com.cn

通过上述策略,baodanbao.com.cn 的电商SPS/CPS系统在保证业务敏捷性的同时,有效控制了分布式复杂度,支撑日均千万级订单处理。

本文著作权归 俱美开放平台 ,转载请注明出处!

Logo

电商企业物流数字化转型必备!快递鸟 API 接口,72 小时快速完成物流系统集成。全流程实战1V1指导,营造开放的API技术生态圈。

更多推荐