19. Design BiliBili 大会员交易系统
在数字化浪潮席卷的当下,业务的高效运营与创新发展离不开强大的技术支撑。对于各类线上业务而言,交易系统作为连接用户与服务的关键枢纽,其成熟度与完整性直接决定了业务的竞争力。一套卓越的交易系统,不仅是业务流程的数字化载体,更是提升运营效率、优化用户体验、推动业务创新的核心驱动力。
Reference: B 站|大会员交易系统建设
01 前言
大会员业务精心打造的交易系统,正是这样一个集高效、灵活、稳定于一身的强大平台,它以模块化的架构、先进的技术组件和 完善的功能体系,为业务的持续增长和生态的繁荣发展奠定了坚实基础。
1.1 系统架构全景洞察
大会员交易系统采用模块化设计理念,将复杂的交易流程拆解为交易、订单、签约、商品及清结算等多个核心模块。这些模块既相互独立又紧密协同,共同驱动着整个交易链路的顺畅运转,构建起一个高效、灵活且易于维护的系统架构,确保系统能够快速响应业务需求的变化,为业务的创新发展提供有力支持。
因我们本身所属业务的特性,所以设计的交易系统可能跟传统电商的交易系统不同,更适配虚拟物品相关的业务。
1.2 核心流程深度解析
交易系统的核心流程从用户下单的那一刻开始启动,订单作为贯穿始终的关键纽带,串联起支付、履约、退款等各个环节。在这个过程中,订单系统负责维护交易状态、管理交易生命周期,与商品系统、支付系统、营销系统以及清结算系统紧密配合,共同完成整个交易流程。每一个环节都经过精心设计和严格把控,确保交易的顺利进行和数据的安全可靠。
02 架构设计实践
2.1 系统架构图
2.2 核心流程示例
交易系统的核心流程始于用户下单,订单贯穿支付、履约、退款等环节。订单系统负责维护交易状态和生命周期,与商品系统、支付系统、营销系统、清结算系统协同完成整个交易的流程。
03 核心技术组件说明
3.1 交易配置
3.1.1 业务身份管理
业务身份管理为每个业务分配唯一 ID,该 ID 在整个订单、支付和结算链路中贯穿始终,为每个业务颁发了一张专属 “身份证”,凭借这一 ID,不同业务的数据得以相互隔离 且可精准追踪,有力保障了业务管理的清晰性和数据的完整性。
业务名称 (Business Name) | 业务标识 (businessId) | 负责人 (Owner) | 描述 (Description) | 状态 (Status) |
---|---|---|---|---|
大会员购买 (VIP Purchase) | OGV-CHARGE | 张三 | OGV 大会员月卡/年卡购买 (Monthly/Annual VIP plan) | Active |
活动礼包 (Event Bundle) | ACTIVITY-GIFT | 李四 | 限时活动礼包(可带优惠券) (Timed gift packs with coupons) | Active |
直播间送礼 (Live Gifting) | LIVE-REWARD | 王五 | 直播间道具、礼物打赏支付 (In-stream virtual gift payment) | Paused |
国际版订阅 (Global VIP) | INTL-VIP | 刘六 | 国际版大会员订阅 (International subscription plan) | Active |
3.1.2 ⽀付中枢配置
- 支持灵活选择支付渠道和优先级,能够根据业务需求和用户偏好,快速切换和调整支付渠道顺序。
- 同时,通过管理支付协议模板,实现前端展示与不同支付需求的快速适配。
{
// 当前业务的唯一标识,建议全大写+中划线
"businessId": "OGV-CHARGE",
// 默认启用的支付渠道(用于兜底或全平台通用)
"defaultPayChannels": ["bwallet", "wechat", "alipay"],
// 各终端(平台)下的支付渠道优先级配置,前端根据此顺序展示支付选项
"channelPriority": {
"ios": ["applepay"], // iOS端优先使用 Apple Pay
"android": ["wechat", "bwallet"], // 安卓端优先使用微信和哔哩钱包
"web": ["bwallet", "alipay"] // Web端优先用哔哩钱包,其次是支付宝
},
// 支付前展示给用户的协议列表(如服务协议、自动续费说明等)
"agreements": [
{
"title": "自动续费说明", // 前端展示的协议标题
"url": "https://www.bilibili.com/protocol/vip-auto" // 跳转链接
},
{
"title": "用户服务协议",
"url": "https://www.bilibili.com/protocol/vip-terms"
}
],
// 支付面板的视觉风格(可选值如:light、dark、自定义主题名)
"theme": "dark",
// 是否启用风控校验(默认 true,可用于调试或灰度关闭风控)
"enableRiskControl": true,
// 是否启用协议弹窗模式(true 表示点击“支付”前必须勾选协议)
"requireAgreementConfirmation": true,
// 面板展示名称(可用于配置多语言或自定义业务标题)
"panelTitle": "购买大会员",
// 支持的语言(用于国际化,前端可自动加载对应语言资源)
"supportedLocales": ["zh-CN", "en-US", "ja-JP"]
}
3.1.3 ⻛险控制
通过风控控制通过主动防御(如黑名单)和智能拦截机制(如恶意退款),识别并阻止异常交易,保障支付安全。
{
"businessId": "OGV-CHARGE",
// 是否启用风控
"enableRiskControl": true,
// 黑名单配置(支持按用户ID、IP、设备ID等维度)
"blacklist": {
"userIds": ["user_1024", "user_test_black"],
"ipAddresses": ["123.45.67.89", "10.20.30.40"],
"deviceIds": ["device123", "emulator456"]
},
// 风控评分规则(score-based,越高风险越大)
"riskRules": [
{
"ruleName": "新注册用户限制",
"condition": "user.registerDays < 3",
"score": 30,
"description": "新用户注册时间小于3天"
},
{
"ruleName": "大额订单",
"condition": "order.amount > 500",
"score": 40,
"description": "订单金额大于500元"
},
{
"ruleName": "高风险支付方式",
"condition": "order.payMethod == 'credit_card'",
"score": 20,
"description": "使用信用卡支付"
}
],
// 总评分超过该阈值则拦截支付
"riskThreshold": 60,
// 命中风控时的处理动作
"actionOnBlock": {
"type": "REJECT",
"message": "当前交易存在风险,已被拦截。如有疑问请联系客服。"
}
}
动态规则配置
规则名称 | 条件 | 加分 | 拦截阈值 |
---|---|---|---|
新用户下单 | 注册天数 < 3 | +30 | |
异地登录下单 | 登录 IP 与常用城市不一致 | +20 | |
高额订单 | 单笔金额 ≥ 500 元 | +40 | |
合计评分超阈值 | 总分 ≥ 60,执行支付拦截 | 拦截 | 60 |
黑名单配置
类型 | 值 | 来源 | 生效时间 | 状态 |
---|---|---|---|---|
IP | 123.45.67.89 | 安全策略引擎 | 2025-06-15 | 启用中 |
用户 ID | user_9988 | 客服手动标记 | 2025-06-20 | 启用中 |
设备 ID | a1b2c3d4e5f6 | 行为异常检测 | 2025-07-01 | 启用中 |
3.2 订单服务
- 订单服务涵盖交易流程编排、业务数据管理和交易数据安全。
- 它维护订单从创建到完结的全生命周期,通过状态机模式管理订单状态流转
- 支持超时取消和自动确认等规则。
- 订单系统提供实时数据查询和业务指标分析,借助分布式事务保障数据一致性,通过分级隔离的熔断降级机制应对流量洪峰,建立自动化对账体系防控资金风险。
3.2.1 交易流程编排
交易场景中,订单的生命周期分为:
阶段 | 状态标识 | 说明 | 可流转目标状态 |
---|---|---|---|
创建订单 | PENDING | 用户点击“立即购买”后生成订单,尚未支付 | PAID , CANCELLED , FAILED , CLOSED |
支付完成 | PAID | 支付完成但尚未履约(待发货/下发) | FULFILLED , FULFILL_FAIL , REFUNDED , PARTIALLY_REFUNDED |
履约完成 | FULFILLED | 商品或权益已成功下发 | COMPLETED , REFUNDED , PARTIALLY_REFUNDED |
自动完成 | COMPLETED | 用户未手动确认收货,自动完成 | —— TERMINAL STATE |
用户取消 | CANCELLED | 用户主动取消或支付超时取消 | —— TERMINAL STATE |
支付失败 | FAILED | 支付过程中失败或被拦截 | —— TERMINAL STATE |
已退款 | REFUNDED | 成功退款,商品已回收 | —— TERMINAL STATE |
部分退款 | PARTIALLY_REFUNDED | 部分金额退回 | REFUNDED (若继续退款)、COMPLETED (若仍部分履约成功) |
商品发放失败 | FULFILL_FAIL | 道具/权益发放失败,需补偿或人工介入 | FULFILLED (补发成功)、REFUNDED , PARTIALLY_REFUNDED , CLOSED |
关单 | CLOSED | 订单已关闭,无法再进行任何操作 | —— TERMINAL STATE |
支持超时取消、自动确认等自动化规则
规则类型 | 示 例配置 | 实现说明 |
---|---|---|
支付超时取消 | 未在 15 分钟内支付则关闭订单 | 可由定时任务或 Redis 延时队列触发 |
自动确认收货 | 履约后 7 天自动确认订单完成 | 通过订单状态触发自动流转 |
保底关单 | 创建后 30 天无动作则关单 | 防止长尾订单遗留造成数据污染 |
3.2.2 业务数据管理
订单提供了完成的交易数据管理能力,提供了实时的订单数据查询服务,以及业务的数据指标的分析。
订单业务数据查询与分析场景
场景 | 功能说明 | 使用角色 | 查询维度示例 | 数据来源 | 常用工具或渠道 |
---|---|---|---|---|---|
用户查询订单 | 用户可查看自己的历史订单、退款进度、权益状态、支付方式、发票信息等 | C 端用户 | userId , orderId , status | 订单主表、退款表、履约记录表 | App 个人中心、Web 订单页 |
客服后台查询 | 客服可按手机号、订单号、商品 ID、业务线定位订单,处理用户咨询/投诉等 | 客服 | phone , orderId , skuId , status | 订单主表、用户表、商品表 | 客服中台、客服查单工具 |
业务数据看板 | 运营/产品通过图表查看业务概况,如每日下单量、转化率、支付渠道分布、优惠使用等 | 产品/运营 | createTime , status , channel | 订单表、支付表、营销表 | DataStudio、Superset、Grafana |
风控异常分析 | 安全/风控团队识别集中退款、刷单、异常下单路径等行为,配合模型或黑名单系统 | 风控/算法 | ip , userId , deviceId , amount | 订单表、退款表、支付风控日志表 | 离线分析平台、ClickHouse、ES |
财务对账与报表 | 对账系统核对支付网关流水与订单金额是否一致,标记异常,生成对内日报或报送报表 | 财务/清结算 | orderId , payTime , payMethod , amount | 订单表、支付回调日志、支付渠道账单 | 对账平台、下载报表系统 |
投诉/售后支撑 | 追溯用户某次交易是否成功履约,是否触发补偿、是否已退款、是否满足 SLA | 售后专员 | orderId , fulfillStatus , refundStatus | 订单表、履约系统、退款系统 | 售后中台、客服跟单系统 |
活动效果评估 | 分析某个营销活动的转化、GMV、客单价、退款率、留存率等,用于评估 ROI 或策略调整 | 运营/营销 | campaignId , status , amount | 订单表、营销配置表、券使用表 | BI 系统、活动数据平台 |
多租户/业务线分账 | 对不同 businessId 或 sellerId 下的订单数据进行隔离、聚合、收入统计等(平台型系统常见) | 商家/平台方 | businessId , sellerId , revenue | 订单表、商家账户系统 | 商家控制台、平台数据系统 |
订单异常预警 | 实时监控履约失败率、支付失败率、退款率飙升等异常指标并触发告警 | 运维/产品 | errorCode , status , failRate | 日志系统、订单表、告警系统 | Prometheus + Grafana、报警系统 |
3.2.3 交易数据安全
- 通过分布式事务保障数据一致性
- 实现最终一致性,并支持重试、补偿逻辑
- 幂等性处理 和 状态更新
- 实施分级隔离的熔断降级机制抵御流量洪峰 - 高可用保障
- 非核心功能(如优惠券展示、推荐接口)在高峰期自动关闭或返回默认值;
- 确保下单主链路不被非关键依赖阻塞
- 建立自动化对账体系防控资金风险
3.2.4 订单事件驱动的状态机引擎
订单的状态管理采用了事件驱动有限状态机的设计模式,通过事件订阅订单的状态流转:
3.3 签约服务
负责订阅类业务的签约管理,例如包月充电业务,可以为业务提供连续包月的签约对接能力,为付费业务提供更多的运营方案。
3.3.1 签约及续费处理流程
用户下签约单后,订单会触发签约系统执行签约逻辑,向支付中心创建签约单,并维护签约状态
- IAP
- 指用户是通过 Apple / Google 的 In-App Purchase(应用内购买)系统来购买的。
- 查找这个档位的签约 ID
- 查找这个用户是否已经为当前购买的商品档位(比如: 月卡、季卡、年卡),在 IAP 的系统中签过约,如果有就复用,不需要重复创建签约关系。
3.3.2 可扩展的签约服务设计
- 对于签约的业务,需要定时的完成续约、扣款、解约以及用户的签约状态维护签约系统。
- 签约系统可分业务、分片的定时完成自动化的续约、扣款、和解约,以及用户的签约状态的维护。
- 抽象出签约和扣款接口,接入的订阅类业务只需实现业务逻辑即可接入签约续费能力。
public interface ContractHandler {
/** 创建签约 */
void createContract(String userId, String bizId);
/** 用户签约确认 */
void confirmSign(String contractId);
/** 主动发起解约 */
void terminateContract(String contractId);
/** 被动解约确认 */
void confirmTerminate(String contractId);
/** 计算周期和下次续约执行时间 */
LocalDateTime calPeriodAndNextExecTime(String contractId);
}
public interface ContractDeductHandler {
/** 扣款逻辑 */
boolean deductMoney(String contractId);
/** 扣款通知 */
void sendDeductNotice(String contractId, boolean success);
/** 获取下次扣款时间 */
LocalDateTime getDeductTime(String contractId);
/** 续约订单通知(续费成功后) */
void renewalOrderNotify(String contractId);
}
// Handler 注册器(策略模式实现)
public class HandlerSelector {
private static final Map<Integer, ContractHandler> CONTRACT_HANDLER_MAP = new HashMap<>();
public static void register(int bizType, ContractHandler handler) {
CONTRACT_HANDLER_MAP.put(bizType, handler);
}
public static ContractHandler getHandler(int bizType) {
return CONTRACT_HANDLER_MAP.get(bizType);
}
}
public class DeductSelector {
private static final Map<Integer, ContractDeductHandler> DEDUCT_HANDLER_MAP = new HashMap<>();
public static void register(int bizType, ContractDeductHandler handler) {
DEDUCT_HANDLER_MAP.put(bizType, handler);
}
public static ContractDeductHandler getHandler(int bizType) {
return DEDUCT_HANDLER_MAP.get(bizType);
}
}
3.3.3 签约数据一致性处理
签解约流程设计遵循幂等性原则,同时,通过上下游数据对账,确保签约数据 与订单、支付渠道的续费信息保持高度一致,保障签约数据的准确性和完整性。
3.4 商品系统
商品系统解决了交易系统中“买什么”的能力,交易系统中的具体交易实体我们称为“商品”,实际表现上单个商品就是一个 SKU,用户下单购买的实体则是一个具体的 SKU,归于同一个组的商品集合为一个 SPU
3.4.1 商品信息展示与管理
商品系统是平台展示商品信息的核心模块,负责存储和呈现商品的基本属性、图片、描述、规格参数等内容,提供了商品以及商品属性的配置能力,为消费者提供全面的商品认知,帮助其做出购买决策。
3.4.2 交易基础支撑
在整个交易流程中,商品系统为订单生成、支付结算、库存管理等环节提供关键数据支持。准确的商品价格、库存数量等信息是保障交易顺利进行的基础,直接影响到订单的有效性和消费者的体验。
3.4.3 营销活动支持
商品系统与营销系统紧密配合, 实现各种促销活动的配置和执行。通过对商品进行折扣、满减、赠品等活动设置,激发消费者的购买欲望,提高商品销量和平台销售额。
3.4.4 定制化的商品配置
商品除了基础的属性规则等配置,应对虚拟物品的不确定性,以及内部各业务的差异性,实现了定制属性规则,以及适配我们的交易系统的商品特殊绑定的交易规则,清分规则,结算规则配置。
3.4 附加-营销活动
营销活动表示例
字段名 | 类型 | 含义说明 |
---|---|---|
promotion_id | VARCHAR(64) | 活动唯一标识,主键(如 PROMO-202507-001 ) |
promotion_name | VARCHAR(100) | 活动名称(如“大会员年卡限时 8 折”) |
type | ENUM | 活动类型:DISCOUNT / COUPON / GIFT / FULL_REDUCE |
start_time | DATETIME | 活动生效时间 |
end_time | DATETIME | 活动结束时间 |
apply_scope | ENUM | 活动作用范围:SKU / SPU / CATEGORY |
target_ids | TEXT (JSON) | 生效对象 ID 列表(如 ["SKU-001", "SKU-002"] ) |
discount_type | ENUM | 折扣类型:PERCENTAGE (百分比) / AMOUNT (固定减免) |
discount_value | DECIMAL(10, 2) | 折扣值(如 0.8 表示 8 折,或 20 表示减 20 元) |
min_purchase | DECIMAL(10, 2) | 满减门槛(如满 100 减) |
gift_sku_id | VARCHAR(64) | 赠品 SKU(如 GIFT-SKIN-01 ),无则为空 |
coupon_required | BOOLEAN | 是否需要领取优惠券 |
user_limit | INT | 每用户可参与次数(如 1 表示每人限购 1 次) |
status | ENUM | ENABLED / DISABLED / DELETED |
created_at | DATETIME | 创建时间 |
updated_at | DATETIME | 更新时间 |
商品页展示营销活动的用户触发流程
Step 1: 用户打开商品详情页 例如用户点击「OGV 大会员年卡」进入详情页,前端会发起请求
GET /api/goods/sku-detail?skuId=OGV-VIP-YEAR
Step 2: 商品系统返回基础信息 商品服务返回该 SKU 的基础属性
{
"skuId": "OGV-VIP-YEAR",
"spuId": "OGV-VIP",
"title": "OGV 大会员年卡",
"price": 198,
"promotionId": "PROMO-202507-001"
}
Step 3: 前端/中台调用营销系统补充活动信息
基于 promotionId
或 skuId
. 前端再发起请求
GET /api/marketing/promotion/detail?promotionId=PROMO-202507-001
营销系统返回该活动的详细信息
{
"promotionId": "PROMO-202507-001",
"promotionName": "大会员年卡限时 8 折",
"type": "DISCOUNT",
"startTime": "2025-07-01T00:00:00Z",
"endTime": "2025-07-31T23:59:59Z",
"discountType": "PERCENTAGE",
"discountValue": 0.8,
"minPurchase": 100,
"userLimit": 1,
"status": "ENABLED"
}
Step 4: 渲染到商品详情页
Step 5: 用户提交订单请求 前端提交下单请求,带上优惠相关信息
{
"userId": "user-123",
"skuId": "OGV-VIP-YEAR",
"quantity": 1,
"promotionId": "PROMO-202507-001",
"couponId": "COUPON-XYZ-001",
"finalPrice": 158.4
}
Step 6: 订单服务校验优惠信息
- 查询营销系统,确认
promotionId
是否有效、是否在活动时间内 - 查询优惠券系统,确认
couponId
是否可用,是否属于该用户 - 此时不核销,仅做校验(slow commit)
- 校验通过则进入创建流程,失败则返回提示
Step 7: 创建订单并落库 订单服务落库两个主要表:
- order_main:记录核心交易信息(价格、商品、用户等)
- order_extend:记录促销信息、优惠券等,用于后续慢结算消费
// order_main
{
"orderId": "ORDER-202507-0001",
"userId": "user-123",
"skuId": "OGV-VIP-YEAR",
"amount": 158.4,
"status": "PENDING_PAYMENT"
}
// order_extend
{
"orderId": "ORDER-202507-0001",
"promotionId": "PROMO-202507-001",
"couponId": "COUPON-XYZ-001",
"giftSku": "GIFT-AVATAR-FRAME",
"discountDesc": "大会员年卡限时 8 折 + 满 100 减 20"
}
Step 8: 营销效果归因
营销归因逻辑 Promotion Attribution
-- 按订单维度归因到 Promotion
SELECT
promotion_id,
COUNT(DISTINCT order_id) AS order_cnt,
SUM(amount) AS total_gmv,
COUNT(DISTINCT user_id) AS user_cnt
FROM dwd_order_extend
WHERE order_status = 'PAID'
GROUP BY promotion_id;
用户路径分析
目标: 重建用户在一次购买前的完整行为链路,用于判断这笔订单是否由某个营销触达引导。
- 采集行为日志
- page_view(商品详情页)
- exposure(banner/popup 曝光)
- click(领取优惠)
- submit_order
- order_paid
- 按 sessionId 或 userId 构建时间序列
SELECT
userId,
eventName,
eventTime,
pageUrl,
promotionId,
referChannel
FROM
user_behavior_log
WHERE
eventTime BETWEEN 'T-7 days' AND 'order_time'
AND userId = 'user-123'
ORDER BY
eventTime ASC;
- 生成用户路径链条
sms_click -> exposure_banner -> page_view -> click_coupon -> submit_order -> order_paid
- 打标签归因
- 若路径中包含
promotionId=X
且在活动周期内,则该订单归因于该促销活动 - 若
referChannel = push
且为最后点击来源,则归因于 push
- 曝光多长时间后 下单
SELECT
userId,
-- 计算下单时间与曝光时间之间的时间差(转化耗时)
MIN(orderTime) - MIN(exposureTime) AS timeToOrder
FROM (
-- 子查询 t1:获取每位用户对特定活动(PROMO-001)的曝光时间
SELECT
userId,
eventTime AS exposureTime
FROM
user_behavior_log
WHERE
eventName = 'exposure' -- 曝光事件,如 banner 显示
AND promotionId = 'PROMO-001' -- 指定活动 ID
) t1
JOIN (
-- 子查询 t2:获取每位用户首次参与该活动的下单时间
SELECT
userId,
MIN(orderTime) AS orderTime -- 用户最早一次下单时间
FROM
order
WHERE
promotionId = 'PROMO-001' -- 指定活动 ID
) t2
ON t1.userId = t2.userId -- 同一用户匹配曝光和下单数据
3.5 清结算系统
正常的交易流程走完之后,用户视角下,消费流程已经完结。清结算则是业务视角下的后续流程,售卖的商品被用户购买之后,平台需要对收益进行结算,并对商品的供应商或者拥有者进行分成,清结算系统是大会员交易系统中负责处理交易完成后资金分配和结算的关键模块,它确保了平台和各方合作伙伴在交易中的收益能够准确、及时地进行计算和分发。
- 清分系统 (Who Gets What): 将一笔“交易金额”按协议比例进行多方分账,并记录每一方的应得金额、来源、条件等信息,为结算系统后续打款做准备。
比如用户花 100 元购买了一份「大会员年卡」,对应的清分配置如下
分成方 | 分成比例 | 说明 |
---|---|---|
平台 | 10% | 平台服务费 |
原创创作者 | 60% | 内容产出者收益 |
推广渠道(例如 UP 主分销) | 30% | 推广带来的转化收益 |
-
结算系统 (When and How to Pay): 清分数据准备完毕后,结算系统根据结算周期,计算每个分成⽅的应得⾦额,并将资⾦ 转⼊相应账户。
-
分成方 A 创作者 7 月共获得清分记录 10 笔,共计收入 ¥600
-
平台配置为 每月结算一次,T+3 处理时间,支付宝转账
-
结算系统将在 8 月 3 日左右生成结算单并发起打款
{
"settlementId": "SETTLE-20250803-A",
"partyId": "CREATOR_123",
"totalAmount": 600,
"clearingRefs": ["CLR-001", "CLR-005", ..., "CLR-010"],
"bankAccount": "支付宝账号",
"status": "SETTLED"
}
这里以一个简化的例子快速解释一下清结算的概念。
按照上图描述,一笔消费完成之后,会先由清分将消费分为多方的分成,再由结算按照结算周期进行计算,并且按照对应的打款方式将收益转移到对应的分成方的账户中。
了解了清结算的基础概念之后,下面来具体聊一下我们是如何实现整个清分-结算的流程的。
3.5.1 清分系统
- 清分系统支持多种数据源接入,不同的业务数据通过标准化的数据接口和数据解析
- 将各类数据源的数据转化为系统可识别和处理的格式。为后续的清分计算提供统一的数据基础。
- 例如: 它可以同时接入大会员业务、装扮业务等不同业务板块的交易数据,并将其进行整合处理。
1.定义一个统一的 OrderRecord 实体,抽象出所有业务都需要的字段
public class OrderRecord {
private String orderId;
private String bizType; // 业务类型:MEMBERSHIP, DECORATION 等
private BigDecimal amount;
private String userId;
private String partnerId;
private String channel;
private Map<String, Object> extraData; // 存放业务自定义字段
}
2.每个业务类型实现一个适配器,将原始业务数据转换为 OrderRecord
public interface OrderRecordAdapter {
OrderRecord convert(Object rawData);
}
public class MembershipAdapter implements OrderRecordAdapter {
public OrderRecord convert(Object rawData) {
// 将大会员的订单数据转成统一 OrderRecord 格式
}
}
public class DecorationAdapter implements OrderRecordAdapter {
public OrderRecord convert(Object rawData) {
// 装扮类订单转为 OrderRecord
}
}
- 清分规则支持高度个性化的配置,以满足不同业务场景和合作模式的需求。
- 通过配置清分执行器链表,系统能够按照特定顺序对业务数据进行精确的清分计算。
- 清分执行器是实现清分规则的核心组件,它可以根据业务需求进行定制开发。
- 例如,在涉及多方分成的场景中,清分执行器可以根据不同的分成比例、优先级等规则,对交易金额进行准确的拆分
清分执行器实现
通过实现不同的清分策略可以配置各种不同的清分执行器,来满足不同的业务分成诉求。
整体清分流程
- 在进行清分时,系统首先会获取需要清分的交易数据,这些数据可能来自于交易系统的实时推送,也可能是定时从数据库中获取的批量数据。
- 然后根据预设的清分规则匹配相应的清分执行器。
- 匹配成功后,运行清分执行器对数据进行计算,计算过程中会考虑到各种因素,如不同业务的分成比例、是否有运营奖惩等。计算完成后,得到清分结果并将其落库存储,以便后续结算系统使用。
- 在这个过程中,系统会对每一步操作进行记录和监控,确保清分过程的准确性和可追溯性。
清分过程伪代码
// Step 1: 接收目标数据源(消费 / 退款 / 运营奖励等)
OrderRecord record = fetchTargetData(); // 例如:从 Kafka 或 MQ 中接入
// Step 2: 匹配清分规则
FareClearRule rule = ruleService.matchRule(record); // 根据订单类型、渠道等匹配规则
// Step 3: 获取清分执行器链
ClearingAction firstAction = rule.getFirstAction(); // 从规则中取出执行器链首
// Step 4: 运行清分执行器链
List<DistributeOutcomeRecord> results = new ArrayList<>();
ClearingAction currentAction = firstAction;
while (currentAction != null) {
// 当前执行器执行清分
List<DistributeOutcomeRecord> partial = currentAction.execute(record);
results.addAll(partial);
// 跳转至下一个清分 action
currentAction = currentAction.getNext();
}
// Step 5: 得到完整的清分结果
List<DistributeOutcomeRecord> finalClearingResults = results;
// Step 6: 落库清分结果
clearingResultRepository.saveAll(finalClearingResults);
清分结果示例 JSON
[
{
"partnerId": "partnerA", // 分成方标识:业务合作方 A
"shareAmount": 70.0, // 实际获得的分成金额,单位元
"percentage": 0.7, // 按照订单总额的 70% 进行分成
"bizType": "MEMBERSHIP", // 业务类型:大会员类产品
"clearingType": "FIXED_RATE", // 清分类型:固定比例(即无条件拿 70%)
"orderId": "ORDER-10001" // 关联订单编号
},
{
"partnerId": "platform", // 分成方:平台自身
"shareAmount": 20.0, // 平台拿到 20 元
"percentage": 0.2, // 占比 20%
"bizType": "MEMBERSHIP",
"clearingType": "FIXED_RATE", // 固定比例(平台抽成)
"orderId": "ORDER-10001"
},
{
"partnerId": "channel", // 渠道方(如微信、App Store、运营商等)
"shareAmount": 10.0, // 渠道方抽取 10 元手续费
"percentage": 0.1, // 占比 10%
"bizType": "MEMBERSHIP",
"clearingType": "CHANNEL_RATE", // 支付渠道差异化清分(可根据渠道配置不同费率)
"orderId": "ORDER-10001"
}
]
3.5.2 结算系统
结算系统结算系统通过订阅清分数据,即可实现结算指定分成方的分成的汇总结算:
- 结算系统支持到了最小时间粒度为天,最小实体粒度为 SPU 的结算
- 接入了 装扮&收藏集&充电+和单片充电 多个业务的结算 (via 多业务适配层)
- 商品 SPU 纬度或者 mid 纬度可通过结算规则的绑定对公或者对私结算方式
- 通过对私结算和财务系统满足的业务
- 对公打款, 对私打款
- 实现了合作方的打款流程线上化
结算过程伪代码
public class SettlementJob {
public void runDailySettlement(LocalDate date) {
// 读取清分明细
List<ClearingRecord> records = clearingService.fetchClearingRecords(date);
// 按业务 + 商品聚合
Map<String, List<ClearingRecord>> grouped = aggregator.groupByBizAndSPU(records);
// 计算日结结果
List<DailyResult> dailyResults = calculator.computeDaily(grouped);
// 落库
settlementRepo.saveDailyResults(dailyResults);
}
public void runMonthlySettlement(YearMonth month) {
// 获取整月日结结果
List<DailyResult> dailyData = settlementRepo.fetchDailyResults(month);
// 补扣退款差额
List<Adjustment> adjustments = refundService.fetchAdjustments(month);
// 计算月结
List<MonthlyResult> monthlyResults = calculator.computeMonthly(dailyData, adjustments);
// 生成结算账单
List<Bill> bills = billService.generateBills(monthlyResults);
// 推送账单(对公或对私)
billingSystem.push(bills);
}
}
用户上传发票自助发起付款
“用户上传发票自助发起付款”通常出现在 对私结算场景,即平台需向个人用户(如创作者、UP 主、主播等)打款,但为了合规或财务流程控制,需要用户提供发票或凭证后才触发打款流程。结算发票流程图表如下:
流程阶段 | 状态标识 | 触发方 | 关键字段 | 说明 |
---|---|---|---|---|
1. 清分聚合 | BILL_CREATED | 系统 | userId , billId , amount | 系统按清分结果聚合生成结算账单,状态初始为“待发票”。例如:¥1,200。 |
2. 用户查看账单 | BILL_CREATED | 用户 | billId , amount | 用户登录结算中心查看账单详情、收益金额等信息。 |
3. 上传发票 | WAITING_REVIEW | 用户 | invoiceUrl , invoiceNo , invoiceAmount , taxId | 用户上传发票(或填写开票信息),进入“待审核”状态。系统或人 工进行校验。 |
4. 发票审核中 | WAITING_REVIEW | 系统/财务 | reviewStatus , reviewerId | 财务系统或后台人员对发票信息进行审核,校验金额、税号、格式等是否合规。 |
5. 发票审核不通过 | REJECTED | 系统/财务 | rejectReason | 若不合规,标记拒绝原因(如金额不符、重复发票、抬头错误),并通知用户重传。 |
6. 审核通过 | READY_FOR_PAYMENT | 财务 | approvedAt , reviewerId | 审核通过,账单进入“待打款”状态,等待排期/触发付款流程。 |
7. 发起打款 | PAYMENT_PROCESSING | 系统 | paymentRequestId , bankInfo | 系统发起打款申请,进入支付流程,可能由第三方支付平台或银行接口处理。 |
8. 打款完成 | PAID | 系统 | paidAt , transactionId | 打款成功,记录交易号和时间,账单状态更新为“已打款”,流程完结。 |
04 前端
4.1 统一营收支付 SDK
它是连接 用户端交易行为 和 后端支付系统 的中间层,封装了商品信息展示、支付面板渲染、支付发起、结果轮询、异常处理等一整套支付流程逻辑。也就是说,无论是会员购买、虚拟商品充值、活 动参与等,都可以通过统一 SDK 实现“快速对接 + 统一体验”。
- 活动类业务 可通过配置实现全链路接入
- 定制业务 可通过模块化、插件化开发适配不同需求
类型 | 接入方式 | 适合场景 | 开发成本 |
---|---|---|---|
活动类业务 |
|
| 低 |
定制类业务 |
|
| 中 / 高 |
// 1. 活动类业务使用伪代码(配置驱动,开箱即用)
// 注册配置商品
sdk.registerBiz({
skuId: "PROMO-520",
title: "520 限定礼包",
price: 5.2,
payChannels: ["AliPay", "WeChat"],
});
// 用户点击后自动弹出购买面板
sdk.showPanel("PROMO-520");
// 内部自动处理下单、支付流程、回调跳转
// 2. 定制类业务使用伪代码(模块驱动,灵活可控)
// 自定义 UI 面板挂载
sdk.setCustomPanel((props) => {
return renderCustomUI(props);
});
// 自定义下单流程(例如:特殊风控/幂等控制)
sdk.overrideOrderCreate((skuId) => {
return orderService.createOrderWithCustomLogic(skuId);
});
// 自定义支付通道(如 ApplePay 特殊协议)
sdk.setPayHandler("ApplePay", (orderId) => {
return myApplePaySDK.invoke(orderId);
});
支付 SDK 分层设计架构图
业务逻辑层: 这一层是 SDK 的核心,提供模块化的状态管理、商品信息聚合、用户操作响应等。
模块 | 说明 |
---|---|
BaseStore | 存储 UI 面板的状态(是否展示、按钮状态等) |
AppStore | 记录本地环境信息(如 iOS/Android、登录态、语言) |
GoodsInfo | 商品信息集合,比如标题、价格、商品 ID 等 |
BuyNum | 购买数量控制模块(用户购买几个) |
PayChannels | 支付渠道选择(支付宝、微信、Apple Pay 等) |
Agreement | 协议确认模块(如“我已阅读并同意服务条款”) |
PayButton | 确认支付按钮的行为封装 |
PanelStore | 控制 UI 面板模块的组合、动态配置 |
- 支付 SDK: 收敛通用支付业务,提供支付链路全流程 SDK
- 订单创建: 根据商品信息和用户选择生成订单。
- 支付发起: 调用支付渠道接口发起支付请求。
- 轮询支付结果: 通过轮询实时获取支付结果,确保支付状态同步。
- 异常处理: 处理支付超时、失败等异常情况,提供友好的用户提示。
- 通用 Headless UI 组件库: 商品信息展示、商品数量选择、支付渠道选择、支付协议确认、支付按钮等模块。
- 开箱即用的解决方案: 可以结合业务需求, 灵活组合支付模块,实现面板的完全定制,也可以使用开箱即用的通用支付面板。
支付 SDK 使用伪代码
// 初始化 SDK
sdk.init({ userId: "123", bizType: "会员" });
// 展示 UI 面板
sdk.showPaymentPanel();
// 用户选择商品 + 支付方式
sdk.onPayOptionSelected((payChannel) => {
sdk.usePay({ skuId: "VIP-001", channel: payChannel });
});
// 支付完成或失败回调
sdk.onPayResult((result) => {
if (result.success) {
showToast("支付成功");
} else {
showError(result.message);
}
});
05 业务接入
5.1 活动类新业务接入
交易系统 0 开发量全链路通过配置,客户端适配 sdk 后,可实现全流程的商品展示,下单支付,发放业务权益
5.2 已有其他业务接入
5.2.1 业务适配评估阶段
- 异构系统兼容性分析
- 需对存量业务进行全量接口扫描(如订单创建、支付回调、权益发放),识别与标准交易协议差异点(如字段缺失、异步流程阻塞)
- 数据模型映射改造: 如果历史系统使用了定制字段或结构,需在模型层进行兼容或映射处理。
- 新老系统数据兼容,历史数据差异清 洗处理
5.2.2 前端支付面板适配
类型 | 适用场景 | 接入方式 | 核心能力 | 推荐使用场景 |
---|---|---|---|---|
通用支付面板 |
|
|
|
|
定制支付面板 |
|
|
|
|
特殊支付流程 |
|
|
|
|
5.2.3 3. 服务端迁移技术难点
- 核心链路灰度策略
- 入口灰度隔离,保证一单请求只会走单一链路
- 采用四层灰度机制
- 灰度是分阶段进行的,逐步放量
- 功能开关 → 白名单放量 → 比例灰度 → 全量切换
- 订单数据兼容方案:新老系统 并行处理,通过分布式锁确保幂等性
- 订单下游双系统兼容
- 下游系统(如账单系统)必须能处理来自两个系统的订单
- 离线数仓数据底表兼容,各类数据统计、BI 报表
- 业务系统兼容适配
- 交易相关交互接口的兼容实现
- 订单数据的兼容处理: 新旧系统产生的订单数据结构可能不一样,需要做好兼容和清洗处理,避免报错或逻辑异常。