文档章节

实现统计在线用户的几种方式,欢迎大家发表观点!

钟良
 钟良
发布于 2016/07/15 15:01
字数 2250
阅读 745
收藏 5
点赞 1
评论 0

最近在考虑做个统计在线用户的功能。以前也做过,用的一些比较简单的方法,但是缺点也很明显:精确统计和服务器、数据库压力之间要做出平衡。
所以想找一个既能精确统计又能不占用太多服务器资源的方法。先说说一些平常的做法:

一,每次用户操作更新其在线时间

这个方法很直接,在用户表里加一个字段update_time,每次用户进行操作,都更新这个字段为当前时间,一般是在一个被所有Action继承的基类里写这个操作。
然后定义一个过期时间,比如10分钟,表示10分钟没进行任何操作的用户默认为不在线。这样,统计当前在线用户的sql语句大概是这样

  1. select count(*) from think_user where update_time>now()-10*60

优点:实现简单,通俗易懂
缺点:1,对“在线”的定义模糊,万一用户看一篇文章时间比较长,10分钟内没进行任何操作,他就被忽略了;2,如果user表数据量很大,那效率将极差

二,将在线用户单独放入一张表

对于方法一的改进。新建一张表think_inline,字段有user_id、update_time,每次用户操作时,先判断表里有没有该用户的记录,没有则新增,有就更新update_time。
并同时加上删除失效数据操作

delete from think_inline where update_time<now()-10*60

这样,统计在线就可以直接count这张表就行了。而且这表的数据量不会很大(至少要比用户表小的多)

优点:减少数据库压力
缺点:仍然对“在线”的定义不准确

三,用JS定时器

这个方法是综合了一和二。新建一张表think_inline,也是在基类中定义每次用户操作时更新时间,参考二的做法。
不同之处是,在每个html模板里,加上一个js定时器,setInterval('updateTime', 10*3600);每隔10分钟发送一次ajax请求,更新update_time字段。这样,即使用户在一个页面停留时间过长,也不会被误认为不在线了。并且可以通过减少请求的间隔,来增加精确度,当然了,对服务器的压力就更大了。

优点:对在线的判断较为准确
缺点:仍然不能既精确又不增加服务器压力,必须在两者之间进行取舍。

四,使用TP的SessionDb驱动进行最优化设计


这也就是网上有人说的session存入数据库的方法,这种方法优点很多。

 

 

1,为什么要将session存入数据库?

session是存储在服务器的一组临时数据。一般情况下,我们在做用户登录时,会将用户数据存入session。这样,在任何页面都可以方便调用,而且每个客户端会产生唯一的session_id,不会混肴。并且在关闭浏览器后,服务器会有session回收机制,自动删除过期session。

这是session的优点:唯一性、方便调用、不会过多占用资源。但是也有缺点:在客户端是以cookie方式保存的,禁用cookie就没用了。

那么,服务器是如何存放session的呢?他是默认将session以文件的方式保存在硬盘上的。可是,对于我们码农来说,操作数据库要比读文件方便的多,并且可以对session数据进行各种操作。

而统计在线用户人数就是通过统计有多少条session记录来实现的。

 

 

 

 

 

 

2,如何把session存入数据库?


TP的SessionDb驱动就实现了这个功能。原理就是通过改写PHP默认的session操作来实现,核心函数session_set_save_handler(),有兴趣的可以研究一下。该驱动将session的增、读、取、和删都放入了数据库。
使用方法也很简单:1,建表,驱动的注释里的sql语句运行下就好
2,添加配置:

 

 

 

//Session配置
'SESSION_TYPE'          => 'db',            //数据库存储session
'SESSION_TABLE'         => 'think_session',    //存session的表
'SESSION_EXPIRE'        => 600,                //session过期时间

 

这样,只要我们在程序里使用了session()函数,数据库里就会有记录。

 

3,利用数据库session实现统计在线用户


1,统计在线总人数

  1. $map = array('session_expire'=>array('gt',NOW_TIME));
    $inline = D('Session')->where($map)->count();

     

2,统计游客(未登录)人数

  1. $map = array('session_expire'=>array('gt',NOW_TIME),'session_data'=>array('eq',''));
    $huiyuan = D('Session')->where($map)->count();

     

3,统计会员(已登录)人数

  1. $map = array('session_expire'=>array('gt',NOW_TIME),'session_data'=>array('neq',''));
    $huiyuan = D('Session')->where($map)->count();

     

4,判断一个用户是否在线。
在用户表里新增一个字段:session_id。
(1)在登录操作里,保存该用户的session_id,

  1. $session_id = session_id();
    D('User')->where(array('id'=>$user_id))->save('session_id'=>$session_id);

     

(2)检查session表里是否存在该session_id,未过期并且有值,

  1. $map = array('session_id'=>$session_id,'session_expire'=>array('gt',NOW_TIME),'session_data'=>array('neq',''));
    $res = D('Session')->where($map)->find();
    if($res){
       dump('该用户在线。')
    }else{
       dump('该用户不在线。')
    }

     


码字太麻烦啦,先写这么多,后面总结该方法的几大优点以及注意事项。

 

 

4,总结


1,实现步骤:用户表新增字段保存session_id;使用TP的SessionDb驱动。是不是很简单?

2,优点
(1)比上面三种方法对数据库和服务器的压力都小,操作简单
(2)能够区分在线用户是会员还是游客(session_data字段是否有值),discuz就是这样做的
(3)可以通过删除某用户的session记录,实现将其“踢下线”的功能

3,缺点
(1)仍然不能精确统计,只能说,XX秒内在线多少人

4,注意事项
(1)由于该方法的SessionDb驱动必须使用session()函数才能触发,所以必须配置自动开启session(默认就是开启)。TP在执行流程里会使用session()函数,所以你什么都不写,session数据也会存入数据库。
(2)因为数据库的session数据是不会自己删除的,所以对于过期的数据,必须调用session()方法才会删。
这也就意味着,如果你的网站一个人都没有访问,那么数据库的过期session记录会一直存在。

也就是由于这种机制,对于一些突发事件(用户直接X浏览器、直接关机、发生地震……),在其关闭浏览器的一段时间(session过期时间)后,其他用户对网站的访问,会触发session回收,删除过期记录。所以,就不怕统计出来的数据不准确了。
当然了,就算没人访问,你也可以在count时加上session_expire>time()来统计。

但是也有误差,就是session过期时间,5分钟后过期,就有5分钟的误差。时间设的越小,对数据库的操作就越频繁;越大,精确度就越低。

(3)这个session过期时间就意味着,如果用户5分钟内不进行任何操作,其就会自动退出登录。所以,为了用户体验好,请加上cookie自动登录功能。目前官网就是这么做的。

(4)评论里有人提到,验证码也会存入session,所以我们判断的时候,就不能值统计有值的记录了。
需要先获取有值的数据,再判断里面有没有保存用户信息的参数名。虽然session_data字段是用二进制存储的,但是查询出来就是一个字符串。
比如,我们用的user下标来保存的用户信息,

 

 

  1. session('user',$data);//用户登录信息
    //获取真实会员数
    //查询有值的session记录
    $list = D('Session')->where(array('session_data'=>array('NEQ',''),'session_expire'=>array('lt',NOW_TIME)))->select();
    //判断值里是否有会员标识
    foreach($list as $k=>$value){
      if(strpos($value['session_data'],'user') === false){
                    $count++;
                }
    dump($count);//真实会员人数
    }

     

(5)由于每种浏览器都有各自的session机制,所以,如果一个人在一台电脑上同时开了5种浏览器,则数据库会保存5条不同的记录
实际使用时,仍需要考虑搜索引擎的误差。在其抓取我们的页面时,也会产生session。

 

 

五,最终结论

由于HTTP协议的限制:请求完成后就会断开与客户端的连接。所以实际上,

 

 

我们根本无法精确而实时地统计在线人数


尽管有各种各样的方法来增加统计的精确度,然而都是治标不治本。

唯有放弃HTTP协议,使用“长连接”的链接方式,才能精确判断用户在还是离



至此,完结


后续,官网将推出聊天室的功能,类似于webQQ,更加方便大家的交流。元芳,你怎么看?
 

求“赞”求“收藏”

本文转载自:http://www.thinkphp.cn/topic/3217.html

共有 人打赏支持
钟良
粉丝 8
博文 76
码字总数 30027
作品 0
嘉兴
部门经理
报表讨论区

BI分析平台的价值之一,就是建立一个共享的报表。对于同一个报表内容,不再需要像以前一样,不同的部门各自制作各自的报表,浪费人力资源不说,还可能因为大家统计口径不一致或手工失误造成数...

bjourway
2011/12/23
89
0
练习项目09:在线聊天室(上)

练习项目09:在线聊天室(上) Python自动化运维2018-01-091 阅读 PythonPython教程asyncore 这个练习项目来自《Python基础教程(第2版)》,案例原名为“虚拟茶话会”。 其实,这个项目就是...

Python自动化运维
01/09
0
0
对QQ空间指定好友2017年说说数据的分析

没错,我准备用我高考60分的数学水平以及小学生都不如的表达水平加上只会HELLO WORLD的编程水平来一次关于QQ空间动态的分析。 一、概况 本次爬虫的对象为我学校的一个“表白墙”(以下简称墙...

equationl
01/02
0
0
#ask:关于多设备登录的处理规则

提问:#关于多设备登录# 今天大家讨论了摩拜的小程序,于是我发现一个不太赞同的地方,摩拜的小程序和app是不支持同时登录的,非常不便捷,反而淘宝这种跟钱有关系的app支持多设备登录。那么...

Cxy_ego
2017/05/02
0
0
高性能 NoSQL 数据库--外存

1.什么是外存 Exist 外存本质上是一个内存级别的nosql。 它提出了“面向变量”的数据访问思想,让用户只见变量,不见接口,省去了繁琐的接口调用。 以此实现了逻辑与数据分离的效果,一份单结...

火羽
2014/12/05
492
0
刺客型营销者的神器:如何通过商务拓展获取10倍免费流量

新媒体人都知道,运营有四大目标:拉新、促活、留存、付费转化。为什么80%的新媒体运营文章都会提到拉新? 因为拉新是运营的第一步,如果第一步都做不好,没有取得优质流量,那么你的产品再完...

半撇私塾
04/03
0
0
【收藏】数据分析必备神器

数据可视化工具 百度ECharts:http://http://echarts.baidu.com/ Cytoscape:http://An Open Source Platform for Complex Network Analysis and Visualization 图表秀:http://图表秀--免......

Data Analyst
2017/04/21
0
0
本周推荐7款CSS3实现的动态特效

大家都知道,在网页制作时使用CSS技术,可以有效地对页面的布局、字体、颜色、背景和其它效果实现更加精确的控制。只要对相应的代码做一些简单的修改,就可以改变同一页面的不同部分,或者页...

gbin1
2014/07/18
229
0
爬取简书和数据分析

爬取简书和数据分析 36大数据2017-11-032 阅读 大数据爬虫data 作者:sexycoder 最近入门了一下scrapy,找了一个网站练手,半天的时间爬取了简书20w用户数据和40w的follow关系。这些存在mys...

36大数据
2017/11/03
0
0
机器学习相关——协同过滤

在现今的推荐技术和算法中,最被大家广泛认可和采用的就是基于协同过滤的推荐方法。本文将带你深入了解协同过滤的秘密。下面直接进入正题 1 什么是协同过滤 协同过滤是利用集体智慧的一个典型...

~大器晚成~
2012/02/01
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

CoreText进阶(五)- 文字排版样式和效果

CoreText进阶(五)- 文字排版样式和效果 效果 以下是三个设置了不同属性的效果图 第一个设置了文字颜色为红色,字体为16号 第二个设置了文字颜色为灰色,字体为16号,对其为居中 第三个设置...

aron1992
24分钟前
1
0
10.23 linux任务计划cron~10.27 target介绍

crontab命令被用来提交和管理用户的需要周期性执行的任务,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务工具,并且会自动启动crond进程,crond进程每分钟会定期检查是...

洗香香
35分钟前
0
0
告警系统主脚本、告警系统配置文件、告警系统监控项目

20.20 告警系统主脚本 告警系统主脚本 main.sh内容 #!/bin/bash#Written by aming.# 是否发送邮件的开关export send=1# 过滤ip地址export addr=`/sbin/ifconfig |grep -A1 "en...

lyy549745
38分钟前
0
0
Don’t Repeat Yourself

在软件工程中,Don’t Repeat Yourself(DRY)是软件开发的原则,旨在减少重复,用抽象代替它,使用数据规范化来避免冗余。 这个原则在维基百科上是说是由Andy Hunt和Dave Thomas《The Pragmat...

woshixin
40分钟前
0
0
搭建webpack项目框架

作者:汪娇娇 时间:2018年6月4日 一、说明 随着业务发展和前端人员的增加,搭建一个通用框架以及制定统一规范就成了必然。对于选型这方面,一开始好像就没考虑其他框架,直接选了webpack。w...

娇娇jojojo
47分钟前
0
0
Java基础——面向对象(内部类)

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 内部类: 1.有名内部类 2.无名内部类 内部类申请...

凯哥学堂
55分钟前
0
0
HttpClient内部三个超时时间的区别

RequestConfig requestConfig = RequestConfig.custom() .setConnectionRequestTimeout(config.connReqTimeout) //从连接池中获取连接的超时时间 ......

1713716445
今天
0
0
每天一个命令SCP

每天一个命令:SCP scp是secure copy的简写,用于在Linux下进行远程拷贝文件的命令,和它类似的命令有cp,不过cp只是在本机进行拷贝不能跨服务器,而且scp传输是加密的。可能会稍微影响一下速...

河图再现
今天
0
0
cron/chkconfig/systemd/unit/target

linux任务计划 : cron工具 任务计划在运维工作中用到的比较多,大部分系统管理工作都是通过定期自动执行某个脚本来完成。 查看linux中任务计划的配置文件: /etc/crontab [root@yolks-001 ~]...

Hi_Yolks
今天
1
0
ftp攻略

Vsftpd完全攻略(一)ftp原理与vsftp安装:https://www.iyunv.com/thread-44698-1-1.html Vsftpd完全攻略(二)设置匿名用户也支持下载和上传与创建目录:https://www.iyunv.com/forum.php?mo...

寰宇01
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部