本篇文章给大家带来了关于PHP的相关知识,其中主要介绍了怎么实现统计在线人数的问题,可以利用表统计方式、用redis有序集合统计、用hyperloglog做统计等等,下面一起来看一下,希望对大家有帮助。
一个业务系统网站每天人数的访问量是多少,在线人数是多少?这种业务我们在开发中就要预留,也是在我们的设计范围内的咯!因为一个正在运营的网站,每天都会用到统计。
那在线人数是如何统计的呢,这里有几种方案,代码用 laravel 框架。可以作为开发中参考。
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-dH:i:s'),'update_time'=>date('Y-m-dH:i:s')];DB::table('user_login')->insert($data);}else{//存在则更新用户登录信息DB::table('user_login')->where('token',$client_id)->update(['update_time'=>date('Y-m-dH: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-dH:i:s'),'update_time'=>date('Y-m-dH:i:s')];DB::table('user_login')->insert($data);}else{//存在则更新用户登录信息DB::table('user_login')->where('token',$client_id)->update(['update_time'=>date('Y-m-dH:i:s')]);}
我们可以实现的功能:
1)当前在线人数
2)某时间段内在线人数
3)最新上线的用户
4)指定用户是否在线
//可实现功能一:当前总共在线人数$c=DB::table('user_login')->count();echo'当前在线人数:'.$c.'<br/>';//可实现功能二:某时间段内在线人数$begin_date='2020-08-1309:00:00';$end_date='2020-08-1318: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($newestas$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-1309:00:00';$end_date='2020-08-1318: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($newestas$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($membersas$value){echo$value.'';}
3 使用 hyperloglog 做统计
跟有序集合方式不同,hyperloglog 十分节约空间,但是实现的功能也非常单一,只能统计在线人数,不能实现其余的任何功能。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
//noteHyperLogLog只需要知道在线总人数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);//note3daystotalonlinenumvar_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 消耗的内存空间不多, 统计的信息却挺多的,这种方案是值得推荐一下的。
产品猿社区致力收录更多优质的商业产品,给服务商以及软件采购客户提供更多优质的软件产品,帮助开发者变现来实现多方共赢;
日常运营的过程中我们难免会遇到各种版权纠纷等问题,如果您在社区内发现有您的产品未经您授权而被用户提供下载或使用,您可按照我们投诉流程处理,点我投诉;
本文来自用户发布投稿,不代表产品猿立场 ;若对此文有疑问或内容有严重错误,可联系平台客服反馈;
部分产品是用户投稿,可能本文没有提供官方下下载地址或教程,若您看到的内容没有下载入口,您可以在我们产品园商城搜索看开发者是否有发布商品;若您是开发者,也诚邀您入驻商城平台发布的产品,地址:点我进入;
如若转载,请注明出处:https://www.chanpinyuan.cn/27357.html;