当前位置: 首页 > news >正文

【架构设计】如何实现3ms内从1000w级别的用户里面随机抽奖出100名用户

        最近在学习it老齐的架构设计,课程里面有这样一个课题,如何实现3ms内从1000w级别的用户里面随机抽取出100m用户。

        首先,我们先从常规的常规的sql出发,如果要从数据表里面随机的选出几名员工的话,可能会使用mysql的相关函数

select username from user order by rand() limit 10

但是我们知道在mysql里面使用order by rand会让数据库性能呈指数级下降。因为MySQL会不得不去执行RAND()函数(很消耗CPU的时间),而且这是为每一条记录及取值,然后再对其排序,所以这种方法不推荐。

        那么,我们来考虑使用第二种改进的方案。

        方案二、

       offset = select FLOOR(RAND()*COUNT()) AS offset FROM 关注用户表;

        select * from 活动用户表 limit offset 1;

        性能尚可,但是因为要执行两条语句,所以可能存在原子性的问题,且不能保证不会存在重复中奖的可能性。

       接着,我们再深入思考,可不可以通过Redis这种方案来进行优化能

        方案三、基于redis set集合做随机弹出

        通过redis的set类型来做入栈和出栈的操作来随机抽出100名用户
     

        具体实现方法:在用户关注直播间的时候,写入MySQL的同时额外在Redis增加userlist Set集合,存储用户编号。

sadd userlist userid1 userid2 userid3...

添加完成之后,预计1000w用户预计占用500M内存空间。    

然后,从里面随机弹出100位用户即可。

 spop userlist 100

10000009
10000034
10000453
10000053
10000034
10000434
.....

select username from 关注用户表 where id in (10000009,10000034,10000453,10000053,10000034,10000434);

这种做法的好处是,使用redis来取代了mysql获取中奖员工编号,提升了效率, 属于用空间换时间的做法,大大的提升了效率,但是仍然没有完全摆脱MySQL,最后一步,仍然是从MySQL中取值,没有把效率发挥到极致。

最后,我来放大招了。

方案四、完全使用Redis实现

sadd userlist "10011515:gaos" "1004554454:ccf" "121432452:zhangxr"....

然后从里面随机弹出100个元素

spop userlist 100

最后,对于弹出的结果进行相应的处理,只显示对应的用户名称即可。

import redis
from random import randint

if __name__ == '__main__':
    redis_conn = redis.Redis(host="127.0.0.1", port=6379, password="")
    print(redis_conn)
    for i in range(100000):
        num_int = str(i).zfill(6)
        redis_conn.sadd("userlist", f"{randint(10000000,99999999)}:ccf{num_int}")
    s2 = redis_conn.spop("userlist", 10)
    print("获奖的员工为:")
    for s in s2:
        if len(s.decode("UTF-8").split(":")) > 1:
            print(s.decode("UTF-8").split(":")[1])

执行完成之后,可以发现pop操作的时间控制在了3ms内,该方案有效!

相关文章:

  • HTB-Chatterbox
  • 矩阵乘法的消去律
  • FL Studio最新20.9版本完整FL水果中文语言更新
  • JAVA集合(二)List接口详解
  • 矩阵的秩的性质
  • Redis在SpringBoot项目中使用
  • Android AIDL跨进程通信
  • Java大牛必会|分布式缓存实现方案之Spring Cache
  • KF、EKF、IEKF、UKF卡尔曼滤波器
  • Neo4j入门+深入
  • 21年icpc上海区域赛B题Strange Permutations (容斥+生成函数)
  • 【CSS】QQ邮箱布局,词典四列布局,行内布局
  • 滑动窗口问题
  • Java的输入 Scanner in=new Scanner(System.in);
  • 接口请求返回状态码
  • [译]Python中的类属性与实例属性的区别
  • __proto__ 和 prototype的关系
  • 0x05 Python数据分析,Anaconda八斩刀
  • ES6系统学习----从Apollo Client看解构赋值
  • JavaScript中的对象个人分享
  • Linux gpio口使用方法
  • mockjs让前端开发独立于后端
  • mysql 5.6 原生Online DDL解析
  • Python3爬取英雄联盟英雄皮肤大图
  • Traffic-Sign Detection and Classification in the Wild 论文笔记
  • XForms - 更强大的Form
  • 当SetTimeout遇到了字符串
  • 你真的知道 == 和 equals 的区别吗?
  • 前端 CSS : 5# 纯 CSS 实现24小时超市
  • 微信小程序开发问题汇总
  • 想晋级高级工程师只知道表面是不够的!Git内部原理介绍
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • 阿里云ACE认证学习知识点梳理
  • ​【C语言】长篇详解,字符系列篇3-----strstr,strtok,strerror字符串函数的使用【图文详解​】
  • # C++之functional库用法整理
  • #QT(一种朴素的计算器实现方法)
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (2)STM32单片机上位机
  • (env: Windows,mp,1.06.2308310; lib: 3.2.4) uniapp微信小程序
  • (JS基础)String 类型
  • (一)使用IDEA创建Maven项目和Maven使用入门(配图详解)
  • (转)shell中括号的特殊用法 linux if多条件判断
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .libPaths()设置包加载目录
  • .net 设置默认首页
  • .net(C#)中String.Format如何使用
  • .Net程序帮助文档制作
  • .net专家(高海东的专栏)
  • @开发者,一文搞懂什么是 C# 计时器!
  • [1]-基于图搜索的路径规划基础
  • [20150707]外部表与rowid.txt
  • [ArcPy百科]第三节: Geometry信息中的空间参考解析
  • [ASP]青辰网络考试管理系统NES X3.5
  • [BT]BUUCTF刷题第9天(3.27)