暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PHP + REDIS统计在线人数的几种方案及分析

编程经验共享 2022-08-17
924

点击进入“编程经验共享”    


在线人数统计业务是我们开发过程中必不可少的业务逻辑,今天就php+redis的几种设计方案,来分析一下各个方案的优缺点:

一. 集合

redis的集合是String类型的无序集合,集合成员是唯一的,没有重复的元素。

集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。


这种方案能储存在线的用户数,也能执行一定的聚合计算,随着用户量的增加,消耗内存空间随之增加。

再来看看集合能统计出哪些信息吧

    //key根据天来变化,储存的值为用户id
    $redis = new \Redis();
    //判断用户是否在线
    $redis->sIsMenber('online_user_20220506','用户标识')


    //每天在线用户总量的统计或者最近一周每天在线用户总量
    $end_time = strtotime('00:00:00');
    for($i=0;$i<6;$i++){
    //统计日期
      $date = $end_time-$i*24*60*60;
      //获取某一天的在线用户数,可以用数组储存再返回给前端显示
      $redis->sCard('online_user_'.date('Ymd',$date));
    }


    //两日连续在线用户总量(通过计算集合的交集获取连续在线用户总量)
    $redis-sInter('online_user_20220506','online_user_20220507')


    //七日在线总用户量(通过计算集合的并集获取在线用户总量)
    $redis->sUnion('online_user_20220506','online_user_20220507','online_user_20220508','online_user_20220509','online_user_20220510','online_user_20220511','online_user_20220512')

    集合的作用看起来还不错,但是无法获取某天里某个时间段的在线用户总量。例如:中午12点~2点的在线用户总量,也不知道用户当天打开的时间。对于这一点有序集合就提供了很好的帮助


    二. 有序集合

    有序集合与集合一样都是string类型元素的集合,且不能有重复的元素。

    集合中最大的成员数为 232 - 1 (4294967295, 每个集合可存储40多亿个成员)。

    不同的是,有序集合每一个元素都会关联一个double类型的分数,通过分数给元素排序。

    我们来看看有序集合能统计出来的数据有哪些吧

      //通过有序集合存储在线用户时,元素为用户标识,分数为进入app或者登录时间
      $redis = new \Redis();
      //判断用户是否在线及用户某日首次进入app的时间
      //(不存在集合中返回null,否则返回分数值即进入app/登录时间)
      $redis->zScore('online_user_20220506','用户标识')


      //每天在线用户总量的统计或者最近一周每天在线用户总量
      $end_time = strtotime('00:00:00');
      for($i=0;$i<6;$i++){
      //统计日期
      $date = $end_time-$i*24*60*60;
      //获取某一天的在线用户数,可以用数组储存再返回给前端显示
      $redis->sCard('online_user_'.date('Ymd',$date));
      }


      //两日连续在线用户总量(通过计算集合的交集获取连续在线用户总量),并储存在新的key中
      $redis-zInterStore('online_user_zand0607',[
      'online_user_20220506',
      'online_user_20220507'
      ])


      //七日在线总用户量(通过计算集合的并集获取在线用户总量)
      $redis->zUnionStore('online_user_zand0607',[
      'online_user_20220506','online_user_20220507',
      'online_user_20220508','online_user_20220509',
      'online_user_20220510','online_user_20220511',
      'online_user_20220512'
      ])


      //统计中午12点~2点在线用户总量(通过分数计算某个时间段在线总量)
      $redis->zCount('online_user_20220506',mktime(12,0,0),mktime(14,0,0));

      有序集合确实比集合要好得很多。缺点和集合一样,当数据量越大时,占用内存越大。


      在redis中还有两种数据类型:hyperLogLog和bitmap


      每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。但是无法存储用户首次访问的时间,也无法计算中午12点到14点的在线用户数。如果需要统计就需要更多的redis键去存储更多的数据,不利于代码编写,还容易出错。


      bitmap也叫位图,也就是用一个bit位来表示一个东西的状态,我们都知道bit位是二进制,所以只有两种状态,0和1。个人不建议大家使用该数据类型,不利于业务系统的发展。


      综上所述,个人推荐使用有序集合存储用户在线信息。有序集合能够更好得聚合运算,有助于业务系统的发展。

      文章转载自编程经验共享,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论