欢迎来到啾啾的博客🐱。
记录学习点滴。分享工作思考和实用技巧,偶尔也分享一些杂谈💬。
有很多很多不足的地方,欢迎评论交流,感谢您的阅读和评论😄。
step 1:需求分析
假设春晚有企业向全国观众发送10亿红包。每个红包被抢10次,即100亿QPS。
step 2:确认边界与大致架构
这个场景可以使用5So反推边界。 因为是10亿红包雨,所以单体难以支撑,所以是分布式架构,所以要考虑CAP。 因为是红包,涉及金额,所以要考虑安全性。
step 3:详细设计
首先,详细设计,设计底层核心逻辑。
设计常规的红包操作
一个红包从发送到领取需要有哪些事务操作?
其中,发红包是一个简单操作,红包要保障能长时间存在(一天),需要持久化保障:
发送红包成功=发送方扣除DB余额+DB增加红包
抢红包则是一个线程安全的原子操作: 获取红包 = 获取红包余额+计算红包额度+扣减红包余额 抢红包(原子操作)= 获取红包+增加余额 在抢红包时,操作需要满足数据的多线程安全。
- 计算红包+扣减红包余额操作
考虑并发操作
常规设计对DB操作压力大,在红包雨场景下肯定无法保障红包雨抢红包的实时、高效。 因此,我们首先考虑减少DB压力。
-
减少红包DB操作 红包雨特性为时间短。因此,在发送红包成功后(入DB),每次抢红包扣减红包额度的操作都不进行DB操作。 而是在内存中操作完成,红包雨时间结束后再行操作DB。
-
缓冲用户DB操作 10亿红包意味着10亿余额写请求,DB压力大,实时性差。 所以使用消息队列做异步处理+保障可靠性,起到缓冲用户DB操作的效果。
-
预计算 每次获取红包余额然后计算红包的方法会有一些资源消耗。 在内存中计算会快一些,但还是需要加锁扣减。 在高并发场景在可以通过预计算来避免,不再实时计算红包大小。
预计算详细方案
-
算个10亿红包(全部预计算) 预计算10亿红包,为每个红包设立token(或者金额+唯一id),讲这些token存入高速、可以并发访问的存储中,如Redis。 用户抢红包时从Redis红包池获取红包。
-
分段预计算+实时计算少量随机性(部分预计算) 不将所有小红包完全预拆分,而是将总红包金额和总数量加载到 Redis 中。使用lua脚本进行分段计算。
-
中奖令牌+异步发放金额 预先生成“中奖令牌”存入Redis,抢红包时=抢令牌,然后拿着令牌异步计算红包金额。
预计算需要用Redis集群分散红包池,且需要负载均衡策略讲服务器请求分散到不同实例。用Redis了也可以多加一级本地缓存,每个应用实例缓存部分到本地,形成多级缓存。 不过多级缓存需要考虑本地缓存丢失情况,设计更复杂一些。
考虑可靠性与可用性
在解决了功能性问题后,我们需要考虑系统的可靠性。 100亿QPS瞬时压力多半超出系统处理能力。
网关限流与负载均衡
在网关对用户身份做校验与行为检测,对异常流量进行限制,,防机器人干扰用户抢红包。 同时做好路由,均衡负载请求压力。
柔性处理异常
服务异常情况做服务降级、快速响应,并设计服务集群熔断保护等。
幂等性设计
一个红包只有一份钱,这很好理解。多次点击一个红包结果应当是一样的。
数据一致性与对账对账
红包雨结束后的数据对账是非常重要的。所以需求每次红包记录,略...
考虑用户体验
公平设计
如果用户一直没有抢到红包肯定不好。要设计兜底机制,比如分出一批红包,专为手气差的用户准备。
step 4:架构设计
核心架构设计如下: