delphi 软件在线人数统计_Redis实现实时统计在线用户人数的几种方案

一个业务系统网站每天人数的访问量是多少,在线人数是多少? 这种业务我们在开发中就要预留,也是在我们的设计范围内的咯!因为一个正在运营的网站,每天都会用到统计。

那在线人数是如何统计的呢,这里有几种方案,代码用laravel框架。可以作为开发中参考。

1 用表统计方式

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

首先我们先新建表:user_login

bb8b379767c497bad35118f25d677b87.png

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 . '
'; // 可实现功能二:某时间段内在线人数$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 . '
'; // 可实现功能三:最新上线的用户$newest = DB::table('user_login') ->orderBy('create_time', 'DESC') ->limit(10) ->get();echo '最新上线的用户有:';foreach ($newest as $value) { echo $value->username . ' ';}echo '
'; // 可实现功能四:指定用户是否在线$username = 'user_1111';$online = DB::table('user_login') ->where('username', $username) ->exists();echo $username . ($online ? '在线' : '不在线');

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

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

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

代码如下:

// 客户端唯一的识别码$client_id = session()->getId();echo $client_id . '
'; // 按日期生成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 . '
'; // 可实现功能二:某时间段内在线人数$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 . '
'; // 可实现功能三:最新上线的用户,时间从小到大排序$newest = Redis::zRangeByScore($key, '-inf', '+inf', ['limit' => [0, 50]]);echo '最新上线的用户有:';foreach ($newest as $value) { echo $value . ' ';}echo '
'; // 可实现功能四:指定用户是否在线$username = $client_id;$online = Redis::zScore($key, $client_id);;echo $username . ($online ? '在线' : '不在线') . '
'; // 可实现功能五:昨天和今天都上线的客户$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). "");}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'));

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

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 . '
'; // 可实现功能2:指定用户是否在线$online = Redis::getBit($key, $uid);echo $uid . ($online ? '在线' : '不在线') . '
'; // 可实现功能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 . '
'; // bitmap无法统计具体有哪些用户

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

95fb08dab7413925ca82b623be4d68fa.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值