2个大厂 100亿级 超大流量 红包 架构方案

100亿级 红包 应用 场景

概述

话说每逢双十一节或春节等节假日对大家来讲是最欢乐的日子可以在微信群中收发红包此外今年微信还推出了面对面红包让大家拜年时可直接收发对于用户来讲很爽也很方便。但对于技术架构侧的考量这使得微信红包的收发数据成几何倍数上升处理的复杂度也增加了很多。

2017年微信红包发送量最大的时间段是除夕夜达到了142亿个。

如此大规模、高并发、高峰值的业务场景怕是在美帝互联网的技术团队包括EBay、Amazon等也无法想象在这种巨大的流量与并发后面需要什么样级别的技术架构支撑

当达百亿级别的资金交易规模时我们该怎样来保证系统的并发性能和交易安全

当今中国的互联网平台有两个场景称得上亿级以上的并发量

一个是微信的红包

一个是字节的红包

都是在一个单位时间达到亿万以以上的请求负载。

百亿级 微信红包技术架构

与传统意义上的红包相比近两年火起来的“红包”似乎才是如今春节的一大重头戏。历经上千年时代传承与变迁春节发红包早已成为历史沉淀的文化习俗融入了民族的血脉。按照各家公布的数据除夕全天微信用户红包总发送量达到80.8亿个红包峰值收发量为40.9万个/秒。春晚直播期间讨论春晚的微博达到5191万条网友互动量达到1.15亿网友抢微博红包的总次数超过8亿次。

微信红包在经过15年春晚摇一摇之后2015年上半年业务量一度呈指数级增长。尤其是微信红包活跃用户数的大量增长使得2016除夕跨年红包成为极大挑战。为了应对16年春节可预知的红包海量业务红包系统在架构上进行了一系列调整和优化。主要包括异地架构、cache系统优化、拆红包并发策略优化、存储优化一系列措施为迎接2016春节红包挑战做好准备。 下面介绍最主要的一些思路。

架构

微信用户在国内有深圳、上海两个接入点习惯性称之为南、北即深圳为南上海为北。用户请求接入后不同业务根据业务特性选择部署方式。微信红包在信息流上可以分为订单纬度与用户纬度。

其中订单是贯穿红包发、抢、拆、详情列表等业务的关键信息属于交易类信息而用户纬度指的是红包用户的收红包列表、发红包列表属于展示类信息。红包系统在架构上有以下几个方面

南北分布

1、订单层南北独立体系数据不同步

用户就近接入请求发红包时分配订单南北并在单号打上南北标识。抢红包、拆红包、查红包详情列表时接入层根据红包单号上的南北标识将流量分别引到南北系统闭环。根据发红包用户和抢红包用户的所属地不同有以下四种情况

1深圳用户发红包深圳用户抢

订单落在深圳深圳用户抢红包时不需要跨城在深圳完成闭环。

2深圳用户发红包上海用户抢

订单落在深圳上海用户抢红包在上海接入后通过专线跨城到深圳最后在深圳闭环完成抢红包。

3上海用户发红包上海用户抢

订单落在上海上海用户抢红包时不需要跨城在上海完成闭环。

4上海用户发红包深圳用户抢

订单落在上海深圳用户抢红包从深圳接入后通过专线跨城到上海最后在上海闭环完成抢红包。

系统这样设计好处是南北系统分摊流量降低系统风险。

2、用户数据写多读少全量存深圳异步队列写入查时一边跨城

用户数据的查询入口在微信钱包中隐藏的很深。这决定了用户数据的访问量不会太大而且也被视为可旁路的非关键信息实时性要求不高。因此只需要在发红包、拆红包时从订单纬度拆分出用户数据写入请求由MQ异步写入深圳。后台将订单与用户进行定时对账保证数据完整性即可。

3、支持南北流量灵活调控

红包系统南北分布后订单落地到深圳还是上海是可以灵活分配的只需要在接入层上做逻辑。例如可以在接入层中实现让所有红包请求都落地到深圳无论用户从上海接入还是深圳接入这样上海的红包业务系统将不会有请求量。提升了红包系统的容灾能力。同时实现了接入层上的后台管理系统实现了秒级容量调控能力。可根据南北请求量的实时监控做出对应的调配。

4、DB故障时流量转移能力 基于南北流量的调控能力当发现DB故障时可将红包业务流量调到另外一边实现DB故障的容灾。

预订单

支付前订单落cache同时利用cache的原子incr操作顺序生成红包订单号。优点是cache的轻量操作以及减少DB废单。在用户请求发红包与真正支付之间存在一定的转化率部分用户请求发红包后并不会真正去付款。

拆红包入账异步化

信息流与资金流分离。

拆红包时DB中记下拆红包凭证然后异步队列请求入账。

入账失败通过补偿队列补偿最终通过红包凭证与用户账户入账流水对账保证最终一致性。如下图所示

这个架构设计理论基础是快慢分离。

红包的入账是一个分布事务属于慢接口。

而拆红包凭证落地则速度快。

实际应用场景中用户抢完红包只关心详情列表中谁是“最佳手气”很少关心抢到的零是否已经到账。

因为只需要展示用户的拆红包凭证即可。

发拆落地其他操作双层cache

1、Cache住所有查询两层cache

除了使用ckv做全量缓存还在数据访问层dao中增加本机内存cache做二级缓存cache住所有读请求。

查询失败或者查询不存在时降级内存cache内存cache查询失败或记录不存在时降级DB。

DB本身不做读写分离。

2、DB写同步cache容忍少量不一致 DB写操作完成后dao中同步内存cache业务服务层同步ckv失败由异步队列补偿

定时的ckv与DB备机对账保证最终数据一致。

高并发

微信红包的并发挑战主要在于微信大群多人同时抢同一个红包。

以上这种情况存在竞争MySQL行锁。为了控制这种并发团队做了以下一些事情

1、请求按红包订单路由逻辑块垂直sticky事务隔离

按红包订单划分逻辑单元单元内业务闭环。服务rpc调用时使用红包订单号的hash值为key寻找下一跳地址。对同一个红包的所有拆请求、查询请求都路由到同一台逻辑机器、同一台DB中处理。

2、Dao搭建本机Memcache内存cache控制同一红包并发个数

在DB的接入机dao中搭建本机内存cache。以红包订单号为key对同一个红包的拆请求做原子计数控制同一时刻能进DB中拆红包的并发请求数。

这个策略的实施依赖于请求路由按红包订单hash值走确保同一红包的所有请求路由到同一逻辑层机器。

3、多层级并发量控制

1发红包控制

发红包是业务流程的入口控制了这里的并发量代表着控制了红包业务整体的并发量。在发红包的业务链路里做了多层的流量控制确保产生的有效红包量级在可控范围。

2抢红包控制

微信红包领取时分为两个步骤抢和拆。

抢红包这个动作本身就有控制拆并发的作用。因为抢红包时只需要查cache中的数据不需要请求DB。

对于红包已经领完、用户已经领过、红包已经过期等流量可以直接拦截。而对于有资格进入拆红包的请求量也做流量控制。通过这些处理最后可进入拆环节的流量大大减少并且都是有效请求。

3拆时内存cache控制

针对同一个红包并发拆的控制上面的文章已介绍。

4、DB简化和拆分

DB的并发能力有很多影响因素。红包系统结合红包使用情境进行了一些优化。比较有借鉴意义的主要有以下两点

1订单表只存关键字段其他字段只在cache中存储可柔性。

红包详情的展示中除了订单关键信息用户、单号、金额、时间、状态外还有用户头像、昵称、祝福语等字段。这些字段对交易来说不是关键信息却占据大量的存储空间。

将这些非关键信息拆出来只存在cache用户查询展示而订单中不落地。

这样可以维持订单的轻量高效同时cache不命中时又可从实时接口中查询补偿达到优化订单DB容量的效果。

2DB双重纬度分库表冷热分离

使用订单hash、订单日期两个纬度分库表也即db_xxx.t_x_dd这样的格式。

其中x表示订单hash值dd表示01-31循环日。

订单hash纬度是为了将订单打散到不同的DB服务器中均衡压力。

订单日期循环日纬度是为了避免单表数据无限扩张使每天都是一张空表。

另外红包的订单访问热度是非常典型的冷热型。

热数据集中在一两天内且随时间急剧消减。

线上热数据库只需要存几天的数据其他数据可以定时移到成本低的冷数据库中。

循环日表也使得历史数据的迁移变得方便。

红包算法

首先如果红包只有一个本轮直接使用全部金额确保红包发完。

然后计算出本轮红包最少要领取多少才能保证红包领完即本轮下水位轮最多领取多少才能保证每个人都领到即本轮上水位。主要方式如下

计算本轮红包金额下水位假设本轮领到最小值1分那接下来每次都领到200元红包能领完那下水位为1分如果不能领完那按接下来每次都领200元剩下的本轮应全部领走是本轮的下水位。

计算本轮红包上水位假设本轮领200元剩下的钱还足够接下来每轮领1分钱那本轮上水位为200元如果已经不够领那按接下来每轮领1分计算本轮的上水位。

为了使红包金额不要太悬殊使用红包均值调整上水位。如果上水位金额大于两倍红包均值那么使用两倍红包均值作为上水位。换句话说每一轮抢到的红包金额最高为两倍剩下红包的均值。

最后获取随机数并用上水位取余如果结果比下水位还小则直接使用下水位否则使用随机金额为本轮拆到金额。

柔性降级方案

系统到处存在发生异常的可能需要对所有的环节做好应对的预案。

下面列举微信红包对系统异常的主要降级考虑。

1、 下单cache故障降级DB

下单cache有两个作用生成红包订单与订单缓存。

缓存故障情况下降级为直接落地DB并使用id生成器独立生成订单号。

2、 抢时cache故障降级DB

抢红包时查询cache拦截红包已经抢完、用户已经抢过、红包已经过期等无效请求。当cache故障时降级DB查询同时打开DB限流保护开关防止DB压力过大导致服务不可用。

另外cache故障降级DB时DB不存储用户头像、用户昵称等上文提到的优化此时一并降级为实时接口查询。查询失败继续降级为展示默认头像与昵称。

3、 拆时资金入账多级柔性

拆红包时DB记录拆红包单据然后执行资金转账。单据需要实时落地而资金转账这里做了多个层级的柔性降级方案

大额红包实时转账小额红包入队列异步转账 所有红包进队列异步转账 实时流程不执行转账事后凭单据批量入账。

总之单据落地后真实入账可实时、可异步最终保证一致即可。

4、 用户列表降级

用户列表数据在微信红包系统中属于非关键路径信息属于可被降级部分。

首先写入时通过MQ异步写通过定时对账保证一致性。

其次cache中只缓存两屏用户查询超过两屏则查用户列表DB。在系统压力大的情况下可以限制用户只查两屏。

调整后的系统经过了2016年春节的实践检验平稳地度过了除夕业务高峰保障了红包用户的体验。

上文参考来源架构说公众号作者方乐明

方乐明2011年毕业于华南理工大学通信与信息系统专业毕业后就职于财付通科技有限公司。微信支付团队组建后主要负责微信红包、微信转账、AA收款等支付应用产品的后台架构。

360w QPS 100亿级 字节红包 体系架构

1. 背景&挑战&目标

1.1 业务背景

1支持八端

2022 年字节系产品春节活动需要支持八端 APP 产品包含抖音/抖音火山/抖音极速版/西瓜/头条/头条极速版/番茄小说/番茄畅听的奖励互通。用户在上述任意一端都可以参与活动得到的奖励在其他端都可以提现与使用。

2玩法多变

主要有集卡、朋友页红包雨、红包雨、集卡开奖与烟火大会等。

3多种奖励

奖励类型包含现金红包、补贴视频红包、商业化广告券、电商券、支付券、消费金融券、保险券、信用卡优惠券、喜茶券、电影票券、dou+券、抖音文创券、头像挂件等。

1.2 核心挑战

1超高吞吐超大并发最高预估 360w QPS 发奖。

2奖励类型多共 10 余种奖励。多种发奖励的场景玩法多变

3从奖励系统稳定性、用户体验、资金安全与运营基础能力全方位保障确保活动顺利进行 。

1.3 最终目标

1奖励入账数据高可靠。提供统一的错误处理机制入账幂等能力和奖励预算控制。

2**奖励展示/使用**支持用户查看、提现现金使用卡券/挂件等能力。

3稳定性保障在大流量的入账场景下保证钱包核心路径稳定性与完善通过常用稳定性保障手段如资源扩容、限流、熔断、降级、兜底、资源隔离等方式保证用户奖励方向的核心体验。

4资金安全通过幂等、对账、监控与报警等机制保证资金安全保证用户资产应发尽发不少发。

5活动隔离实现内部测试、灰度放量和正式春节活动三个阶段的奖励入账与展示的数据隔离不互相影响。

2. 产品需求介绍

用户可以在任意一端参与字节的春节活动获取奖励以抖音红包雨现金红包入账场景为例具体的业务流程如下

登录抖音 → 参与活动 → 活动钱包页 → 点击提现按钮 → 进入提现页面 → 进行提现 → 提现结果页

另外从钱包页也可以进入活动钱包页。

奖励发放核心场景

  1. 集卡集卡抽卡时发放各类卡券集卡锦鲤还会发放大额现金红包集卡开奖时发放瓜分奖金和优惠券
  2. 红包雨发红包、卡券以及视频补贴红包其中红包和卡券最高分别 180w QPS

3. 钱包资产中台设计与实现

在 2022 年春节活动中业务方分为

UG、激励中台、视频红包、钱包方向、资产中台等

其中UG 主要负责活动的玩法实现包含集卡、红包雨以及烟火大会等具体的活动相关业务逻辑和稳定性保障。

而钱包方向定位是大流量场景下实现奖励入账、奖励展示、奖励使用与资金安全保障的相关任务。

其中资产中台负责奖励发放与奖励展示部分。

3.1 春节资产资产中台总体架构图如下

钱包资产中台核心系统划分如下

  1. 资产订单层

    收敛八端奖励入账链路

    提供统一的接口协议对接上游活动业务方的奖励发放功能

    同时支持预算控制、补偿、订单号幂等。

  2. 活动钱包 api 层

    统一奖励展示链路同时支持大流量场景

3.2 资产订单中心设计

核心发放模型

说明

活动 ID 唯一区分一个活动

本次春节分配了一个单独的母活动 ID

场景 ID 和具体的一种奖励类型一一对应

定义该场景下发奖励的唯一配置

场景 ID 可以配置的能力有

  • 发奖励账单文案
  • 是否需要补偿
  • 限流配置
  • 是否进行库存控制
  • 是否要进行对账。
  • 提供可插拔的能力供业务可选接入。

订单号设计

资产订单层支持订单号维度的发奖幂等订单号设计逻辑为

${actID}_${scene_id}_${rain_id}_${award_type}_${statge}

从单号设计层面保证不超发每个场景的奖励用户最多只领一次。

4. 核心难点问题解决

4.1 难点一支持八端奖励数据互通

有八个产品端需要统一对接

其中抖音系和头条系 APP 是不同的账号体系所以不能通过用户 ID 打通奖励互通。

具体解决方案是

  • 给每个用户生成唯一的 actID
  • 手机号优先级最高如果不同端登录的手机号一样在不同端的 actID 是一致的。

在唯一 actID 基础上每个用户的奖励数据是绑定在 actID 上的入账和查询是通过 actID 维度实现的即可实现八端奖励互通。

示意图如下

4.2 难点二高场景下的奖励入账实现

超高并发场景发现金红包都是最关键的一环。有几个原因如下

  1. 预估发现金红包最大流量有 180w TPS。
  2. 现金红包本身价值高需要保证资金安全。
  3. 用户对现金的敏感度很高在保证用户体验与功能完整性同时也要考虑成本问题。

终上所述发现金红包面临比较大的技术挑战。

发红包其实是一种交易行为资金流走向是从公司成本出然后进入个人账户。

1从技术方案上是要支持订单号维度的幂等同一订单号多次请求只入账一次。订单号生成逻辑为

${actID}_${scene_id}_${rain_id}_${award_type}_${statge}

从单号设计层面保证不超发。

2支持高并发有以下 2 个传统方案

具体方案类型实现思路优点缺点
同步入账申请和预估流量相同的计算和存储资源1.开发简单 2.不容易出错浪费存储成本。 拿账户数据库举例经实际压测结果支持 30w 发红包需要 152 个数据库实例如果支持 180w 发红包至少需要 1152 个数据库实例还没有算上 tce 和 redis 等其他计算和存储资源。
异步入账申请部分计算和存储资源资源实际入账能力与预估有一定差值1.开发简单 2.不容易出错 3.不浪费资源用户体验受到很大影响。 入账延迟较大以今年活动举例会有十几分钟延迟。用户参与玩法得到奖励后在活动钱包页看不到奖励也无法进行提现会有大量客诉影响抖音活动的效果。

以上两种传统意义上的技术方案都有明显的缺点

那么进行思考既能相对节约资源又能保证用户体验的方案是什么

最终采用的是红包雨 token 方案具体方案是

使用异步入账加较少量分布式存储和较复杂方案来实现

下面具体介绍一下。

4.2.1 红包雨 token 方案

根据预估发放红包估算红包雨 token 方案, 计算实际入账最低要支持的 TPS 为 30w所以实际发放中有压单的过程。

设计目标

在活动预估给用户发放180w与实际入账30w有很大 gap 的情况下保证用户的核心体验。

用户在前端页面查看与使用过当中不能感知压单的过程即查看与使用体验不能受到影响相关展示的数据包含余额累计收入与红包流水使用包含提现等。

具体设计方案

我们在大流量场景下每次给用户发红包会生成一个加密 token使用非对称加密包含发红包的元信息红包金额actID与发放时间等

分别存储在客户端和服务端容灾互备每个用户有个 token 列表。

每次发红包的时候会在 Redis 里记录该 token 的入账状态

然后用户在活动钱包页看到的现金红包流水、余额等数据是合并已入账红包列表+token 列表-已入账/入账中 token 列表的结果。

同时为保证用户提现体验不感知红包压单流程

在进入提现页或者点击提现时将未入账的 token 列表进行强制入账

保证用户提现时账户的余额为应入账总金额不 block 用户提现流程。

示意图如下

token 数据结构

token 使用的是 protobuf 格式

经单测验证存储消耗实际比使用 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 安全性保障

采用非对称加密算法保障存储在的客户端尽可能不被破解。

如果 token 加密算法被黑产破译可监控报警发现可降级。

4.3 难点三发奖励链路依赖多的稳定性保障

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

根据历史经验实现的功能越复杂依赖会变多对应的稳定性风险就越高那么如何保证高依赖的系统稳定性呢

解决方案

现金红包入账最基础要保障的功能

是将用户得到的红包进行入账

核心的功能需要支持幂等与预算控制避免超发

红包账户的幂等设计强依赖数据库保持事务一致性。

但是如果极端情况发生中间的链路可能会出现问题如果是弱依赖需要支持降级掉不影响发放主流程。

钱包方向发红包最短路径为依赖服务实例计算资源和 MySQL 存储资源实现现金红包入账。

发红包强弱依赖梳理图示

psm依赖服务是否强依赖降级方案降级后影响
资产中台tcc降级读本地缓存
bytkekv主动降级开关跳过 bytekv依赖下游做幂等
资金交易层分布式锁 Redis被动降级调用失败直接跳过基本无
token Redis主动降级开关不调用 Redis用户能感知到入账有延迟会有很多客诉
MySQL主有问题联系 dba 切主故障期间发红包不可用

4.4 难点四大流量发卡券预算控制

大流量集中发券的一个场景钱包侧与算法策略配合进行卡券发放库存控制防止超发。

具体实现

1钱包资产中台维护每个卡券模板 ID 的消耗发放量。

2每次卡券发放前读取该卡券模板 ID 的消耗量以及总库存数。同时会设置一个阈值如果卡券剩余量小于 10%后不发这个券使用兜底券或者祝福语进行兜底。

3 发券流程 累计每个券模板 ID 的消耗量使用 Redis incr 命令原子累加消耗量然后与总活动库存进行比对如果消耗量大于总库存数则拒绝掉防止超发也是一个兜底流程。

具体流程图

优化方向

1大流量下使用 Redis 计数单 key 会存在热 key 问题需要拆分 key 来解决。

2大流量场景下操作 Redis 会存在超时问题返回上游处理中上游继续重试发券会多消耗库存少发本次春节活动实际活动库存在预估库存基础上加了 5%的量级来缓解超时带来的少发问题。

4.5 难点五高 QPS 场景下的热 key 的读取和写入稳定性保障

最大流量预估读取有 180wQPS写入 30wQPS。

这是典型的超大流量热点 key、更新延迟不敏感非数据强一致性场景数字是一直累加

同时要做好容灾降级处理最后实际活动展示的金额与产品预计发放数值误差小于 1%。

4.5.1 方案一

高 QPS 下的读取和写入单 key比较容易想到的是使用 Redis 分布式缓存来进行实现但是单 key 读取和写入的会打到一个实例上压测过单实例的瓶颈为 3w QPS。

所以做的一个优化是拆分多个 key然后用本地缓存兜底。

具体写入流程

设计拆分 100 个 key每次发红包根据请求的 actID%100 使用 incr 命令累加该数字因为不能保证幂等性所以超时不重试。

读取流程

与写入流程类似优先读取本地缓存

如果本地缓存值为为 0那么去读取各个 Redis 的 key 值累加到一起进行返回。

问题

1拆分 100 个 key 会出现读扩散的问题需要申请较多 Redis 资源存储成本比较高。

而且可能存在读取超时问题不能保证一次读取所有 key 都读取成功故返回的结果可能会较上一次有减少。

2容灾方案方面如果申请备份 Redis也需要较多的存储资源需要的额外存储成本。

4.5.2 方案二

设计思路

在方案一实现的基础上进行优化

在写场景通过本地缓存进行合并写请求进行原子性累加

读场景返回本地缓存的值减少额外的存储资源占用。

使用 Redis 实现中心化存储最终大家读到的值都是一样的。

具体设计方案

每个 docker 实例启动时都会执行定时任务分为读 Redis 任务和写 Redis 任务。

读取流程

  1. 本地的定时任务每秒执行一次

    读取 Redis 单 key 的值如果获取到的值大于本地缓存那么更新本地缓存的值。

  2. 对外暴露的 sdk 直接返回本地缓存的值即可。

  3. 有个问题需要注意下每次实例启动第一秒内是没有数据的所以会阻塞读等有数据再返回。

写入流程

  1. 因为读取都是读取本地缓存本地缓存不过期所以处理好并发情况下的写即可。

  2. 本地缓存写变量使用 go 的 atomic.AddInt64 支持原子性累加本地写缓存的值。

  3. 每次执行更新 Redis 的定时任务

    先将本地写缓存复制到 amount 变量最后将 amount 的值 incr 到 Redis 单 key 上实现 Redis 的单 key 的值一直累加。

  4. 容灾方案是使用备份 Redis 集群写入时进行双写

    一旦主机群挂掉设计了一个配置开关支持读取备份 Redis。两个 Redis 集群的数据一致性通过定时任务兜底实现。

具体写入流程图如下

本方案调用 Redis 的流量是跟实例数成正比

经调研读取侧的服务为主会场实例数 2 万个写入侧服务为资产中台实例数 8 千个

所以实际 Redis 要支持的 QPS 为 2.8 万/定时任务执行间隔单位为 s

经压测验证 Redis 单实例可以支持单 key2 万 get8k incr 的操作

所以设置定时任务的执行时间间隔是 1s如果实例数更多可以考虑延长执行时间间隔。

4.5.3 方案对比
优点缺点
方案一1. 实现成本简单1. 浪费存储资源 2. 难以做容灾 3. 不能做到一直累加
方案二1. 节约资源 2. 容灾方案比较简单同时也节约资源成本1. 实现稍复杂需要考虑好并发原子性累加问题

结论

从实现效果资源成本和容灾等方面考虑最终选择了方案二上线。

4.6 难点六大流量场景下资金安全保障

钱包方向在本次春节活动期间做了三件事情来保障大流量大预算的现金红包发放的资金安全

  1. 现金红包发放整体预算控制的拦截
  2. 单笔现金红包发放金额上限的拦截
  3. 大流量发红包场景的资金对账
  • 小时级别对账支持红包雨/集卡/烟火红包发放 h+1 小时级对账并针对部分场景设置兜底 h+2 核对。
  • 准实时对账红包雨已入账的红包数据反查钱包资产中台和活动侧做准实时对账

多维度核对示意图

准实时对账流程图

说明

准实时对账监控和报警可以及时发现是否异常入账情况如果报警发现会有紧急预案处理。

5. 通用模式抽象

在经历过春节超大流量活动后的设计与实现后有一些总结和经验与大家一起分享一下。

5.1 容灾降级层面

大流量场景为了保证活动最终上线效果容灾是一定要做好的。

参考业界通用实现方案如降级、限流、熔断、资源隔离根据预估活动参与人数和效果进行使用存储预估等。

5.1.1 限流层面

1限流方面应用了 api 层 nginx 入流量限流分布式入流量限流分布式出流量限流。

这几个限流器都是字节跳动公司层面公共的中间件经过大流量的验证。

2首先进行了实际单实例压测根据单实例扛住的流量与本次春节活动预估流量打到该服务的流量进行扩容并结合下游能抗住的情况

在 tlb 入流量、入流量限流以及出流量限流分别做好了详细完整的配置并同。

限流目标

保证自身服务稳定性防止外部预期外流量把本身服务打垮防止造成雪崩效应保证核心业务和用户核心体验。

简单集群限流是实例维度的限流

每个实例限流的 QPS=总配置限流 QPS/实例数

对于多机器低 QPS 可能会有不准的情况要经过实际压测并且及时调整配置值。

对于分布式入流量和出流量限流两种使用方式如下每种方式都支持高低 QPS区别只是 SDK 使用方式和功能不同。

一般低 QPS 精度要求高采用 redis 计数方式使用方提供自己的 redis 集群。

高 QPS 精度要求低退化为总 QPS/tce 实例数的单实例限流。

5.1.2 降级层面

对于高流量场景每个核心功能都要有对应的降级方案来保证突发情况核心链路的稳定性。

1本次春节奖励入账与活动活动钱包页方向做好了充分的操作预案一共有 26 个降级开关关键时刻弃车保帅防止有单点问题影响核心链路。

2以发现金红包链路举例钱包方向最后完全降级的方案是只依赖 docker 和 MySQL其他依赖都是可以降级掉的MySQL 主有问题可以紧急联系切主虽说最后一个都没用上但是前提要设计好保证活动的万无一失。

5.1.3 资源隔离层面

1提升开发效率不重复造轮子

因为钱包资产中台也日常支持抖音资产发放的需求本次春节活动也复用了现有的接口和代码流程支持发奖。

2同时针对本次春节活动服务层面做了集群隔离

创建专用活动集群底层存储资源隔离活动流量和常规流量互不影响。

5.1.4 存储预估

1不但要考虑和验证了 Redis 或者 MySQL 存储能抗住对应的流量同时也要按照实际的获取参与和发放数据等预估存储资源是否足够。

2对于字节跳动公司的 Redis 组件来讲

可以进行垂直扩容每个实例增加存储最大 10G也可以进行水平扩容单机房上限是 500 个实例因为 Redis 是三机房同步的所以计算存储时只考虑一个机房的存储上限即可。

要留足 buffer因为水平扩容是很慢的一个过程突发情况遇到存储资源不足只能通过配置开关提前下掉依赖存储需要提前设计好。

5.1.5 压测层面

本次春节活动钱包奖励入账和活动钱包页做了充分的全链路压测验证下面是一些经验总结。

  1. 在压测前要建立好压测整条链路的监控大盘在压测过程当中及时和方便的发现问题。
  2. 对于 MySQL 数据库在红包雨等大流量正式活动开始前进行小流量压测预热数据库峰值流量前提前建链减少正式活动时的大量建链耗时保证发红包链路数据库层面的稳定性。
  3. 压测过程当中一定要传压测标支持全链路识别压测流量做特殊逻辑处理与线上正常业务互不干扰。
  4. 针对压测流量不做特殊处理压测流量处理流程保持和线上流量一致。
  5. 压测中要验证计算资源与存储资源是否能抗住预估流量
  • 梳理好压测计划基于历史经验设置合理初始流量渐进提升压测流量实时观察各项压测指标。
  • 存储资源压测数据要与线上数据隔离对于 MySQL 和 Bytekv 这种来讲是建压测表对于 Redis 和 Abase 这种来讲是压测 key 在线上 key 基础加一下压测前缀标识 。
  • 压测数据要及时清理Redis 和 Abase 这种加短时间的过期时间过期机制处理比较方便如果忘记设置过期时间可以根据写脚本识别压测标前缀去删除。
  1. 压测后也要关注存储资源各项指标是否符合预期。

5.2 微服务思考

在日常技术设计中大家都会遵守微服务设计原则和规范根据系统职责和核心数据模型拆分不同模块提升开发迭代效率并不互相影响。

但是微服务也有它的弊端对于超大流量的场景功能也比较复杂会经过多个链路这样是极其消耗计算资源的。

本次春节活动资产中台提供了 sdk 包代替 rpc 进行微服务链路聚合对外提供基础能力如查询余额、判断用户是否获取过奖励强制入账等功能。访问流量最高上千万与使用微服务架构对比节约了上万核 CPU 的计算资源。

6. 系统的未来演进方向

1梳理上下游需求和痛点优化资产中台设计实现完善基础能力优化服务架构提供一站式服务让接入活动方可以更专注进行活动业务逻辑的研发工作。

2加强实时和离线数据看板能力建设让奖励发放数据展示的更清晰更准确。

3加强配置化和文档建设对内减少对接活动的对接成本对外提升活动业务方接入效率。

上文参考来源字节跳动技术团队春节钱包大流量奖励系统入账及展示的设计与实现

推荐阅读

Docker面试题史上最全 + 持续更新
场景题假设10W人突访你的系统如何做到不 雪崩
尼恩Java面试宝典
Springcloud gateway 底层原理、核心实战 (史上最全)
Flux、Mono、Reactor 实战史上最全
sentinel 史上最全
Nacos (史上最全)
分库分表 Sharding-JDBC 底层原理、核心实战史上最全
TCP协议详解 (史上最全)
clickhouse 超底层原理 + 高可用实操 史上最全
nacos高可用图解+秒懂+史上最全
队列之王 Disruptor 原理、架构、源码 一文穿透
环形队列、 条带环形队列 Striped-RingBuffer 史上最全
一文搞定SpringBoot、SLF4j、Log4j、Logback、Netty之间混乱关系史上最全
单例模式史上最全
红黑树 图解 + 秒懂 + 史上最全
分布式事务 秒懂
缓存之王Caffeine 源码、架构、原理史上最全10W字 超级长文
缓存之王Caffeine 的使用史上最全
Java Agent 探针、字节码增强 ByteBuddy史上最全
Docker原理图解+秒懂+史上最全
Redis分布式锁图解 - 秒懂 - 史上最全
Zookeeper 分布式锁 - 图解 - 秒懂
Zookeeper Curator 事件监听 - 10分钟看懂
Netty 粘包 拆包 | 史上最全解读
Netty 100万级高并发服务器配置
Springcloud 高并发 配置 一文全懂

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

“2个大厂 100亿级 超大流量 红包 架构方案” 的相关文章