当前位置:   article > 正文

关于抢红包设计的几个思考_红包内存队列

红包内存队列

 

关于抢红包设计的几个思考


工作中遇到一个关于直播间用户给直播间发红包,以及当前直播间观众领取该红包的项目需求

对于发红包  >>>>>> 抢红包 这中间的有几点关键的点
1、对于直播间发送红包,需要一个红包队列支持

2、抢红包出现的并发问题

 

1⃣️发送红包至直播间,多人发送,只需要一个队列即可解决所有红包的顺序问题,采用redis队列

那用什么队列比较合适最好

2⃣️抢红包怎么控制并发问题?

先设计数据库模型

红包规格

  1. CREATE TABLE `red_packet_info` (
  2. `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  3. `red_packet_id` varchar(32) NOT NULL COMMENT COMMENT '红包id',
  4. `total_packet` int(11) NOT NULL DEFAULT 0 COMMENT '红包总个数',
  5. `total_packet_detail` varchar(64) NOT NULL DEFAULT 0 COMMENT '红包详情',
  6. `remaining_packet` int(11) NOT NULL DEFAULT 0 COMMENT '剩余红包个数',
  7. `remaining_packet_detail` varchar(64) NOT NULL DEFAULT 0 COMMENT '剩余红包详情',
  8. `user_id` bigint(64) NOT NULL COMMENT '新建红包用户的用户标识',
  9. `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  10. `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  11. PRIMARY KEY (`id`) ) ,
  12. UNIQUE KEY `uk_red_packet_id` (`red_packet_id`),
  13. ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='红包信息表,新建一个红包插入一条记录';

红包领取记录表

  1. CREATE TABLE `red_packet_record` (
  2. `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id',
  3. `red_packet_id` varchar(32) NOT NULL COMMENT COMMENT '红包id',
  4. `award_id` varchar(32) NOT NULL DEFAULT '0' COMMENT '抢到礼物id',
  5. `award_name` varchar(32) NOT NULL DEFAULT '0' COMMENT '抢到礼物名称',
  6. `user_id` int(20) NOT NULL COMMENT '抢到红包用户的用户标识',
  7. `user_name` varchar(32) NOT NULL DEFAULT '0' COMMENT '抢到红包的用户的用户名',
  8. `user_head` varchar(256) NOT NULL DEFAULT '0' COMMENT '抢到红包的用户的头像',
  9. `create_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  10. `update_dt` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
  11. PRIMARY KEY (`id`) ),
  12. KEY `uk_red_packet_id_user_id`(`red_packet_id`,`user_id`) USING BTREE,
  13. ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COMMENT='抢红包记录表,抢一个红包插入一条记录';

红包队列设计链路

阻塞队列(Blocking Queue)

基于Redis的Redisson分布式无界阻塞队列(Blocking Queue)结构的RBlockingQueue Java对象实现了java.util.concurrent.BlockingQueue接口。

尽管RBlockingQueue对象无初始大小(边界)限制,但对象的最大容量受Redis限制,最大元素数量是4 294 967 295个。

放入数据:
  offer(anObject):表示如果可能的话,将anObject加到BlockingQueue里,即如果BlockingQueue可以容纳,
    则返回true,否则返回false.(本方法不阻塞当前执行方法的线程)
  offer(E o, long timeout, TimeUnit unit),可以设定等待的时间,如果在指定的时间内,还不能往队列中
    加入BlockingQueue,则返回失败。
  put(anObject):把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断
    直到BlockingQueue里面有空间再继续。

获取数据:
  poll(time):取走BlockingQueue里排在首位的对象,若不能立即取出,则可以等time参数规定的时间,
    取不到时返回null;
  poll(long timeout, TimeUnit unit):从BlockingQueue取出一个队首的对象,如果在指定时间内,
    队列一旦有数据可取,则立即返回队列中的数据。否则知道时间超时还没有数据可取,返回失败。
  take():取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到
    BlockingQueue有新的数据被加入; 
  drainTo():一次性从BlockingQueue获取所有可用的数据对象(还可以指定获取数据的个数), 
    通过该方法,可以提升获取数据效率;不需要多次分批加锁或释放锁。

对于红包队列最好使用有界队列,但是redis的Blocking Queue是有最大容量限制,不用考虑会撑爆内存的问题

一、添加红包队列

  1. RBlockingQueue<String> queue = redissonClient.getBlockingQueue(userId);
  2. boolean isOffer = queue.offer(redPacketId);
  3. if(!isOffer){
  4. log.error("redPacket queue is full","红包队列已满");
  5. }
  6. return queue.size();

获取队列首个

take是阻塞方法,采用peek

  1. RBlockingQueue<String> queue = blockingQueueInfo(liveId);
  2. List<String> curRedPacketList = new ArrayList<>();
  3. Iterator<String> listOfRedPacket = queue.iterator();
  4. while (listOfRedPacket.hasNext()){
  5. curRedPacketList.add(listOfRedPacket.next());
  6. }
  7. String headElement = queue.peek();

二、抢红包

针对抢红包的过程,其实很简单,控制好红包的拆分以及用户重复领取就可以了,当然抢的过程要保持好的性能。

性能瓶颈:1、抢红包      原子操作,保证红包个数小于0的时候扣减失败

                  2、拆红包     CAS落库更新

 

 

 

 

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/849685
推荐阅读
相关标签
  

闽ICP备14008679号