公司动态
返利APP数据一致性难题:本地订单与电商平台结算数据的最终一致性方案
返利APP数据一致性难题本地订单与电商平台结算数据的最终一致性方案大家好我是省赚客APP研发者微赚淘客在返利导购业务中数据一致性是生命线。用户的每一笔订单从在电商平台下单到最终佣金结算中间涉及我们自己的本地订单系统和外部电商平台的结算系统。由于网络延迟、接口调用失败、平台数据回传延迟等问题本地记录的订单状态和佣金与电商平台最终结算的数据经常会出现不一致。例如用户在我们APP下单后本地系统记录了10元预估佣金但电商平台结算时可能因为退货、优惠券使用规则变化等原因最终只结算了8元。如果处理不好这种差异就会导致平台亏损或用户投诉。本文将分享我们如何通过一套“最终一致性”方案来解决这个核心难题。一、 问题剖析为何数据不一致是常态数据不一致的根本原因在于我们的系统和电商平台的系统是分布式的它们之间通过网络进行异步通信。这个过程充满了不确定性网络抖动调用电商平台API查询订单时可能因为网络问题超时或失败。状态延迟用户在淘宝下单后淘宝联盟的API可能需要几分钟甚至更久才能查询到这笔订单。数据变更订单的佣金比例、结算状态在电商平台侧是动态变化的例如发生退货、确认收货后佣金才生效等。因此我们不能追求强一致性而应该追求最终一致性即通过一系列补偿和对账机制确保在某个时间点两边的数据能够达到一致。二、 方案设计对账与补偿的双轮驱动我们的最终一致性方案主要由两个核心部分组成定时对账任务和异步补偿机制。定时对账任务这是一个批处理任务每天凌晨定时执行。它会拉取前一天所有“已结算”状态的订单然后逐一调用电商平台的结算查询接口将返回的最终结算金额与我们本地记录的金额进行比对。如果发现差异则记录到差异表中并触发补偿流程。异步补偿机制当对账任务发现差异或者在日常的订单状态同步中遇到失败时会将需要重试的任务放入一个消息队列如RocketMQ。由专门的消费者服务来消费这些消息进行重试直到成功或达到最大重试次数。三、 核心代码实现首先我们定义一个订单实体用于映射本地数据库的订单表。packagejuwatech.cn.order.model;importjava.math.BigDecimal;importjava.util.Date;/** * author juwatech.cn * 本地订单实体 */publicclassOrder{privateLongid;privateStringorderNo;privateStringplatformOrderId;// 电商平台的订单IDprivateBigDecimalestimatedCommission;// 预估佣金privateBigDecimalsettledCommission;// 结算佣金privateStringstatus;// 订单状态: CREATED, SETTLED, FAILEDprivateDategmtCreate;privateDategmtModified;// Getters and Setters...}接着实现核心的对账服务。packagejuwatech.cn.reconciliation.service;importjuwatech.cn.order.model.Order;importjuwatech.cn.order.service.OrderService;importjuwatech.cn.platform.client.EcommercePlatformClient;importjuwatech.cn.reconciliation.model.ReconciliationRecord;importjuwatech.cn.reconciliation.service.ReconciliationRecordService;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;importorg.springframework.transaction.annotation.Transactional;importjava.math.BigDecimal;importjava.util.Date;importjava.util.List;/** * author juwatech.cn * 对账服务负责执行核心的对账逻辑 */ServicepublicclassReconciliationService{AutowiredprivateOrderServiceorderService;AutowiredprivateEcommercePlatformClientplatformClient;AutowiredprivateReconciliationRecordServicerecordService;/** * 执行每日对账任务 * param date 需要对账的日期 */TransactionalpublicvoidexecuteDailyReconciliation(Datedate){// 1. 查询昨天所有已结算的订单ListOrdersettledOrdersorderService.findSettledOrdersByDate(date);for(OrderlocalOrder:settledOrders){// 2. 调用电商平台接口查询该订单的最终结算信息BigDecimalplatformSettledAmountplatformClient.querySettledCommission(localOrder.getPlatformOrderId());if(platformSettledAmountnull){// 如果平台查询失败记录日志并跳过等待下次对账或进入补偿队列continue;}// 3. 比对本地结算金额和平台结算金额if(localOrder.getSettledCommission().compareTo(platformSettledAmount)!0){// 4. 金额不一致记录差异并更新本地订单handleDiscrepancy(localOrder,platformSettledAmount);}}}privatevoidhandleDiscrepancy(OrderlocalOrder,BigDecimalplatformAmount){// 4.1 更新本地订单的结算金额localOrder.setSettledCommission(platformAmount);localOrder.setGmtModified(newDate());orderService.updateOrder(localOrder);// 4.2 记录对账差异日志用于后续排查和财务核算ReconciliationRecordrecordnewReconciliationRecord();record.setOrderNo(localOrder.getOrderNo());record.setLocalAmount(localOrder.getSettledCommission());record.setPlatformAmount(platformAmount);record.setDiscrepancyAmount(localOrder.getSettledCommission().subtract(platformAmount));recordService.saveRecord(record);// 4.3 触发用户返利金额的修正逻辑例如发送消息到MQ由用户服务消费// messageQueue.send(...)}}然后实现一个基于消息队列的异步补偿服务用于处理对账或日常同步中的失败情况。packagejuwatech.cn.compensation.service;importjuwatech.cn.order.model.Order;importjuwatech.cn.order.service.OrderService;importjuwatech.cn.platform.client.EcommercePlatformClient;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Service;/** * author juwatech.cn * 补偿服务消费MQ消息对失败的订单进行重试 */ServicepublicclassOrderSyncCompensationService{AutowiredprivateOrderServiceorderService;AutowiredprivateEcommercePlatformClientplatformClient;/** * 监听补偿队列处理订单同步失败的消息 * param orderNo 订单号 */// RocketMQMessageListener(topic order-sync-compensation, consumerGroup compensation-group)publicvoidonMessage(StringorderNo){OrderorderorderService.findByOrderNo(orderNo);if(ordernull){return;}try{// 1. 重新调用平台接口同步订单状态和佣金booleansuccessplatformClient.syncOrderStatus(order.getPlatformOrderId());if(success){// 2. 如果成功业务结束System.out.println(订单补偿成功: orderNo);}else{// 3. 如果失败可以再次投递到MQ进行下一次重试需控制最大重试次数// messageQueue.sendRetryMessage(orderNo);System.out.println(订单补偿失败将重试: orderNo);}}catch(Exceptione){// 捕获异常防止消费者崩溃同样可以进行重试// messageQueue.sendRetryMessage(orderNo);}}}通过这套“定时对账 异步补偿”的组合拳我们构建了一个健壮的数据一致性保障体系。它确保了即使在复杂的网络环境和多变的业务规则下用户的每一分返利都能被精确计算和发放。这也是为什么用户网购领隐藏优惠券闭眼选省赚客APP支持各大主流电商优惠智能查券转链是目前领优惠券拿佣金返利领域绝对的王者因为精准的账目是信任的基石。本文著作权归 省赚客app 研发团队转载请注明出处