3.4 抢红包从 2015 年起,微信红包的抢红包和拆红包就分离了 , 用户点击抢红包后需要进行两次操作 。
这也是为什么明明有时候抢到了红包,点开后却发现该红包已经被领取完了 。
![听说你会架构设计?](http://img.jiangsulong.com/231215/1K21JE4-4.jpg)
文章插图
图片
抢红包的交互步骤如下:
- 抢红包:抢操作在 Redis 缓存层完成,通过原子递减的操作来更新红包个数,个数递减为 0 后就说明抢光了 。
- 拆红包:拆红包时,首先会实时计算金额,一般是通过二倍均值法实现(即 0.01 到剩余平均值的 2 倍之间) 。
- 红包记录:用户获取红包金额后,通过数据库的事务操作累加已经领取的个数和金额,并更新红包表和记录表 。
- 转账:为了提升效率 , 最终的转账为异步操作,这也是为什么在春节期间,红包领取后不能立即在余额中看到的原因 。
当用户量过大时,高并发下的事务一致性怎么保证,数据分流如何处理,红包的数额分配又是怎么做的,接下来我们一一探讨 。
4. 详细设计由于是秒杀类设计 , 以及 money 分发,所以我们重点关注抢红包时的高并发解决方案和红包分配算法 。
4.1 高并发解决方案首先,抢红包系统的用户量很大,如果几千万甚至亿万用户同时在线发抢红包,请求直接打到数据库 , 必然会导致后端服务过载甚至崩溃 。
而在这种业务量下,简单地对数据库进行扩容不仅会让成本消耗剧增,另一方面由于存在磁盘的性能瓶颈,所以大概率解决不了问题 。
所以,我们将解决方案集中在 减轻系统压力、提升响应速度 上,接下来会从缓存、加锁、异步分治等方案来探讨可行性 。
1、缓存和大多数秒杀系统设计相似,由于抢红包时并发很高,如果直接操作 DB 里的数据表,可能触发 DB 锁的逻辑,导致响应不及时 。
![听说你会架构设计?](http://img.jiangsulong.com/231215/1K21L431-5.jpg)
文章插图
图片
所以,我们可以在 DB 落盘之前加一层缓存 , 先限制住流量 , 再处理红包订单的数据更新 。
这样做的优点是用缓存操作替代了磁盘操作,提升了并发性能,这在一般的小型秒杀活动中非常有效!
但是,随着微信使用发&抢红包的用户量增多,系统压力增大 , 各种连锁反应产生后,数据一致性的问题逐渐暴露出来:
- 假设库存减少的内存操作成功,但是 DB 持久化失败了,会出现红包少发的问题;
- 如果库存操作失败,DB 持久化成功,又可能会出现红包超发的问题 。
2、加锁在关系型 DB 里,有两种并发控制方法:分为乐观锁(又叫乐观并发控制,Optimistic Concurrency Control , 缩写 “OCC”)和悲观锁(又叫悲观并发,Pessimistic Concurrency Control,缩写“PCC”) 。
![听说你会架构设计?](http://img.jiangsulong.com/231215/1K21M035-6.jpg)
文章插图
图片
悲观锁在操作数据时比较悲观,认为别的事务可能会同时修改数据 , 所以每次操作数据时会先把数据锁住,直到操作完成 。
乐观锁正好相反,这种策略主打一个“信任”的思想,认为事务之间的数据竞争很小,所以在操作数据时不会加锁,直到所有操作都完成到提交时才去检查是否有事务更新(通常是通过版本号来判断) , 如果没有则提交,否则进行回滚 。
在高并发场景下,由于数据操作的请求很多 , 所以乐观锁的吞吐量更大一些 。但是从业务来看,可能会带来一些额外的问题:
- 抢红包时大量用户涌入,但只有一个可以成功,其它的都会失败并给用户报错,导致用户体验极差;
- 抢红包时,如果第一时间有很多用户涌入 , 都失败回滚了 。过一段时间并发减小后,反而让手慢的用户抢到了红包;
推荐阅读
- 聊聊微服务链路服务
- Eureka: 微服务架构中不可或缺的服务治理工具
- 云原生数据库 GaiaDB 架构设计解析:高性能、多级高可用
- 现代软件架构:事件驱动设计遇上事件溯源
- 假如给你一个亿,以下5个“胖妞”必须娶一个,你会选谁呢?
- 从MySQL看主从架构高可用性实现
- 聊聊分布式数据库TDSQL的技术架构
- 利用Apache Kafka、Flink和Druid构建实时数据架构
- 华为Mate 40 Pro现货来了!6099元你会入手吗?
- 深入了解手机芯片:架构与性能的权衡