1. 项目背景与挑战
1.1 项目背景
(1)八端支持:
2022年,字节系产品在春节活动中面临的挑战是支持八个不同的APP产品(包括抖音、抖音火山版、抖音极速版、西瓜视频、头条、头条极速版、番茄小说、番茄畅听)。用户在这些平台上参与活动,所获得的奖励可以在任意平台上提现或使用。
(2)多样的玩法:
活动形式丰富多样,涵盖了集卡、红包雨、朋友页面红包雨、集卡开奖以及烟火大会等多种玩法,确保了用户的参与热情和活动的可玩性。
(3)丰富的奖励种类:
活动奖品的种类多达十余种,包括现金红包、补贴视频红包、广告券、电商券、支付券、消费金融券、保险券、信用卡优惠券、喜茶优惠券、电影票券、dou+券、抖音文创券以及头像挂件等,让用户有更多选择和动力参与。
1.2 核心挑战
(1)大流量支持:
设计并实现一个支持八端平台之间奖励互通的奖励入账系统,并应对每秒最高可达360万次请求的高并发场景。
(2)复杂场景与奖励种类:
面对多种发放奖励的场景和多达10种不同的奖励类型,需要与多个下游系统进行对接,同时保证系统的高可用和低延迟。
(3)综合保障:
从系统稳定性、用户体验、资金安全到运营基础能力等多个层面进行全面保障,确保春节活动的顺利进行,并能够及时应对突发问题。
1.3 主要目标
(1)奖励入账系统:
设计和实现一个全面支持八端平台奖励互通的奖励入账系统。该系统需要对接多个下游奖励系统,消除不同系统间的差异,并向上游业务提供统一的接口协议,确保奖励入账的准确性和一致性。同时,还需实现幂等能力、错误处理机制及奖励预算控制,确保活动的平稳进行。
(2)奖励展示与使用:
开发和实现活动钱包页面,让用户在八个不同端口上查看、提现或使用所获得的奖励(如现金、卡券、挂件等),确保用户体验的一致性与流畅性。
1.4 基础能力
- SDK支持: 提供基础SDK,包括查询红包余额、累计收入、查询用户是否获得过奖励等功能,供业务方快速查询使用。
- 预算控制: 与上游发奖端的算法策略无缝对接,实现卡券奖励入账的库存控制,避免出现超发现象。
- 提现灰度放量: 在春节活动高峰期提供用户提现的灰度放量能力,同时解决提现过程中未入账的处理问题。
- 运营干预能力: 提供灵活的运营配置能力,支持发布公告、活动调整以及应急处理,确保应对突发情况时能及时满足业务需求。
1.5 稳定性保障
在高并发的入账场景下,确保钱包核心路径的稳定性,借助资源扩容、流量限流、熔断、降级等稳定性保障手段,维护用户奖励体验的核心流畅度。
1.6 资金安全保障
通过幂等性、对账机制、监控与报警等多重保障措施,确保资金的安全,避免任何资金损失,确保用户获得的奖励无遗漏,并且不会出现多发或漏发情况。
1.7 活动隔离
在不同的活动阶段(如内部测试、灰度发布及正式活动阶段)实现奖励入账和展示的数据隔离,确保不同阶段的数据互不影响,保证各阶段活动的独立性与稳定性。
2. 产品需求概述
在字节的春节活动中,用户可以通过任意端口参与,并获得相应奖励。以抖音红包雨现金红包入账场景为例,整个业务流程如下所示:
- 用户登录抖音
- 参与活动
- 进入活动钱包页
- 点击提现按钮
- 进入提现页面
- 进行提现操作
- 查看提现结果
同时,用户也可以直接从钱包页进入活动钱包页,查看自己参与活动所获得的奖励。
最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。
这是大佬写的 7701页的BAT大佬写的刷题笔记,让我offer拿到手软
奖励发放核心场景
- 集卡活动:用户在集卡环节通过抽卡获得各类卡券。如果用户是集卡锦鲤,还能获得大额现金红包。集卡开奖时,用户还可以获得瓜分奖惠券。
- 红包雨:此场景中会发放红包、卡券和视频补贴红包。其中,红包和卡券的发放量最大可达到180万次每秒的高并发。
- 烟火大会:发放红包、卡券和头像挂件等奖励。
这些核心场景构成了活动奖励发放的主要部分,确保了不同形式的奖励能够高效地覆盖到每位参与用户,并且在高并发的情况下,系统能够稳定、流畅地处理奖励发放的任务。
如果你近期准备面试跳槽,建议在CXYKK.COM:程序员快看在线刷题,涵盖 1万+ 道 Java 面试题,500套技术教程,几乎覆盖了所有主流技术面试题、简历模板、算法刷题,,全部免费
3. 钱包资产中台设计与实现
在2022年春节活动中,UG团队主要负责活动玩法的实现,包括集卡、红包雨和烟火大会等活动的具体业务逻辑和稳定性保障。而钱包部分的职责则集中在如何在大流量场景下实现奖励的入账、展示、使用以及资金的安全保障。资产中台则是负责奖励发放与展示的核心系统。
3.1 春节资产中台总体架构
钱包资产中台的系统架构分为两个主要部分:
-
资产订单层:
该层的职责是收敛八端平台的奖励入账链路,并为上游活动业务方(如UG、激励中台、视频红包等)提供统一的接口协议。它隐藏了对接奖励业务下游的具体实现,并支持预算控制、补偿机制、订单号幂等等功能。 -
活动钱包API层:
该层负责收敛八端平台的奖励展示链路,同时能够支持大流量场景下的请求处理。通过高效的API设计,确保用户能够顺畅查看奖励和进行提现等操作。
3.2 资产订单中心设计
资产订单中心的设计以奖励发放为核心,并通过以下方式保证高效和稳定的奖励发放:
核心发放模型:
- 活动ID:每个活动通过唯一的活动ID来区分,本次春节活动使用了单独的母活动ID。
- 场景ID:每种奖励类型与具体的发放场景一一对应,定义了该场景下发放奖励的配置。场景ID的配置可以包括:奖励账单文案、是否需要补偿、限流配置、是否进行库存控制、是否要进行对账等功能。
通过提供可插拔的能力,支持业务方灵活选择接入,保证不同场景能够满足个性化的需求。
实现效果:
- 活动隔离:保证不同活动间的配置完全隔离,确保它们互不干扰。
- 奖励配置树状结构:每个活动可以发放多种奖励,同时每种奖励可以关联多种奖励ID。
- 分发场景的个性化配置:每种奖励ID可以在不同的场景下进行个性化配置,确保灵活性。
3.3 订单号设计
资产订单层支持基于订单号维度的发奖幂等性,确保每个场景的奖励用户最多只能领取一次。为了避免超发,订单号的设计遵循以下格式:
${actID}_\${scene_id}_\${rain_id}_\${award_type}_\${stage}
这种设计方式通过订单号来保证幂等性和精确的奖励发放,确保每个用户在特定场景下的奖励仅发放一次,从而避免了多发的问题。
4. 核心难点问题解决
4.1 难点一:支持八端奖励数据互通
正如前文所提到,2022年春节活动涉及八个产品端,其中包括抖音系和头条系APP,这两个系的账号体系并不一致,因此无法通过用户ID直接实现奖励互通。为了解决这个问题,字节账号中台打通了八端的账号体系,并为每个用户生成了唯一的actID
(优先使用手机号,如果不同端的手机号相同,则actID
一致)。
在此基础上,钱包端根据字节账号中台提供的唯一actID
,设计并实现了一个通用的解决方案,使得每个用户的奖励数据都与actID
绑定。无论用户在哪个端口参与活动,奖励的入账、查询和使用都通过actID
维度进行操作,从而实现了八端之间的奖励数据互通。
示意图如下:
4.2 难点二:高场景下的奖励入账实现
在春节活动中,发放现金红包是最为关键的一部分,且其挑战性极大,主要体现在以下几个方面:
- 超大流量:预计发放现金红包的流量高达180万TPS。
- 资金安全:现金红包本身涉及较高的资金价值,确保资金的安全至关重要。
- 用户敏感度:用户对现金奖励具有很高的敏感度,因此在保证用户体验和功能完整的同时,也需要控制成本。
发放红包本质上是一次交易行为,资金流向是从公司账户流出,然后进入用户的个人账户。在技术实现上,主要需要支持订单号维度的幂等性,即同一个订单号无论请求多少次,只会入账一次。订单号的生成逻辑为:
${actID}_\${scene_id}_\${rain_id}_\${award_type}_\${stage}
通过这种设计,确保了每个场景的奖励不会超发。
4.3 传统方案的对比
为了处理如此高的并发,存在两种常见的技术方案:
具体方案类型 | 实现思路 | 优点 | 缺点 |
---|---|---|---|
同步入账 | 为预估流量申请相应数量的计算和存储资源 | 1. 开发简单; 2. 错误率较低 | 资源浪费极大。实际压测表明,支持30万发红包需要152个数据库实例,若要支持180万发红包,需要至少1152个数据库实例,此外还需要大量的计算和存储资源,如TCE、Redis等。 |
异步入账 | 申请部分计算和存储资源,实际入账能力与预估存在差距 | 1. 开发简单; 2. 不容易出错; 3. 不浪费资源 | 用户体验较差。由于入账延迟较长,用户在参与玩法并获得奖励后,可能会面临延迟十几分钟才能在活动钱包页看到奖励,并且无法立即提现,导致大量用户投诉,影响活动效果。 |
虽然这两种传统方案各有优缺点,但它们都无法同时保证资源利用的高效性和用户体验的流畅性。因此,如何在保证资源节省的同时,保持较好的用户体验,成为解决问题的关键。
4.4 红包雨Token方案
最终,针对红包雨、集卡开奖以及烟火大会等大流量发奖场景,我们选择了“红包雨Token方案”。该方案结合了异步入账和分布式存储的优势,采用了较复杂的技术设计,以支持高流量场景下的奖励入账。
在此方案中,我们预估发奖的QPS最高可达到180万,而根据现有的账户入账设计,需要大量的存储和计算资源。因此,我们计算出钱包实际入账最低需要支持30万TPS的流量。基于此要求,我们通过引入压单的过程来调节系统压力,确保在高并发情况下系统依然能够稳定运行,同时避免资源浪费。
通过红包雨Token方案,我们不仅有效地减少了资源浪费,同时也保障了用户体验,确保用户能够及时看到自己的奖励并进行提现,从而解决了传统方案中的瓶颈问题。
4. 核心难点问题解决
4.1 难点一:支持八端奖励数据互通
如前所述,2022年春节活动涉及八个不同的产品端,其中包括抖音系和头条系APP,而这两个系有各自独立的账号体系,无法通过直接的用户ID来实现跨端的奖励互通。为了解决这个问题,字节账号中台统一了八端的账号体系,并为每个用户生成了唯一的actID
(优先使用手机号,若同一手机号在不同端登录,actID
保持一致)。
在此基础上,钱包系统设计了一个通用方案,确保每个用户的奖励数据绑定在唯一的actID
上,所有奖励的入账、查询和使用都通过actID
来实现,从而在不同平台之间实现奖励数据的互通。
4.2 难点二:高场景下的奖励入账实现
春节活动中的现金红包是核心环节之一,尤其是在发放现金红包时,面临以下几个挑战:
- 高并发: 预计每秒发放180万次红包。
- 资金安全: 现金红包的价值较高,需要确保资金流转的安全。
- 用户体验: 用户对现金奖励的敏感度极高,必须在保障功能完整的同时,优化用户体验和控制成本。
发红包本质上是一次交易行为,资金从公司账户流出并进入个人账户。因此,技术上需要支持基于订单号的幂等性,确保同一个订单号只会入账一次。订单号设计为:
${actID}_\${scene_id}_\${rain_id}_\${award_type}_\${stage}
确保每个场景的奖励不会超发。
4.3 传统方案对比
为应对高并发的奖励入账问题,存在两种常见方案:同步入账和异步入账。
方案类型 | 实现思路 | 优点 | 缺点 |
---|---|---|---|
同步入账 | 根据预估流量申请计算和存储资源 | 开发简单、错误率低 | 存储资源浪费严重 |
异步入账 | 申请部分计算和存储资源,实际入账能力与预估流量存在差距 | 不浪费资源 | 用户体验差,存在延迟 |
这两种方案各有优缺点,无法同时兼顾资源效率和用户体验。因此,采用了红包雨Token方案,在此方案中,红包发放会生成一个加密Token,记录红包的相关信息,并在客户端与服务端都存储该Token。每个用户有一个Token列表,入账状态会记录在Redis中。用户在活动钱包页查看余额和流水时,系统会合并已入账的红包列表和未入账的Token列表,并在提现时强制入账未入账的Token,确保用户提现时账户余额为实际应入账的总金额,不会阻塞提现流程。
4.4 红包雨Token方案
在红包雨、集卡开奖和烟火大会等场景中,红包发放量极大,最大流量预计达到180万QPS。根据现有账户入账设计,支持此类流量需要大量存储和计算资源。我们计算出,钱包实际入账最低要支持30万TPS的流量。为此,我们采用了压单机制,并在不影响用户体验的前提下,保证系统稳定运行。
Token 数据结构:
红包雨Token采用protobuf
格式,经过单元测试后发现,它比传统的JSON格式节省了一半的存储空间和带宽,同时减少了CPU的序列化和反序列化消耗。
type RedPacketToken struct {
AppID int64 `protobuf:"varint,1,opt,name=app_id" json:"app_id,omitempty"` // 客户端应用ID
ActID int64 `protobuf:"varint,2,opt,name=act_id" json:"act_id,omitempty"` // 活动发起者用户ID
ActivityID string `protobuf:"bytes,3,opt,name=activity_id" json:"activity_id,omitempty"` // 活动唯一标识
SceneID string `protobuf:"bytes,4,opt,name=scene_id" json:"scene_id,omitempty"` // 场景标识
Amount int64 `protobuf:"varint,5,opt,name=amount" json:"amount,omitempty"` // 红包金额(单位:分)
OutTradeNo string `protobuf:"bytes,6,opt,name=out_trade_no" json:"out_trade_no,omitempty"` // 商户订单号
OpenTime int64 `protobuf:"varint,7,opt,name=open_time" json:"open_time,omitempty"` // 开奖时间戳
RainID int32 `protobuf:"varint,8,opt,name=rain_id" json:"rain_id,omitempty"` // 红包雨批次ID
Status Status `protobuf:"varint,9,opt,name=status" json:"status,omitempty"` // 入账状态
Nonce string `protobuf:"bytes,10,opt,name=nonce" json:"nonce,omitempty"` // 防重放随机数
Version string `protobuf:"bytes,11,opt,name=version" json:"version,omitempty"` // 数据版本标识
}
4.5 Token 状态流转
红包Token在未入账前会置为“处理中”(状态2),一旦成功入账,状态更新为“成功”(状态8)。如果发红包没有失败,系统会进行重试,直到成功入账为止。
4.6 Token 安全性保障
Token的安全性通过非对称加密算法来保障,确保存储在客户端的Token尽量不被破解。加密算法的秘密仓库限制了非授权访问。若极端情况下Token加密被破解,系统将进行监控和报警处理,并可通过降级措施应对潜在风险。
4.7 活动钱包页展示红包流水
在活动钱包页,红包流水的展示包括现金红包入账流水、提现流水和C2C红包流水,所有数据源合并并按照创建时间倒叙排列。该页支持分页显示,并在系统压力较大时进行降级,确保用户体验不受影响。
4.8 难点三:发奖励链路的稳定性保障
红包发放流程的降级示意图如下:
正如经验所示,功能复杂的系统往往依赖较多,稳定性风险也随之增大。为了解决这一问题,我们采取了多个保障措施,包括资源扩容、熔断、限流等手段,确保系统能够在高并发的情况下稳定运行,避免发生单点故障或系统崩溃。
解决方案
在春节活动的高流量场景下,确保现金红包的顺利入账是至关重要的。为保障红包入账功能的稳定性与幂等性,同时避免超发,我们采取了一系列方案来应对不同情况下的技术挑战。尤其是在强弱依赖的链路中,我们需要确保即使出现极端情况,系统能够支持降级处理,不影响发奖的主流程。
现金红包入账的强弱依赖
在现金红包入账的过程中,不同的服务和存储资源具有不同的依赖关系。根据这些依赖关系,我们设计了相应的降级方案,确保系统即使在极端情况下也能正常运行,并尽量减少对用户体验的影响。
发红包强弱依赖梳理图:
组件 | 依赖服务 | 是否强依赖 | 降级方案 | 降级后影响 |
---|---|---|---|---|
资产中台 | TCC | 是 | 降级读取本地缓存 | 无 |
ByteKV | 否 | 主动降级跳过ByteKV,依赖下游做幂等 | 无 | |
资金交易层 | 分布式锁 Redis | 否 | 被动降级,调用失败,直接跳过 | 基本无 |
Token Redis | 否 | 主动降级不调用Redis | 用户感知入账延迟,可能产生客诉 | |
MySQL | 是 | 切换主库 | 故障期间红包不可用 |
从上表可以看出,不同服务和存储资源的依赖关系有所不同,其中MySQL和TCC属于强依赖,系统必须保证它们的可用性;而ByteKV和Redis则是弱依赖,可以在出现故障时通过降级处理来保障系统正常运行。
4.4 难点四:大流量发卡券预算控制
需求背景
春节活动的烟火大会将在除夕晚上7点半开始,这是一个大流量集中发券的场景。为了防止超发,需要在钱包侧与算法策略配合进行卡券发放的库存控制。具体的目标是保证每个卡券的发放量不超过预定的预算,并且在卡券数量较少时采用兜底方案,避免过多超发。
具体实现
- 卡券消耗量管理: 钱包资产中台维护每个卡券模板ID的消耗发放量,实时更新每个卡券的消耗状态。
- 发放前的库存检查: 每次卡券发放前,算法策略会读取钱包SDK,获取该卡券模板ID的消耗量以及总库存数,并设置一个阈值。当卡券剩余量低于10%时,不再发放该卡券,改为发放兜底券或祝福语等替代品。
- 库存超发控制: 在卡券发放过程中,钱包资产中台会利用Redis进行原子操作,通过
incr
命令累加卡券消耗量,并与总库存进行对比,如果消耗量超过库存数,拒绝发放,防止超发。
优化方向
- Redis热Key问题: 在大流量情况下,Redis会出现热Key问题,导致性能瓶颈。为解决此问题,我们可以拆分Key,通过分布式方式避免单个Key压力过大。
- Redis超时问题: 由于大流量操作可能引起Redis超时,导致发券数量减少,我们在活动开始前预留了5%的库存量来缓解由于超时导致的少发问题。
4.5 难点五:高QPS场景下的热Key稳定性保障
需求背景
在除夕晚上7点半,烟火大会活动开始时,需要展示所有红包雨和烟火大会红包的实时累计发放总额,预估读取QPS为180万,写入QPS为30万。为了保证系统的稳定性,必须处理热点Key和更新延迟,容灾方案应确保系统误差控制在一个可接受的范围内。
4.5.1 方案一:分布式Redis缓存优化
针对这种超大流量场景,我们需要优化Redis缓存,以确保读取和写入的稳定性。由于单个Redis实例的瓶颈限制(每秒支持大约3万QPS),我们设计了将数据拆分成多个Key的方案,并结合本地缓存进行兜底。这样可以避免单点瓶颈,提高系统整体的性能和稳定性。
具体写入流程:
我们将数据拆分为100个Redis Key,按actID%100
的规则来分配每个Key。每次发红包时,使用incr
命令原子性地增加相应Key的值,并且避免重试操作,以保证幂等性。
具体读取流程:
读取时,我们首先尝试从本地缓存获取数据。如果本地缓存为空,则从Redis中读取多个Key,并将它们的值累加后返回给用户。
问题与挑战:
- 拆分Key带来的资源消耗: 拆分100个Key会导致读扩散问题,可能需要较多的Redis资源,增加了存储成本。并且在读取时,无法保证一次性读取所有Key,可能导致读取延迟或部分Key未能及时更新。
- 容灾方案: 如果使用备份Redis,也需要更多的存储资源,带来额外的存储成本。
通过这一系列优化方案,我们能够有效地应对春节活动中大流量带来的技术挑战,确保在高并发场景下系统的稳定性和用户体验。
4.5.2 方案二
设计思路
在方案一的基础上,我们对系统进行优化,旨在节省资源并提高容灾能力,同时确保数字不断累加的要求。通过使用本地缓存合并写请求进行原子性累加,读操作则通过返回本地缓存的值来减少额外存储资源的占用。最终,所有读取的数据都将从 Redis 中获得中心化存储,保证最终返回的值一致。
具体设计方案
每个容器实例启动时都会执行定时任务,任务分为读 Redis 和写 Redis 两部分。下面详细描述这两部分的具体流程。
读取流程:
- 本地定时任务每秒执行一次,读取 Redis 中单个 Key 的值。如果读取到的值大于本地缓存中的值,则更新本地缓存的值。
- 对外暴露的 SDK 会直接返回本地缓存中的值。
- 需要注意的是,在实例启动后的第一秒内,本地缓存没有数据,因此读操作会阻塞直到数据可用。
写入流程:
- 由于读取操作都从本地缓存获取数据(且本地缓存不设过期时间),所以主要关注并发写入的处理。
- 本地缓存写操作使用 Go 的
atomic.AddInt64
来确保原子性地累加本地写缓存的值。 - 定时任务每次执行时,首先将本地写缓存的内容复制到
amount
变量中,然后原子性地减少本地缓存中的值,最后使用incr
命令将amount
的值累加到 Redis 中,从而确保 Redis 中的单个 Key 值能够持续累加。 - 为了确保系统稳定性和容灾能力,我们采用了备份 Redis 集群。写入操作会同时写入主 Redis 和备份 Redis。当主 Redis 集群出现故障时,系统会自动切换到备份 Redis,通过配置开关来读取备份 Redis的数据。为了保证数据一致性,我们设计了定时任务来进行数据同步和修正。
在此方案中,Redis 的流量与实例数成正比。
经过调研,我们了解到主会场实例数为 2 万个,资产中台实例数为 8 千个,预计 Redis 需要支持的 QPS 为 2.8万 / 定时任务执行间隔(单位:秒)。
经过压测,Redis 单实例可以支持单个 Key 读取 2 万 QPS 和 8 千次 incr
操作。
因此,定时任务的执行间隔设置为 1 秒。如果实例数增加,可以适当延长执行间隔。
4.5.3 方案对比
方案 | 优点 | 缺点 |
---|---|---|
方案一 | 1. 实现简单,开发成本较低; 2. 易于理解和部署。 | 1. 存储资源浪费较大; 2. 难以实现容灾方案; 3. 累加过程无法保证持续性。 |
方案二 | 1. 节约资源; 2. 容灾方案设计简单,易于实施; 3. 更加高效,保证数据一致性。 | 1. 实现相对复杂; 2. 需要谨慎处理并发和原子性累加问题。 |
结论
综合考虑实现效果、资源成本、容灾能力以及系统的稳定性,最终我们选择了方案二进行上线。这一方案不仅能够节约资源,提升容灾能力,还确保了数据累加的连续性和一致性,满足了高并发场景下的需求。
4.6 难点六:进行母活动与子活动的平滑切换
需求背景
为了确保春节活动的顺利上线和交付质量,我们将活动划分为三个阶段:
-
第一阶段:内部测试阶段
在这一阶段,主要由内部人员进行测试,确保系统各项功能的稳定性。 -
第二阶段:外部演练阶段
该阶段为灰度放量,限定部分外部用户参与活动。通过这种方式,我们可以在较小范围内验证活动功能,并及时发现和解决潜在问题。 -
第三阶段:正式春节活动
这是最终的正式活动阶段,涵盖了广泛的用户群体,目的是验证活动的实际效果和用户体验。
这三个阶段是完全独立的,其中每个阶段都包含用户奖励的获取、展示与使用。这种逐步推广的方式能够有效避免一次性放量可能带来的系统压力,并能在演练阶段及时解决问题,从而确保正式活动的顺利进行。
4.6 难点六:进行母活动与子活动的平滑切换
需求背景
为了确保春节活动的顺利交付,我们将活动分成三个阶段进行部署:
-
第一阶段:内部人员测试阶段
该阶段主要由内部团队进行功能验证,确保系统的各项功能在内部环境中稳定运行。 -
第二阶段:外部演练阶段(灰度放量)
在此阶段,部分外部用户被邀请参与活动,以验证系统的稳定性、用户体验以及各种可能的问题。该阶段的主要目标是发现并解决潜在问题,影响范围较小。 -
第三阶段:正式活动阶段
这是整个春节活动的正式开始,面向广泛的用户群体,旨在提供完整的活动体验。
这三个阶段是完全独立的,涉及到用户获得奖励、展示奖励和使用奖励等多个方面。在不同的阶段,活动配置和奖励内容可能发生变化,因此需要有灵活的配置管理机制,确保各阶段活动的顺利切换。
设计思路
为了应对多个阶段之间的活动切换问题,我们在钱包资产中台设计了母活动与子活动的分层配置机制。母活动代表整个春节活动,而子活动则根据不同时间段的需求进行配置切换。通过这种方式,我们能够在不同时间段自动切换不同的子活动配置,从而满足不同阶段的产品需求。
这种设计减少了上游和下游系统之间的沟通成本,同时避免了配置出错的风险。在实施过程中,我们还确保了系统能够同步切换配置,大大提高了研发与测试的效率。
设计示意图:
通过这种方式,我们能够有效地管理多个阶段的活动配置,同时确保每个阶段的奖励、活动和用户体验都能够精确控制。
4.7 难点七:大流量场景下资金安全保障
需求背景
在春节活动期间,现金红包的发放面临着极大的资金压力。为了保证大流量、大预算的现金红包发放过程中的资金安全,我们从以下三个方面进行了保障:
-
整体预算控制拦截:
对于整个活动的现金红包预算进行控制,防止资金超出预算。 -
单笔红包发放金额上限拦截:
设置单笔红包的最大金额限制,防止个别用户通过恶意行为获得过高的奖励。 -
资金对账机制:
进行实时和小时级的资金对账,确保资金发放的准确性。- 小时级对账: 针对红包雨、集卡、烟火红包等场景进行小时级别的对账,并设置兜底核对机制,确保资金准确无误。
- 准实时对账: 针对红包雨已入账的红包数据,与钱包资产中台和活动侧进行准实时对账,及时发现和修正异常情况。
资金对账示意图
准实时对账流程图
准实时对账监控与报警
通过实时监控和报警机制,我们能够及时发现资金入账的异常情况,并在第一时间启动紧急预案进行处理,保障资金的安全性。
5. 通用模式抽象
在经历了春节活动的大流量处理后,我们总结了一些经验教训,并提炼出一些通用模式,希望对未来的大流量场景处理有所帮助。
5.1 容灾降级层面
在大流量场景中,容灾能力是至关重要的。为了确保活动的最终上线效果和稳定性,我们采用了多种容灾机制。以下是我们采取的一些措施:
- 降级处理: 当系统出现性能瓶颈时,能够及时启动降级策略,保证核心业务的正常运行。
- 限流机制: 对于超出预期流量的请求进行限流,防止系统崩溃。
- 熔断机制: 在系统出现异常时,快速中断对外服务,避免连锁反应。
- 资源隔离: 将不同的服务进行资源隔离,避免某一服务的故障波及到其他服务。
通过这些措施,我们能够有效应对大流量情况下的风险,确保活动的稳定性和用户体验。
5.1.1 限流层面
在限流方面,我们采用了多层次的限流策略:
- API层限流: 使用Nginx进行入流量限流,防止过多请求打入服务。
- 分布式入流量限流: 对来自不同源的请求进行限流,避免单一来源的流量造成系统崩溃。
- 分布式出流量限流: 控制服务向外部输出的流量,确保下游系统不被压垮。
这些限流器是字节跳动公司内部的公共中间件,经过了大流量的验证,确保在春节活动期间流量不会超出系统承载能力。
限流目标
我们的限流目标是:
- 保证服务稳定性:防止外部的预期外流量压垮自身服务。
- 防止雪崩效应:通过合理的限流策略,避免出现系统崩溃或性能退化的情况。
- 保证用户体验:核心业务流程不受影响,用户体验始终保持高效稳定。
对于集群限流,我们采用了实例维度的限流策略,每个实例的QPS=总配置限流QPS/实例数。通过压测和实际运行,及时调整配置,确保服务稳定运行。
限流方式:
- 对于低QPS场景,我们使用Redis计数方式,精度较高。
- 对于高QPS场景,精度要求较低,限流退化为总QPS/tce实例数的单实例限流。
通过这些限流策略,我们能够确保在高并发场景下,系统稳定运行并为用户提供流畅的体验。
5.1.2 降级层面
在面对高流量场景时,确保系统的稳定性是至关重要的。为了避免单点故障影响到整个活动流程,每个核心功能都必须有明确的降级方案,以保证在突发情况下,系统仍能稳定运行。
-
降级开关的实现
本次春节活动在奖励入账和活动钱包页面方面做了充分的操作预案,设定了26个降级开关。关键时刻,我们可以通过关闭某些非核心功能,避免单点问题影响到主流程,确保核心链路的稳定。 -
金红包发放链路的降级方案
以发放现金红包为例,钱包系统最后的降级方案是仅依赖Docker和MySQL,其他依赖都可以降级掉。比如,当MySQL主库出现问题时,可以通过紧急切换到备用主库来保障系统继续运行。虽然在实际情况中这些降级方案未必完全用上,但提前设计这些降级路径是确保活动万无一失的重要步骤。
5.1.3 资源隔离层面
资源隔离是高流量活动中不可忽视的一个环节,它有助于提升开发效率和避免资源竞争,同时确保关键业务和常规业务互不影响。
-
复用现有接口和代码流程
为提升开发效率,我们充分利用了现有的接口和代码流程,避免了重复造轮子。例如,钱包资产中台也支持了抖音的资产发放需求,因此我们能够在春节活动中复用这些现有接口,减少了开发工作量。 -
集群隔离
在活动期间,服务层面我们做了集群隔离,专门为春节活动创建了专用的活动集群。这意味着活动的流量和常规的业务流量不会相互干扰。此外,底层的存储资源也进行了隔离,确保活动流量的高效处理不会影响常规流量。
5.1.4 存储预估
确保存储资源能够应对活动期间的高流量是非常关键的。我们不仅考虑了Redis和MySQL能否承载预期的流量,还对存储资源进行了详细的预估,确保存储足够应对大规模数据处理。
-
Redis和MySQL扩容
- Redis垂直扩容:每个Redis实例可以增加最大10GB的存储。
- Redis水平扩容:单机房Redis实例数最多可支持500个实例。由于Redis是三机房同步,因此存储资源的计算只考虑一个机房的存储上限。
为应对突发情况,我们还特别留足了缓冲资源,以应对Redis的水平扩容较慢的问题。在存储资源不足的情况下,可以通过配置开关提前下掉一些依赖,避免系统因存储压力过大而崩溃。
-
存储资源的预估
我们通过评估历史数据、活动流量和参与人数,确保预估的存储资源足够。在活动之前,通过提前计算,确保存储系统能够处理活动期间的巨大数据量。
5.1.5 压测层面
充分的压测验证是保障活动顺利进行的基础。通过压测,我们能够模拟大流量的场景,并在实际活动开始前发现潜在问题。
-
监控大盘建设
在压测前,我们建立了完整的监控大盘,能够实时监控系统的各项指标,方便在压测过程中发现和解决问题。 -
数据库压测预热
对于MySQL数据库,我们在红包雨等大流量活动前进行小流量压测,提前预热数据库连接池,减少正式活动时大量建链的耗时,从而保障数据库层面的稳定性。 -
压测标识与隔离
在压测过程中,所有流量都带有压测标识,确保压测流量能够与线上流量隔离处理,避免对实际用户业务造成干扰。对于Redis和Abase等缓存系统,我们为压测数据加上特殊的前缀标识,确保数据和线上数据不发生冲突。 -
实时观察和调整
在压测过程中,实时观察计算资源和存储资源是否能够承受预估流量,特别是针对MySQL和Redis,我们确保压测数据与线上数据完全隔离。每次压测后,我们会对存储资源的各项指标进行详细检查,确保系统能够承受高负载。
5.2 微服务思考
微服务架构在日常技术设计中是非常重要的,它帮助我们将系统拆分成多个模块,提高了开发效率和可维护性。但在超大流量场景下,微服务架构可能会带来一些挑战,特别是在链路较长的复杂场景中,计算资源的消耗非常大。
-
SDK代替RPC
本次春节活动中,钱包资产中台提供了SDK包,代替了传统的RPC微服务链路聚合,提供查询余额、判断用户是否获得奖励、强制入账等功能。这种方式显著减少了计算资源的消耗。相较于微服务架构,SDK方式帮助节约了上万核CPU的计算资源,特别适合高流量场景下使用。 -
资源优化与性能提升
使用SDK可以减少RPC调用和网络传输的开销,从而提高系统的整体性能,特别是在大流量场景下,避免了服务间大量的通信和数据传输,极大地提升了系统的响应速度和稳定性。
6. 系统的未来演进方向
在成功实施春节活动后,我们总结了很多经验,并规划了系统未来的发展方向:
-
优化资产中台设计
我们将梳理上下游需求和痛点,进一步优化资产中台的设计,完善基础能力,提升服务架构的灵活性和可扩展性。目标是为活动方提供一站式的服务,减少对接成本,提升活动方接入效率。 -
强实时和离线数据看板
我们计划加大力度建设强实时和离线数据看板能力,以便更加清晰地展示奖励发放数据,帮助运营团队及时监控活动的进展和效果。 -
加强配置化与文档建设
为了减少内部对接的成本和提高外部活动方的接入效率,我们将进一步加强配置化和文档的建设,确保系统能够更加便捷地支持未来更多的活动需求。
通过这些措施,我们将为未来的大规模活动提供更强的支持,提升系统的灵活性、稳定性和可扩展性。
参考文献
非本人技术原创,仅做分享
原文链接:字节技术团队-# 春节钱包大流量奖励系统入账及展示的设计与实现
最后说一句(求关注,求赞,别白嫖我)
最近无意间获得一份阿里大佬写的刷题笔记,一下子打通了我的任督二脉,进大厂原来没那么难。
这是大佬写的 7701页的BAT大佬写的刷题笔记,让我offer拿到手软
本文,已收录于,我的技术网站 cxykk.com:程序员编程资料站,有大厂完整面经,工作技术,架构师成长之路,等经验分享
求一键三连:点赞、分享、收藏
点赞对我真的非常重要!在线求赞,加个关注我会非常感激!
真的免费,如果你近期准备面试跳槽,建议在cxykk.com在线刷题,涵盖 1万+ 道 Java 面试题,几乎覆盖了所有主流技术面试题、简历模板、算法刷题