红包系统的一些思考

对红包系统的一些个人想法,有问题欢迎补充交流

一个抢红包系统如何实现?

正常流程:
发红包-> 抢红包 -> 拆红包

发红包:逻辑简单,创建一个红包,无高并发的情形。
抢红包:逻辑复杂,高并发更新情形。复杂点:高并发情况下,剩余红包数量如何原子性的维护? 高并发情况下,红包数据如何落盘?接口性能如何保证?
拆红包:查询抢到红包的金额,高并发查询,并不复杂。

抢红包特点:

1 并发请求高。(红包场景的特点-->并发抢)
2 系统安全性要求高。(不能出现钱金额超发,红包数量超发的情况)

并发请求高:

  1. 硬件上不提
  2. 接口性能上,使用内存操作替代实时的DB事务操作,另外请求内部尽量避免锁抢占操作。

主要流程可以如下所示:
红包系统的一些思考_第1张图片

设计想法:
高并发请求,该接口设计一定要轻量。抢红包阶段,只需要明确是否抢到红包,红包金额等在该接口不涉及。用户抢到红包最重要的前提有三个。

a. 根据缓存判断是否存在库存 
b. 缓存中库存数量自减成功 
c. 发送异步mq消息成功

正常逻辑只会请求redis以及发送一个mq,十分轻量。

接口的稳定性强依赖mq的稳定性; 原因是redis挂掉的情况下,其实可以走正常sql落盘数据库的方式,只更新库存数量即可(这里又并发强锁的问题,比较耗时)。

计算红包大小,以及插入抢红包记录,更新红包记录放在异步操作,原因是这样的操作比较重,如果放在同步里面,在高并发情况下,增加了服务异常的概率。放在mq的好处,最重要的是可以以固定速率消费,避免了高并发的场景。如果出现队列中消息过多的情况。 只有两个原因:1. 消费机器数目过少。 2. 存储数据库更新操作出现瓶颈。 对于第一个,暴力简单,增加消费机器的数量。 第二个来说比较麻烦,底层数据分库分表,增加更新查询速率。

问题:发送mq失败怎么办?

  1. 重试
  2. 缓存自增,返回失败

问题:返回成功后,服务宕机怎么办?

已经发送mq成功,这里需要mq来保证,在宕机情况下,消息也不会丢失。 另外就算mq不能恢复,也可以根据发送mq成功的日志进行后续的补偿逻辑,也不会造成多发的情况。

问题:存在这样的场景,读取到红包剩余N个,然后这里按照抢到红包的操作,将红包数量更新到N-1个,在读取和更新期间,其他请求对库存发生了更新操作怎么办?即将红包数量更新到N-1的时候,库存已经是N-1了,这里会出现少减的情况。

方案一:

redis的watch命令。通过redis的watch命令,可以知道更新这个数字的时候,这个数字有没有被改过。

红包系统的一些思考_第2张图片

这样设计有个缺点就是红包数量比较多,另外同时多人抢红包情况下,会出现多次如下的循环 (如何避免这种情况?) 思考了一下,其实多次这样循环对性能影响不大,而且理论上不会出现多次循环,最多可能两三次。

红包系统的一些思考_第3张图片

方案二

通过sql语句, 更新库存将库存作为条件放入where后

update table set N=N-1 where N=N

依旧避免不了出现多次 获取红包数量 <-> 更新失败 的循环。

如有其他内容,欢迎补充~

你可能感兴趣的:(设计思想)