PHP四种统计在线人数方式详细介绍

目录
  • 1 用表统计方式
  • 2 使用 redis 有序集合实现在线人数统计
  • 3 使用 hyperloglog 做统计
  • 4 使用 bitmap 统计

1 用表统计方式

用数据表统计在线人数,这种方式只能用在并发量不大的情况下。

首先我们先新建表:user_login

编辑

user_login 表

模拟用户登录,不存在用户就存入表,存在的则更新登录信息

// 客户端唯一的识别码
$client_id = session()->getId();
//用户是否已存在
$user = DB::table('user_login')
    ->where('token', $client_id)
    ->first();
//不存在则插入数据
if (empty($user)) {
    $data = [
        'token' => $client_id,
        'username' => 'user_' . $client_id, // 模拟用户
        'uid' => mt_rand(10000000, 99999999),   //模拟用户id
        'create_time' => date('Y-m-d H:i:s'),
        'update_time' => date('Y-m-d H:i:s')
    ];
    DB::table('user_login')->insert($data);
} else {
    // 存在则更新用户登录信息
    DB::table('user_login')
     ->where('token', $client_id)
     ->update([
          'update_time' => date('Y-m-d H:i:s')
      ]);
}

这里还需要定期清理无任何操作的用户,假如用户一个小时内无任何操作,我们可以记为无效用户

代码如下:

// 客户端唯一的识别码
$client_id = session()->getId();
//用户是否已存在
$user = DB::table('user_login')
    ->where('token', $client_id)
    ->first();
//不存在则插入数据
if (empty($user)) {
    $data = [
        'token' => $client_id,
        'username' => 'user_' . $client_id, // 模拟用户
        'uid' => mt_rand(10000000, 99999999),   //模拟用户id
        'create_time' => date('Y-m-d H:i:s'),
        'update_time' => date('Y-m-d H:i:s')
    ];
    DB::table('user_login')->insert($data);
} else {
    // 存在则更新用户登录信息
    DB::table('user_login')
     ->where('token', $client_id)
     ->update([
          'update_time' => date('Y-m-d H:i:s')
      ]);
}

我们可以实现的功能:

1)当前在线人数

2)某时间段内在线人数

3)最新上线的用户

4)指定用户是否在线

// 可实现功能一:当前总共在线人数
$c = DB::table('user_login')->count();
echo '当前在线人数:' . $c . '<br />';
// 可实现功能二:某时间段内在线人数
$begin_date = '2020-08-13 09:00:00';
$end_date = '2020-08-13 18:00:00';
$c = DB::table('user_login')
    ->where('create_time', '>=', $begin_date)
    ->where('create_time', '<=', $end_date)
    ->count();
echo $begin_date . '-' . $end_date . '在线人数:' . $c . '<br />';
// 可实现功能三:最新上线的用户
$newest = DB::table('user_login')
    ->orderBy('create_time', 'DESC')
    ->limit(10)
    ->get();
echo '最新上线的用户有:';
foreach ($newest as $value) {
    echo $value->username . ' ';
}
echo '<br />';
// 可实现功能四:指定用户是否在线
$username = 'user_1111';
$online = DB::table('user_login')
    ->where('username', $username)
    ->exists();
echo $username . ($online ? '在线' : '不在线');

2 使用 redis 有序集合实现在线人数统计

因为是内存中,所以效率很高,可以统计某个时间段内的在线人数,可以做各种聚合操作。但是如果在线人数比较多的情况下,会比较占用内存。还有一点:

无法通过用户操作时间清除掉无效用户,只有手动登出的用户才会从集合中删除。

代码如下:

// 客户端唯一的识别码
$client_id = session()->getId();
echo $client_id . '<br />';
// 按日期生成key
$day = date('Ymd');
$key = 'online:' . $day;
// 是否在线
$is_online = Redis::zScore($key, $client_id);
if (empty($is_online)) {    // 不在线,加入当前客户端
    Redis::zAdd($key, time(), $client_id);
}
// 可实现功能一:当前总共在线人数
$c = Redis::zCard($key);
echo '当前在线人数:' . $c . '<br />';
// 可实现功能二:某时间段内在线人数
$begin_date = '2020-08-13 09:00:00';
$end_date = '2020-08-13 18:00:00';
$c = Redis::zCount($key, strtotime($begin_date), strtotime($end_date));
echo $begin_date . '-' . $end_date . '在线人数:' . $c . '<br />';
// 可实现功能三:最新上线的用户,时间从小到大排序
$newest = Redis::zRangeByScore($key, '-inf', '+inf', ['limit' => [0, 50]]);
echo '最新上线的用户有:';
foreach ($newest as $value) {
    echo $value . ' ';
}
echo '<br />';
// 可实现功能四:指定用户是否在线
$username = $client_id;
$online = Redis::zScore($key, $client_id);;
echo $username . ($online ? '在线' : '不在线') . '<br />';
// 可实现功能五:昨天和今天都上线的客户
$yestoday = Carbon::yesterday()->toDateString();
$yes_key = str_replace('-', '', $yestoday);
$members = [];
Redis::pipeline(function ($pipe) use ($key, $yes_key, &$members) {
    Redis::zinterstore('new_key', [$key, $yes_key], ['aggregate' => 'min']);
    $members = Redis::zRangeByScore('new_key', '-inf', '+inf', ['limit' => [0, 50]]);
    //dump($members);
});
echo '昨天和今天都上线的用户有:';
foreach ($members as $value) {
    echo $value . ' ';
}

3 使用 hyperloglog 做统计

跟有序集合方式不同,hyperloglog 十分节约空间,但是实现的功能也非常单一,只能统计在线人数,不能实现其余的任何功能。

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

// note HyperLogLog 只需要知道在线总人数
for ($i=0; $i < 6; $i++) {
    $online_user_num = mt_rand(10000000, 99999999);     //模拟在线人数
    var_dump($online_user_num);
    for ($j=1; $j < $online_user_num; $j++) {
        $user_id = mt_rand(1, 100000000);
        $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 num
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']));
var_dump($redis->pfcount('002|online_users_day_both_3'));

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

4 使用 bitmap 统计

bitmap 就是通过一个 bit 位来表示某个元素对应的值或者状态,其中的 key 就是对应元素本身。我们知道 8 个 bit 可以组成一个 Byte,所以 bitmap 本身会极大的节省储存空间。

bitmap 常用来做比如用户签到、活跃用户、在线用户等功能。

代码如下

// 模拟当前用户
$uid = request('uid');
$key = 'online_bitmap_' . date('Ymd');
// 设置当前用户在线
Redis::setBit($key, $uid, 1);
// 可实现功能1:在线人数
$c = Redis::bitCount($key);
echo '在线人数:' . $c . '<br />';
// 可实现功能2:指定用户是否在线
$online = Redis::getBit($key, $uid);
echo $uid . ($online ? '在线' : '不在线') . '<br />';
// 可实现功能3:昨天和今天均上线的用户总数
$yestoday = Carbon::yesterday()->toDateString();
$yes_key = str_replace('-', '', $yestoday);
$c = 0;
Redis::pipeline(function ($pipe) use ($key, $yes_key, &$c) {
    Redis::bitOp('AND', 'yest', $key, $yes_key);
    $c = Redis::bitCount('yest');
});
echo '昨天和今天都上线的用户数量有:' . $c . '<br />';

bitmap 消耗的内存空间不多, 统计的信息却挺多的,这种方案是值得推荐一下的。

到此这篇关于PHP四种统计在线人数方式详细介绍的文章就介绍到这了,更多相关PHP统计在线人数内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • php版微信数据统计接口用法示例

    本文实例讲述了php版微信数据统计接口用法.分享给大家供大家参考,具体如下: php版微信数据统计接口其实是非常的好用了在前版本还没有此功能是后面的版本增加上去了,下面来看一个php版微信数据统计接口的例子: 微信在1月6日时放出了新的数据分析接口传送门: 请注意: 1.接口侧的公众号数据的数据库中仅存储了2014年12月1日之后的数据,将查询不到在此之前的日期,即使有查到,也是不可信的脏数据: 2.请开发者在调用接口获取数据后,将数据保存在自身数据库中,即加快下次用户的访问速度,也降低了微信侧

  • PHP 使用Echarts生成数据统计报表的实现代码

    echarts统计,简单示例 先看下效果图 看下代码 HTML页面 为ECharts准备一个Dom,宽高自定义 <div class="panel panel-info"> <div class="panel-body"> <div id="echart_show" style="height:500px"></div> </div> </div> js文

  • php和jquery实现地图区域数据统计展示数据示例

    HTML 首先在head部分载入raphael.js库文件和chinamapPath.js路径信息文件,本文不重复写下,唯一不同的地方是需要在body中加一个div#tip,用来展示地图信息的提示框. 复制代码 代码如下: <div id="map"></div> <div id="tip"></div> jQuery 通过调用raphael绘制出中国地图,然后载入统计数据,由于地图区块小,我们不在地图载入的时候就将数

  • PHP+MySQL实现对一段时间内每天数据统计优化操作实例

    本文实例讲述了PHP+MySQL实现对一段时间内每天数据统计优化操作.分享给大家供大家参考,具体如下: 在互联网项目中,对项目的数据分析必不可少.通常会统计某一段时间内每天数据总计变化趋势调整营销策略.下面来看以下案例. 案例 在电商平台中通常会有订单表,记录所有订单信息.现在我们需要统计某个月份每天订单数及销售金额数据从而绘制出如下统计图,进行数据分析. 订单表数据结构如下: order_id order_sn total_price enterdate 25396 A4E610E250C2D

  • PHP+Mysql+jQuery中国地图区域数据统计实例讲解

    今天我要给大家介绍在实际应用中,如何把数据载入到地图中.本文结合实例,使用PHP+Mysql+jQuery实现中国地图各省份数据统计效果. 本例以统计某产品在各省份的活跃用户数为背景,数据来源于mysql数据库,根据各省份的活跃用户数,分成不同等级,并以不同的背景色显示各省份的活跃程度,符合实际应用需求. HTML 首先在head部分载入raphael.js库文件和chinamapPath.js路径信息文件. <script type="text/javascript" src=

  • PHP四种统计在线人数方式详细介绍

    目录 1 用表统计方式 2 使用 redis 有序集合实现在线人数统计 3 使用 hyperloglog 做统计 4 使用 bitmap 统计 1 用表统计方式 用数据表统计在线人数,这种方式只能用在并发量不大的情况下. 首先我们先新建表:user_login 编辑 user_login 表 模拟用户登录,不存在用户就存入表,存在的则更新登录信息 // 客户端唯一的识别码 $client_id = session()->getId(); //用户是否已存在 $user = DB::table('

  • ASP.NET MVC下的四种验证编程方式[续篇]

    在<ASP.NET MVC的四种验证编程方式>一文中我们介绍了ASP.NET MVC支持的四种服务端验证的编程方式("手工验证"."标注ValidationAttribute特性"."让数据类型实现IValidatableObject或者IDataErrorInfo"),那么在ASP.NET MVC框架内部是如何提供针对这四种不同编程方式的支持的呢?接下来我们就来聊聊这背后的故事. 一.ModelValidator与ModelVali

  • 详解Spring Security 中的四种权限控制方式

    Spring Security 中对于权限控制默认已经提供了很多了,但是,一个优秀的框架必须具备良好的扩展性,恰好,Spring Security 的扩展性就非常棒,我们既可以使用 Spring Security 提供的方式做授权,也可以自定义授权逻辑.一句话,你想怎么玩都可以! 今天松哥来和大家介绍一下 Spring Security 中四种常见的权限控制方式. 表达式控制 URL 路径权限 表达式控制方法权限 使用过滤注解 动态权限 四种方式,我们分别来看.  1.表达式控制 URL 路径权

  • Android 基于Bitmap的四种图片压缩方式

    知识点介绍 Android 中图片主要以 Bitmap 的形式存在,所以压缩图片主要就是减少 Bitmap 的大小.Bitmap 的大小可以通过如下的公式计算得到:size = width * height * 单个像素所占字节数.因此压缩图片通过改变公式中的三个变量即可实现. 单个像素所占空间大小在 Android 中有多种,详见如下 格式 所占空间 说明 Bitmap.Config.ALPHA_8 1B 该种格式表示图片只有透明度没有颜色,1个像素占用8位 Bitmap.Config.ARG

  • Json对象和字符串互相转换json数据拼接和JSON使用方式详细介绍(小结)

    JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式.它基于ECMAScript的一个子集. JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C.C++.C#.Java.JavaScript.Perl.Python等).这些特性使JSON成为理想的数据交换语言. 易于人阅读和编写,同时也易于机器解析和生成(一般用于提升网络传输速率). 一.JSON字符串转换为JSON对象: eval() 和 JSON.parse eg- js

  • Android Intent传递对象的两种方法(Serializable,Parcelable)详细介绍

    Android Intent传递对象的两种方法(Serializable,Parcelable)详细介绍 今天要给大家讲一下Android中Intent中如何传递对象,就我目前所知道的有两种方法,一种是Bundle.putSerializable(Key,Object);另一种是Bundle.putParcelable(Key, Object);当然这些Object是有一定的条件的,前者是实现了Serializable接口,而后者是实现了Parcelable接口,为了让大家更容易理解我还是照常写

  • Shell四种运行方式(启动方式)的实现

    Shell 是一个应用程序,它的一端连接着 Linux 内核,另一端连接着用户.Shell 是用户和 Linux 系统沟通的桥梁,我们都是通过 Shell 来管理 Linux 系统. 我们可以直接使用 Shell,也可以输入用户名和密码后再使用 Shell:第一种叫做非登录式,第二种叫做登录式. 我们可以在 Shell 中一个个地输入命令并及时查看它们的输出结果,整个过程都在跟 Shell 不停地互动,这叫做交互式.我们也可以运行一个 Shell 脚本文件,让所有命令批量化.一次性地执行,这叫做

  • Vue路由参数的传递与获取方式详细介绍

    目录 前言 1. 通过动态路由参数传递 2. 通过query字符串传递 3. props 隐式传递 前言 vue 页面路由切换时传参的方式有如下几种: 动态路由参数 它隐藏字段信息,相对于来说较安全,同时地址栏中的地址也相对较短 它必须是先定义后使用,一般用于根据固定参数,返回对应的数据所用 query字符串 ?id=1 通过search字符串的方式来在地址栏中传递数据,相对于来说地址栏会暴露字段信息安全性较低,一般用于搜索相关,它可以不定义就可以直接用 props 隐式传递 隐式传递,它一般用

  • 详解SpringMVC中的四种跳转方式、视图解析器问题

    目录 一.视图解析器: 1.springmvc核心配置文件,添加视图解析器: 2.视图解析器的使用: 3.视图解析器类InternalResourceViewResolver源码解析: 二.SpringMVC四种跳转方式: 1.跳转方式案例: 一.视图解析器: 1.springmvc核心配置文件,添加视图解析器: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www

  • thinkphp四种url访问方式详解

    本文实例分析了thinkphp的四种url访问方式.分享给大家供大家参考.具体分析如下: 一.什么是MVC thinkphp的MVC模式非常灵活,即使只有三个中和一个也可以运行. M -Model 编写model类 对数据进行操作 V -View  编写html文件,页面呈现 C -Controller 编写类文件(UserAction.class.php) 二.ThinkPHP的MVC特点    (简单了解) 三.ThinkPHP的MVC对应的目录  (简单了解) M 项目目录/应用目录/Li

随机推荐