千万用户3毫秒内抽奖100名如何实现?
🍁 作者:知识浅谈,CSDN签约讲师,CSDN博客专家,华为云云享专家,阿里云专家博主
📌 擅长领域:全栈工程师、爬虫、ACM算法
💒 公众号:知识浅谈
🔥 联系方式vx:zsqtcc
🤞千万用户3毫秒内抽奖100名如何实现?🤞
正菜来了⛳⛳⛳
🎈场景再现
某618活动,零点的时候从关注的用户中抽出100个人进行超级某东e卡发放,预计全网超过1000万用户参加关注抽奖活动,要求 “同一用户不能重复参与,同一用户不允许二次开奖”,为了满足要求,请给出解决方案。
🎈解决方案
🍮原始实现方法
- rand() 随机产生一个随机数
select * from 关注用户表 order by rand() desc limit,0,100
预计千万级别的对技术倒排大概率凉凉。
🍮执行100次下边的sql
效率可以,不过要执行两次SQL,并发环境下有原子性问题,切不能保证不会重复中奖
offset = SELECT FLOOR(RAND() * COUNT(*)) AS offset from 关注用户表
select * from 关注用户表 limit offset,1
🍮基于Redis Set集合做随机弹出
📐第 1 步:
在用户关注直播间在写入MySQL关注用户表时额外在Redis:增加一个userlist Set集合,存储用户编号。
Redis Seti可以保证全局唯一,且数据基于Hash乱序存储,取出的直接就是随机值。
sadd userlist xxxid
预计用户编号长整型,1000万用户占用空间大概500MB。
100万50mb, 1000万500MB,不会对内存造成很大压力(redis虽然怕大key,但是在内存可控范围内,小key很多却不会有什么问题)
📐第 2步:
抽奖的时候,直接使用spop弹出随机100个用户编号即可,这个操作是原子性的,先弹出再返回,在加上Redist命令队列单线程不存在并发问题,这样杜绝了重复获奖的可能。
📐第 3步:
下一步执行1次select ini语句,提取数据,因为都是通过主键提取,效率快也不存在in索引失效问题,但要注意in的数量上限是1000个,超过1000个备选项要拆成多个in.
🍮摆脱MySQL,纯Redis方案
进阶方案,内存富裕可用
因为抽奖结果页面通常只显示用户昵称,我们还可以使用Rdis提速,用内存换时间。具体做法是
估算千万用户需要3G左右内存,spop提取速度完全可控制在3ms内完成,且不会重复。
TIPS:Redis不怕Key多,就怕大Key.
测试结果:
1000 次pop执行时间2565
🍚总结
以上就是千万用户3毫秒内抽奖100名如何实现的。
- 点赞
- 收藏
- 关注作者
评论(0)