(给PHP开发者加星标,提升PHP技能)

转自:饼bing

blog.csdn.net/hao508506/article/details/52496656

在线人数统计业务是我们开发web肯定要设计的业务逻辑,本文就会给出几种设计方案,来分析下各个方案的优缺点:

  • 使用有序集合

这种方案能够同时储存在线的用户 和 用户上线时间,能够执行非常多的聚合计算,但是所消耗的内存也是非常可观的。

  • 使用集合

这种方案能储存在线的用户,也能够执行一定的聚合计算,相对有序集合,所消耗的内存要小些,但是随着用户量的增多,消耗内存空间也处于增加状态

  • 使用hyperloglog

这种方案无论统计多少在线用户, 消耗的内存都是12k,但是只能给出在线用户的统计信息,无法获取准确的在线用户名单

  • 使用bitmap

这种方案还是比较好的,在尽可能节省内存空间情况下,记录在线用户的情况,而且能做一定的聚合运算

下面我们就用实际例子来说明:

我们先以每天会有10w~30w的小量用户, 100w的用户群来说明下面的几种方案

方案一:使用有序集合

先生成用户在线记录数据:

$start_time = mktime(0, 0, 0, 9, 5);    //mondayfor ($i=0; $i 6; $i++) {    $day_start_time  = $start_time + 86400 * $i;    //every day begin time    $day_end_time =  $day_start_time + 86400;       //every day end time    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000 

    for ($j=1; $j         $user_id = mt_rand(1, 1000000);        $redis->zadd('000|online_users_day_'.$i, mt_rand($day_start_time, $day_end_time), $user_id);    }}

好了记下来我们就来看看都能统计出哪些信息来吧

//note: 统计每天的在线总人数for ($i=0; $i 6; $i++) {     print_r($redis->zsize('000|online_users_day_'.$i). "\n");}

//note: 统计最近6天都在线的人数var_dump($redis->zInter('000|online_users_day_both_6',     [    '000|online_users_day_0',     '000|online_users_day_1',     '000|online_users_day_2',     '000|online_users_day_3',     '000|online_users_day_4',     '000|online_users_day_5'    ]    ));

//note: 统计出近6天中共有多少上线$redis->zunion('000|online_users_day_total_6', ['000|online_users_day_0', '000|online_users_day_1', '000|online_users_day_2', '000|online_users_day_3', '000|online_users_day_4', '000|online_users_day_5']);

//note: 统计某个时间段总共在线用户print_r($redis->zcount('000|online_users_day_5', mktime(13, 0, 0, 9, 10), mktime(14, 0, 0, 9, 10)));

//note: 统计某个时间段在线用户名单print_r($redis->zrangebyscore('000|online_users_day_5', mktime(13, 0, 0, 9, 10), mktime(14, 0, 0, 9, 10),     array('withscores' => TRUE)));

不单单只有这些, 我们还能统计出早, 中, 午, 晚 等等时间段的用户在线情况,还有很多其他的,这就让我们发挥想象吧,是不是挺多的?只是确实也相当耗费内存空间

方案二:使用集合

还是先来成用户在线记录数据:

//note set 一般聚合for ($i=0; $i 6; $i++) {    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000 

    for ($j=1; $j         $user_id = mt_rand(1, 1000000);        $redis->sadd('001|online_users_day_'.$i, $user_id);    }}

好了记下来我们就来看看都能统计出哪些信息来吧

//note 判断某个用户是否在线var_dump($redis->sIsMember('001|online_users_day_5', 100030));

//note 每天在线用户总量的统计for ($i=0; $i 6; $i++) {     print_r($redis->ssize('001|online_users_day_'.$i). "\n");}

//note 对不同时间段的在线用户名单进行聚合print_r($redis->sInterStore('001|online_users_day_both_4and5', '001|online_users_day_4', '001|online_users_day_5'). "\n");

//note 对指定的时间段的在线用户名单进行统计print_r($redis->sUnionStore('001|online_users_day_total_4add5', '001|online_users_day_4', '001|online_users_day_5'). "\n");

//note 哪天上线哪天没上线print_r($redis->sDiffStore('001|online_users_day_diff_4jian5', '001|online_users_day_4', '001|online_users_day_5'). "\n");

是不是也挺不错的,先不要着急, 我们接着往下看

方案三:使用hyperloglgo

先来成用户在线记录数据:

// note HyperLogLog 只需要知道在线总人数for ($i=0; $i 6; $i++) {    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000     var_dump($online_user_num);    for ($j=1; $j         $user_id = mt_rand(1, 1000000);        $redis->pfadd('002|online_users_day_'.$i, [$user_id]);    }}

这种方案,我们来看看都能实现哪些业务呢

$count = 0;for ($i=0; $i 3; $i++) {     $count += $redis->pfcount('002|online_users_day_'.$i);    print_r($redis->pfcount('002|online_users_day_'.$i). "\n");}var_dump($count);

//note  3 days total online numvar_dump($redis->pfmerge('002|online_users_day_both_3', ['002|online_users_day_0', '002|online_users_day_1', '002|online_users_day_2']));var_dump($redis->pfcount('002|online_users_day_both_3'));

好少啊,是的, 这种方案仅仅只能统计出某个时间段在线人数的总量, 对在线用户的名单却无能为力,但是却挺节省内存的,对统计数据要求不多情况下 ,我们便可以考虑这种方案。

方案四:使用bitmap

笔者对这种方案其实挺喜欢的,消耗的内存空间不多, 统计的信息却挺多的,还是老步骤,先来生成数据:

//note bitmap 综合前面3个的优缺点for ($i=0; $i 6; $i++) {    $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000 

    for ($j=1; $j         $user_id = mt_rand(1, 1000000);        $redis->setbit('003|online_users_day_'.$i, $user_id, 1);    }}

接下来我们看看能满足的统计信息吧

//note userid today whether online var_dump($userid = mt_rand(1, 1000000));var_dump($redis->getbit('003|online_users_day_5', $userid));

//note how many user is onlinevar_dump($redis->bitcount('003|online_users_day_5'));

//note 6 days both onlinevar_dump($redis->bitop('AND', '003|online_users_day_both_6', '003|online_users_day_0', '003|online_users_day_1', '003|online_users_day_2', '003|online_users_day_3', '003|online_users_day_4', '003|online_users_day_5'));var_dump($redis->bitcount('003|online_users_day_both_6'));

//note 6 days total onlinevar_dump($redis->bitop('OR', '003|online_users_day_total_6', '003|online_users_day_0', '003|online_users_day_1', '003|online_users_day_2', '003|online_users_day_3', '003|online_users_day_4', '003|online_users_day_5'));var_dump($redis->bitcount('003|online_users_day_total_6'));

//note 6 days only one onlinevar_dump($redis->bitop('XOR', '003|online_users_day_only_one_6', '003|online_users_day_0', '003|online_users_day_1', '003|online_users_day_2', '003|online_users_day_3', '003|online_users_day_4', '003|online_users_day_5'));var_dump($redis->bitcount('003|online_users_day_only_one_6'));

怎么样?是不是集合能统计的 这家伙也能统计出来?而且消耗的内容还少。

对于这几种方案其实各有各的好处, 根据业务统计信息 来取相应的方案来实施吧,这样内存利用也就更合理了

- EOF -

推荐阅读  点击标题可跳转

1、如何在 PHP 中进行会话处理?

2、PHP下kafka的实践

3、PHP 内存泄漏问题解析

看完本文有收获?请分享给更多人

推荐关注「PHP开发者」,提升PHP技能

点赞和在看就是最大的支持❤️

腾讯在线人数统计_PHP + REDIS 实践:统计在线人数的几种方案分析相关推荐

  1. Redis 分布式集群的几种方案及问题

    1.Redis 分布式集群的几种方案 1.1.主从复制 从服务器连接主服务器,发送SYNC命令: 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命 ...

  2. REDIS实践之在线人数统计几种方案分析

    在线人数统计业务是我们开发web肯定要设计的业务逻辑,本文就会给出几种设计方案,来分析下各个方案的优缺点: 使用有序集合 这种方案能够同时储存在线的用户 和 用户上线时间,能够执行非常多的聚合计算,但 ...

  3. Redis高可用集群主流架构方案分析

    redis在互联网大数据平台有着广泛的应用,主要被用来缓存热点数据,避免海量请求压垮数据库,同时可以提升服务节点的响应速度和并发量.随着数据量的增多,由于redis是占用单台物理机或虚机的内存,内存资 ...

  4. Redis实现消息队列的4种方案

    Redis作为内存中的数据结构存储,常用作数据库.缓存和消息代理.它支持数据结构,如 字符串,散列,列表,集合,带有范围查询的排序集(sorted sets),位图(bitmaps),超级日志(hyp ...

  5. Redis 处理接口幂等性的两种方案

    前言:接口幂等性问题,对于开发人员来说,是一个跟语言无关的公共问题.对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦重复了,可能会导致很严重的 ...

  6. Redis实现分布式锁的7种方案

    https://www.cnblogs.com/wangyingshuo/p/14510524.html 七种方案前言 日常开发中,秒杀下单.抢红包等等业务场景,都需要用到分布式锁.而Redis非常适 ...

  7. Redis 消息队列的三种方案选型

    文章目录 Redis 消息队列的三种方案选型 消息队列(Message Queue,简称 MQ) 消息队列使用场景 Redis 消息队列应用背景,选型思考 Redis消息队列发展历程 在Redis中提 ...

  8. Springboot+redis 做实时在线人数统计

    Springboot+redis 做实时在线人数统计 介绍 实现 介绍 利用redis 有序集合实现. Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员. 不同的是 ...

  9. 给你一个亿的keys,Redis如何统计?

    前言 不知你大规模的用过Redis吗?还是仅仅作为缓存的工具了?在Redis中使用最多的就是集合了,举个例子,如下场景: 签到系统中,一天对应一系列的用户签到记录. 电商系统中,一个商品对应一系列的评 ...

最新文章

  1. hpunix下11gRac的安装
  2. VMware虚拟机安装
  3. 关于搞技术的一点思考
  4. 中止请求和超时 跨域的HTTP请求 认证方式 JSONP
  5. 不是美工却依然想写出美丽的CSS该肿么办
  6. make clean
  7. Java中的GC(垃圾回收)log
  8. Chrome 快捷键
  9. C#导出数据—使用Word模板
  10. win10系统默认壁纸路径
  11. Namenode HA原理详解
  12. 【ProVerif学习笔记】1:基本使用流程
  13. 抖音壁纸表情包小程序源码,可对接流量主
  14. pool(三)——Timer
  15. 【干货】电商知识图谱构建及搜索推荐场景下的应用.pdf(附下载链接)
  16. 今年很火的AI绘画怎么玩
  17. 使用HTML5 SVG绘制的多层饼形图(纯javascript)
  18. Ubuntu 18.04 安装Wine 微信
  19. cut命令的详细用法
  20. 百万级 QPS 业务新宠,金山办公携手 Apache APISIX 打造网关实践新体验

热门文章

  1. error 4 in libc-2.12.so 解决办法
  2. 【转】在CSS中 ID与Class的区别?谢谢
  3. Windows Phone 7 程序菜单栏ApplicationBar
  4. SQLServer 2005删除无主键表中的重复项
  5. LDAP 查询基本知识
  6. SAP更新数据表的程序执行需要SE38后执行
  7. SAP LSMW批导数据的几个注意点
  8. 强制结束后台作业(SAP SM37 SM35 SM50)
  9. ABAP中Conversion Routine示例
  10. BAPI_ACC_DOCUMENT_POST生成预制凭证增强