导购app佣金模式微服务拆分:领域驱动设计在返利系统中的实践

导购app佣金模式微服务拆分:领域驱动设计在返利系统中的实践

大家好,我是省赚客APP研发者阿宝!"省赚客"作为聚娃科技旗下的导购返利平台,其核心业务围绕用户推广、订单跟踪与佣金结算展开。早期单体架构下,佣金计算逻辑与订单、商品、用户模块高度耦合,导致迭代缓慢、测试困难。为提升系统可维护性与扩展性,我们采用领域驱动设计(DDD)方法论,对返利系统进行微服务拆分,明确限界上下文(Bounded Context),并以聚合根保障业务一致性。

识别核心子域与限界上下文

通过事件风暴工作坊,我们识别出三个核心子域:

  • 推广域(Promotion):管理用户生成的推广链接、任务配置
  • 订单域(Order):处理电商平台回传的订单数据
  • 佣金域(Commission):负责佣金计算、状态机与结算

每个子域对应一个独立微服务,拥有专属数据库与API契约。

佣金聚合根设计

佣金域的核心是Commission聚合根,它封装了佣金生命周期的所有规则:

java 复制代码
package juwatech.cn.commission.domain;

import java.math.BigDecimal;
import java.time.LocalDateTime;

public class Commission {
    private String id;
    private String userId;
    private String orderId;
    private BigDecimal amount;
    private CommissionStatus status;
    private LocalDateTime confirmedAt;
    private LocalDateTime settledAt;

    public void confirm(BigDecimal actualAmount) {
        if (this.status != CommissionStatus.PENDING) {
            throw new IllegalStateException("Only PENDING commission can be confirmed");
        }
        this.amount = actualAmount;
        this.status = CommissionStatus.CONFIRMED;
        this.confirmedAt = LocalDateTime.now();
    }

    public void settle() {
        if (this.status != CommissionStatus.CONFIRMED) {
            throw new IllegalStateException("Only CONFIRMED commission can be settled");
        }
        this.status = CommissionStatus.SETTLED;
        this.settledAt = LocalDateTime.now();
    }

    // getters omitted
}

该聚合根确保状态变更符合业务规则,防止非法跃迁。

领域事件驱动跨服务协作

当订单域确认一笔有效订单后,发布OrderConfirmedEvent,佣金服务监听并创建佣金记录:

java 复制代码
// 订单服务发布事件
package juwatech.cn.order.event;

public class OrderConfirmedEvent {
    private String orderId;
    private String userId;
    private String itemId;
    private BigDecimal orderAmount;
    private LocalDateTime confirmedTime;
    // constructor, getters
}

// 佣金服务消费事件
package juwatech.cn.commission.application;

import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Service;

@Service
public class CommissionEventHandler {

    private final CommissionService commissionService;

    public CommissionEventHandler(CommissionService commissionService) {
        this.commissionService = commissionService;
    }

    @KafkaListener(topics = "order-confirmed")
    public void handleOrderConfirmed(OrderConfirmedEvent event) {
        // 查询推广关系,确定是否应计佣
        PromotionRelation relation = promotionClient.getRelation(event.getUserId(), event.getItemId());
        if (relation != null) {
            BigDecimal rate = taskConfigClient.getRate(relation.getTaskId());
            BigDecimal commissionAmount = event.getOrderAmount().multiply(rate);
            commissionService.createPendingCommission(
                event.getOrderId(),
                event.getUserId(),
                commissionAmount
            );
        }
    }
}

该机制解耦订单与佣金服务,避免直接调用。

防腐层(Anti-Corruption Layer)隔离外部依赖

佣金服务需调用推广服务获取任务配置,但不希望暴露其内部模型。我们通过防腐层转换:

java 复制代码
package juwatech.cn.commission.infra.ac;

import juwatech.cn.commission.domain.TaskRate;
import juwatech.cn.promotion.api.dto.TaskConfigDto;

public class PromotionAcLayer {
    private final PromotionFeignClient client;

    public PromotionAcLayer(PromotionFeignClient client) {
        this.client = client;
    }

    public TaskRate getTaskRate(String taskId) {
        TaskConfigDto dto = client.getTaskConfig(taskId);
        return new TaskRate(dto.getId(), new BigDecimal(dto.getCommissionRate()));
    }
}

TaskRate是佣金域自有模型,不受推广服务变更影响。

Saga模式保障跨服务最终一致性

佣金创建、用户余额更新、账单生成涉及多个服务,我们采用Saga模式实现补偿:

java 复制代码
package juwatech.cn.commission.application;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class CommissionSettlementSaga {

    @Transactional
    public void executeSettlement(String commissionId) {
        try {
            commissionDomain.confirm(commissionId); // 1. 确认佣金
            balanceClient.increaseBalance(userId, amount); // 2. 增加余额
            billClient.createBill(commissionId, amount); // 3. 生成账单
        } catch (Exception e) {
            // 触发补偿
            compensationService.compensate(commissionId, e);
        }
    }
}

补偿服务按逆序执行:

java 复制代码
public void compensate(String commissionId, Exception cause) {
    if (billExists(commissionId)) {
        billClient.cancelBill(commissionId);
    }
    if (balanceIncreased(commissionId)) {
        balanceClient.decreaseBalance(userId, amount);
    }
    commissionDomain.rollbackToPending(commissionId);
}

虽非强一致,但在金融容忍范围内满足业务需求。

CQRS优化查询性能

佣金列表页需展示状态、金额、订单信息等,若从聚合根加载效率低下。我们采用CQRS模式,写模型更新后同步写入读模型:

java 复制代码
// 写操作完成后发布事件
applicationEventPublisher.publishEvent(new CommissionUpdatedEvent(commissionId));

// 读模型监听器
@EventListener
public void onCommissionUpdated(CommissionUpdatedEvent event) {
    Commission commission = commissionRepository.findById(event.getId());
    CommissionView view = viewMapper.toView(commission);
    viewRepository.save(view); // 存入MySQL读库
}

前端直接查询commission_view表,避免复杂JOIN。

本文著作权归聚娃科技省赚客app开发者团队,转载请注明出处!

相关推荐
消失的旧时光-194317 小时前
从 Kotlin 到 Dart:为什么 sealed 是处理「多种返回结果」的最佳方式?
android·开发语言·flutter·架构·kotlin·sealed
惊讶的猫18 小时前
OpenFeign(声明式HTTP客户端)
网络·网络协议·http·微服务·openfeign
鹏北海18 小时前
micro-app 微前端项目部署指南
前端·nginx·微服务
L5434144618 小时前
告别代码堆砌匠厂架构让你的系统吞吐量翻倍提升
大数据·人工智能·架构·自动化·rpa
子春一19 小时前
Flutter for OpenHarmony:色彩捕手:基于 CIELAB 色差模型与人眼感知的高保真色彩匹配游戏架构解析
flutter·游戏·架构
冻感糕人~20 小时前
收藏备用|小白&程序员必看!AI Agent入门详解(附工业落地实操关联)
大数据·人工智能·架构·大模型·agent·ai大模型·大模型学习
ai_xiaogui20 小时前
【开源前瞻】从“咸鱼”到“超级个体”:谈谈 Panelai 分布式子服务器管理系统的设计架构与 UI 演进
服务器·分布式·架构·分布式架构·panelai·开源面板·ai工具开发
匀泪20 小时前
云原生(LVS NAT模式集群实验)
服务器·云原生·lvs
X54先生(人文科技)20 小时前
《元创力》开源项目库已经创建
人工智能·架构·开源软件
无心水20 小时前
分布式定时任务与SELECT FOR UPDATE:从致命陷阱到优雅解决方案(实战案例+架构演进)
服务器·人工智能·分布式·后端·spring·架构·wpf