`
阅读更多

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

 

  • 使用有序集合
这种方案能够同时储存在线的用户 和 用户上线时间,能够执行非常多的聚合计算,但是所消耗的内存也是非常可观的。
  • 使用集合
这种方案能储存在线的用户,也能够执行一定的聚合计算,相对有序集合,所消耗的内存要小些,但是随着用户量的增多,消耗内存空间也处于增加状态
  • 使用hyperloglog
这种方案无论统计多少在线用户, 消耗的内存都是12k,但是只能给出在线用户的统计信息,无法获取准确的在线用户名单
  • 使用bitmap
这种方案还是比较好的,在尽可能节省内存空间情况下,记录在线用户的情况,而且能做一定的聚合运算
 
下面我们就用实际例子来说明:
 
我们先以每天会有10w~30w的小量用户, 100w的用户群来说明下面的几种方案
 
方案一:使用有序集合
 
先生成用户在线记录数据:
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. $start_time = mktime(0, 0, 0, 9, 5);    //monday  
  2. for ($i=0; $i < 6; $i++) {  
  3.     $day_start_time  = $start_time + 86400 * $i;    //every day begin time  
  4.     $day_end_time =  $day_start_time + 86400;       //every day end time  
  5.     $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000   
  6.   
  7.     for ($j=1; $j < $online_user_num$j++) {   
  8.         $user_id = mt_rand(1, 1000000);  
  9.         $redis->zadd('000|online_users_day_'.$i, mt_rand($day_start_time$day_end_time), $user_id);  
  10.     }  
  11. }  

好了记下来我们就来看看都能统计出哪些信息来吧
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //note: 统计每天的在线总人数  
  2. for ($i=0; $i < 6; $i++) {   
  3.     print_r($redis->zsize('000|online_users_day_'.$i). "\n");  
  4. }  
  5.   
  6. //note: 统计最近6天都在线的人数  
  7. var_dump($redis->zInter('000|online_users_day_both_6',   
  8.     [  
  9.     '000|online_users_day_0',   
  10.     '000|online_users_day_1',   
  11.     '000|online_users_day_2',   
  12.     '000|online_users_day_3',   
  13.     '000|online_users_day_4',   
  14.     '000|online_users_day_5'  
  15.     ]  
  16.     ));  
  17.   
  18. //note: 统计出近6天中共有多少上线  
  19. $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']);  
  20.   
  21. //note: 统计某个时间段总共在线用户  
  22. print_r($redis->zcount('000|online_users_day_5'mktime(13, 0, 0, 9, 10), mktime(14, 0, 0, 9, 10)));  
  23.   
  24. //note: 统计某个时间段在线用户名单  
  25. print_r($redis->zrangebyscore('000|online_users_day_5'mktime(13, 0, 0, 9, 10), mktime(14, 0, 0, 9, 10),   
  26.     array('withscores' => TRUE)));  

不单单只有这些, 我们还能统计出早, 中, 午, 晚 等等时间段的用户在线情况,还有很多其他的,这就让我们发挥想象吧,是不是挺多的? 只是确实也相当耗费内存空间
 
方案二:使用集合
 
还是先来成用户在线记录数据:
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //note set 一般聚合  
  2. for ($i=0; $i < 6; $i++) {  
  3.     $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000   
  4.   
  5.     for ($j=1; $j < $online_user_num$j++) {   
  6.         $user_id = mt_rand(1, 1000000);  
  7.         $redis->sadd('001|online_users_day_'.$i$user_id);  
  8.     }  
  9. }  

好了记下来我们就来看看都能统计出哪些信息来吧
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //note 判断某个用户是否在线  
  2. var_dump($redis->sIsMember('001|online_users_day_5', 100030));  
  3.   
  4. //note 每天在线用户总量的统计  
  5. for ($i=0; $i < 6; $i++) {   
  6.     print_r($redis->ssize('001|online_users_day_'.$i). "\n");  
  7. }  
  8.   
  9. //note 对不同时间段的在线用户名单进行聚合  
  10. print_r($redis->sInterStore('001|online_users_day_both_4and5''001|online_users_day_4''001|online_users_day_5'). "\n");  
  11.   
  12. //note 对指定的时间段的在线用户名单进行统计  
  13. print_r($redis->sUnionStore('001|online_users_day_total_4add5''001|online_users_day_4''001|online_users_day_5'). "\n");  
  14.   
  15. //note 哪天上线哪天没上线  
  16. print_r($redis->sDiffStore('001|online_users_day_diff_4jian5''001|online_users_day_4''001|online_users_day_5'). "\n");  

是不是也挺不错的,先不要着急, 我们接着往下看
 
方案三:使用hyperloglgo
 
先来成用户在线记录数据:
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. // note HyperLogLog 只需要知道在线总人数  
  2. for ($i=0; $i < 6; $i++) {  
  3.     $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000   
  4.     var_dump($online_user_num);  
  5.     for ($j=1; $j < $online_user_num$j++) {   
  6.         $user_id = mt_rand(1, 1000000);  
  7.         $redis->pfadd('002|online_users_day_'.$i, [$user_id]);  
  8.     }  
  9. }  

这种方案,我们来看看都能实现哪些业务呢
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. $count = 0;  
  2. for ($i=0; $i < 3; $i++) {   
  3.     $count += $redis->pfcount('002|online_users_day_'.$i);  
  4.     print_r($redis->pfcount('002|online_users_day_'.$i). "\n");  
  5. }  
  6. var_dump($count);  
  7.   
  8. //note  3 days total online num  
  9. var_dump($redis->pfmerge('002|online_users_day_both_3', ['002|online_users_day_0''002|online_users_day_1''002|online_users_day_2']));  
  10. var_dump($redis->pfcount('002|online_users_day_both_3'));  

好少啊,是的, 这种方案仅仅只能统计出某个时间段在线人数的总量, 对在线用户的名单却无能为力,但是却挺节省内存的,对统计数据要求不多情况下 ,我们便可以考虑这种方案。
 
方案四:使用bitmap
 
笔者对这种方案其实挺喜欢的,消耗的内存空间不多, 统计的信息却挺多的,还是老步骤,先来生成数据:
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //note bitmap 综合前面3个的优缺点  
  2. for ($i=0; $i < 6; $i++) {  
  3.     $online_user_num = mt_rand(100000, 300000);     //online user between 100000 and 300000   
  4.   
  5.     for ($j=1; $j < $online_user_num$j++) {   
  6.         $user_id = mt_rand(1, 1000000);  
  7.         $redis->setbit('003|online_users_day_'.$i$user_id, 1);  
  8.     }  
  9. }  

接下来我们看看能满足的统计信息吧
 
[php] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. //note userid today whether online   
  2. var_dump($userid = mt_rand(1, 1000000));  
  3. var_dump($redis->getbit('003|online_users_day_5'$userid));  
  4.   
  5. //note how many user is online  
  6. var_dump($redis->bitcount('003|online_users_day_5'));  
  7.   
  8. //note 6 days both online  
  9. var_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'));  
  10. var_dump($redis->bitcount('003|online_users_day_both_6'));  
  11.   
  12. //note 6 days total online  
  13. var_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'));  
  14. var_dump($redis->bitcount('003|online_users_day_total_6'));  
  15.   
  16. //note 6 days only one online  
  17. var_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'));  
  18. var_dump($redis->bitcount('003|online_users_day_only_one_6'));  

怎么样? 是不是集合能统计的 这家伙也能统计出来? 而且消耗的内容还少。
 
对于这几种方案其实各有各的好处, 根据业务统计信息 来取相应的方案来实施吧,这样内存利用也就更合理了
分享到:
评论

相关推荐

    Windows版 Redis 5.0.14

    Redis 是一个开源的内存数据结构存储系统,常被用作数据库、缓存和消息代理。在Windows环境下,Redis 的安装和使用与在Linux系统中有所不同。这里我们将详细讨论Windows版Redis 5.0.14的相关知识点。 1. **Redis ...

    StackExchange.Redis Redis客户端

    最近需要在C#中使用Redis,在Redis的官网找到了ServiceStack.Redis,最后在测试的时候发现这是个坑,4.0已上已经收费,后面只好找到3系列的最终版本,最后测试发现还是有BUG或者是我不会用。没有办法,最好找到了...

    Linux 系统 安装redis redis-5.0.1.tar.gz 安装包

    在Linux系统中安装Redis是一个常见的任务,特别是在搭建服务器或开发基于Redis的数据缓存应用时。Redis是一个开源的、高性能的键值对存储系统,适用于数据缓存、消息队列等多种场景。本文将详细介绍如何在Linux上...

    redis-windows-Redis7.0.0.zip

    Redis,全称Remote Dictionary Server,是一款开源的、高性能的键值存储系统,广泛应用于缓存、消息队列、数据持久化等多种场景。它以其高效、轻量级的特性,在IT行业中备受青睐,尤其是在互联网领域。在Windows环境...

    redis部署6.2.6最新稳定版文档和程序 redis部署6.2.6最新稳定版文档和程序

    redis部署6.2.6最新稳定版文档和程序redis部署6.2.6最新稳定版文档和程序redis部署6.2.6最新稳定版文档和程序redis部署6.2.6最新稳定版文档和程序redis部署6.2.6最新稳定版文档和程序redis部署6.2.6最新稳定版文档和...

    redis在win上的运行脚本redis.bat

    Redis是一款高性能的键值对数据库,常用于缓存、消息队列等场景。在Windows操作系统上运行Redis,通常需要借助一些额外的工具。标题提到的"redis在win上的运行脚本redis.bat"就是一个帮助用户在Windows环境下启动...

    redis win x64位 及 安装卸载RedisServer服务

    Redis是世界上最受欢迎的开源内存数据结构存储系统,它可以用作数据库、缓存和消息代理。在Windows 64位环境下,Redis的安装和卸载过程是很多开发者和系统管理员需要了解的重要技能。以下是对这些知识点的详细说明:...

    Redis Desktop Manager redis的可视化工具压缩包,解压即用

    Redis Desktop Manager是一款强大的开源图形化界面工具,专为管理和操作Redis键值存储系统而设计。它为用户提供了直观且高效的界面,使得在处理Redis数据库时能够更加便捷。这个压缩包包含的就是这款工具的安装文件...

    Redis-7.0.5-x64 for Windows 64位版 Redis 7.0.5

    Redis是一款高性能的键值对内存数据库,被广泛应用于缓存、数据存储等领域。在这个Windows 64位版本的Redis 7.0.5中,我们能够看到一系列关键组件和配置文件,这使得它能够在Windows环境下运行。以下是关于Redis ...

    若依前后端分离版去redis版/无redis版本

    基于前后端分离的应用,无论是否使用Redis,都需要考虑如何进行数据的存储和缓存。下面我将分别介绍基于Redis和无Redis的两种版本的特点。 基于Redis的版本 特点 缓存处理:Redis作为内存数据库可以用来缓存频繁访问...

    Redis 7.0.4 x64位 windows 系统 安装包 Redis7.0.4.zip

    Redis7.0.4.zip,解压缩到D盘根目录后,安装后启动为Windows服务 注意是windows 64位系统才可使用,不支持windows 32位系统使用 已经在Win10,Win11,Windows server 2012系统测试运行可用 使用步骤注意事项: ...

    Windows 上安装 Redis安装,redis7.2安装到windows上面

    在Windows上安装Redis的过程涉及到多个步骤,包括启用必要的Windows功能、安装WSL2(Windows Subsystem for Linux 2)、设置默认WSL版本以及在Linux环境中安装Redis。以下是对这些步骤的详细说明: 1. **启用...

    redis 免安装 redis客户端 redis-desktop-manager-0.8.8.384

    Redis 是一个高性能的键值数据库,它以键值对的形式存储数据,广泛应用于缓存、消息中间件、实时分析等领域。在 Windows 环境下,通常需要通过安装过程来设置 Redis 服务,但这里提供的资源是“redis 免安装”,意味...

    redis 可视化工具以及免安装redis 绿色版

    Redis,全称Remote Dictionary Server,是一款高性能的键值存储数据库,常用于缓存、消息队列等场景。本文将深入探讨Redis的可视化工具及其免安装绿色版的使用,帮助你更好地管理和操作Redis服务器。 首先,了解...

    Redis使用教程,详解

    Redis 使用教程详解 Redis 是一个高性能的 NoSQL 键值存储数据库,广泛应用于缓存、任务列表、网站访问统计数据、过期处理、应用排行榜、分布式集群架构中的 session 分离等领域。下面是 Redis 的详细使用教程。 ...

    redis3.0安装包 window 64位

    (1)支持Lua脚本:Redis 3.0支持Lua脚本,可以在Redis中执行脚本,大大提高了Redis的灵活性和可扩展性; (2)可插拔模块化:Redis 3.0提供了可插拔的模块化功能,可以根据用户的需求,自定义模块,实现不同的功能...

    redis++使用说明,windows下编译redis-plus-plus

    "Redis++使用说明,windows下编译Redis-Plus-Plus" 在这篇文章中,我们将详细介绍如何在Windows平台下编译Redis++,包括编译hiredis.lib和Win32_Interop.lib静态库文件的过程,然后安装Cmake并编译Redis++,最后...

    redis 6.0 windows 版本

    Redis是一款高性能的键值存储系统,常用于数据库、缓存和消息代理等场景。它支持丰富的数据类型,如字符串、哈希、列表、集合和有序集合。在Windows平台上使用Redis,通常需要通过编译源码或者寻找预编译的二进制...

    【ASP.NET编程知识】.net core使用redis基于StackExchange.Redis.docx

    ASP.NET Core 使用 Redis 基于 StackExchange.Redis ASP.NET Core 是一个开源的、跨平台的框架,使用 C# 语言开发。Redis 是一个基于内存的数据存储系统,可以用来存储和处理大量数据。StackExchange.Redis 是一个...

    Redis-6.2.7 Windows 版

    Redis是一款高性能的键值对数据库,常用于缓存、消息队列等场景。这个"Redis-6.2.7 Windows 版"是针对Windows操作系统编译优化的版本,旨在为Windows用户提供便捷的服务。以下是关于Redis 6.2.7及其在Windows上的...

Global site tag (gtag.js) - Google Analytics