说明:
- 活动 ID 唯一区分一个活动,本次春节分配了一个单独的母活动 ID
- 场景 ID 和具体的一种奖励类型一一对应,定义该场景下发奖励的唯一配置,场景 ID 可以配置的能力有:发奖励账单文案;是否需要补偿;限流配置;是否进行库存控制;是否要进行对账。提供可插拔的能力,供业务可选接入。
实现效果:
- 实现不同活动之间的配置隔离
- 每个活动的配置呈树状结构,实现一个活动发多种奖励,一种奖励发多种奖励 ID
- 一种奖励 ID 可以有多种分发场景,支持不同场景的个性化配置
订单号设计:
资产订单层支持订单号维度的发奖幂等,订单号设计逻辑为${actID}_${scene_id}_${rain_id}_${award_type}_${statge},从单号设计层面保证不超发,每个场景的奖励用户最多只领一次。
4. 核心难点问题解决
4.1 难点一:支持八端奖励数据互通前文背景已经介绍过了,参与 2022 年春节活动一共有八个产品端,其中抖音系和头条系 APP 是不同的账号体系,所以不能通过用户 ID 打通奖励互通。具体解决方案是字节账号中台打通了八端的账号体系给每个用户生成唯一的 actID(手机号优先级最高,如果不同端登录的手机号一样,在不同端的 actID 是一致的)。钱包侧基于字节账号中台提供的唯一 actID 基础上,设计实现了支持八端奖励入账、查看与使用的通用方案,即每个用户的奖励数据是绑定在 actID 上的,入账和查询是通过 actID 维度实现的,即可实现八端奖励互通。
示意图如下:

每年的春节活动,发现金红包都是最关键的一环,今年也不例外。有几个原因如下:
- 预估发现金红包最大流量有 180w TPS。
- 现金红包本身价值高,需要保证资金安全。
- 用户对现金的敏感度很高,在保证用户体验与功能完整性同时也要考虑成本问题。
终上所述,发现金红包面临比较大的技术挑战。
发红包其实是一种交易行为,资金流走向是从公司成本出然后进入个人账户。
(1)从技术方案上是要支持订单号维度的幂等,同一订单号多次请求只入账一次。订单号生成逻辑为${actID}_${scene_id}_${rain_id}_${award_type}_${statge},从单号设计层面保证不超发。
(2)支持高并发,有以下 2 个传统方案:
具体方案类型 | 实现思路 | 优点 | 缺点 |
同步入账 | 申请和预估流量相同的计算和存储资源 | 1.开发简单; | 浪费存储成本。拿账户数据库举例,经实际压测结果:支持 30w 发红包需要 152 个数据库实例,如果支持 180w 发红包,至少需要 1152 个数据库实例,还没有算上 tce 和 redis 等其他计算和存储资源。 |
异步入账 | 申请部分计算和存储资源资源,实际入账能力与预估有一定差值 | 1.开发简单; | 用户体验受到很大影响。入账延迟较大,以今年活动举例会有十几分钟延迟。用户参与玩法得到奖励后在活动钱包页看不到奖励,也无法进行提现,会有大量客诉,影响抖音活动的效果。 |
以上两种传统意义上的技术方案都有明显的缺点,那么进行思考,既能相对节约资源又能保证用户体验的方案是什么?
最终采用的是红包雨 token 方案,具体方案是使用异步入账加较少量分布式存储和较复杂方案来实现,下面具体介绍一下。
本次春节活动在红包雨/集卡开奖/烟火大会的活动下有超大流量发红包的场景,前文介绍过发奖 QPS 最高预估有 180w QPS,按照现有的账户入账设计,需要大量存储和计算资源支撑,根据预估发放红包数/产品最大可接受发放时间,计算得到钱包实际入账最低要支持的 TPS 为 30w,所以实际发放中有压单的过程。
设计目标:
在活动预估给用户发放(180w)与实际入账(30w)有很大 gap 的情况下,保证用户的核心体验。用户在前端页面查看与使用过当中不能感知压单的过程,即查看与使用体验不能受到影响,相关展示的数据包含余额,累计收入与红包流水,使用包含提现等。
具体设计方案:
我们在大流量场景下每次给用户发红包会生成一个加密 token(使用非对称加密,包含发红包的元信息:红包金额,actID,与发放时间等),分别存储在客户端和服务端(容灾互备),每个用户有个 token 列表。每次发红包的时候会在 Redis 里记录该 token 的入账状态,然后用户在活动钱包页看到的现金红包流水、余额等数据,是合并已入账红包列表 token 列表-已入账/入账中 token 列表的结果。同时为保证用户提现体验不感知红包压单流程,在进入提现页或者点击提现时将未入账的 token 列表进行强制入账,保证用户提现时账户的余额为应入账总金额,不 block 用户提现流程。
示意图如下:

token 数据结构:
token 使用的是 pb 格式,经单测验证存储消耗实际比使用 json 少了一倍,节约请求网络的带宽和存储成本;同时序列化与反序列化消耗 cpu 也有降低。
// 红包雨token结构
type RedPacketToken struct {
AppID int64 `protobuf: varint,1,opt json: AppID,omitempty ` // 端ID
ActID int64 `protobuf: varint,2,opt json: UserID,omitempty ` // ActID
ActivityID string `protobuf: bytes,3,opt json: ActivityID,omitempty ` // 活动ID
SceneID string `protobuf: bytes,4,opt json: SceneID,omitempty ` // 场景ID
Amount int64 `protobuf: varint,5,opt json: Amount,omitempty ` // 红包金额
OutTradeNo string `protobuf: bytes,6,opt json: OutTradeNo,omitempty ` // 订单号
OpenTime int64 `protobuf: varint,7,opt json: OpenTime,omitempty ` // 开奖时间
RainID int32 `protobuf: varint,8,opt,name=rainID json: rainID,omitempty ` // 红包雨ID
Status int64 `protobuf: varint,9,opt,name=status json: status,omitempty ` //入账状态
}
token 状态机流转:
在调用账户真正入账之前会置为处理中(2)状态,调用账户成功为成功(8)状态,发红包没有失败的情况,后续都是可以重试成功的。
token 安全性保障:
采用非对称加密算法来保障存储在的客户端尽可能不被破解,其中加密算法为秘密仓库,限制其他人访问。同时考虑极端情况下如果 token 加密算法被黑产破译,可监控报警发现,可降级。
4.2.2 活动钱包页展示红包流水需求背景:
活动钱包页展示的红包流水是现金红包入账流水、提现流水、c2c 红包流水三个数据源的合并,按照创建时间倒叙排列,需要支持分页,可降级,保证用户体验不感知发现金红包压单过程。

发红包流程降级示意图如下:

