B/S架构如何统计用户在线时长在线人数?
Posted zprealm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了B/S架构如何统计用户在线时长在线人数?相关的知识,希望对你有一定的参考价值。
目录
一、问题背景:
项目上想要统计用户的平均在线时长,和在线人数,同时做到用户15分钟不操作后,自动掉线, 保存用户在线时长。本文仅提供问题分析思路,具体实现方式自行百度。
二、需求梳理:
- 用点击登录开始计时
- 用户退出登录或不操作15分钟后结束计时
- 用户关闭浏览器,再打开浏览器,间隔不超过15分钟记为同一次登录,累加时间
三、提供3个方案思路,由简到繁,根据项目情况选择:
- 心跳机制,前端页面定时发送心跳到后端服务。
- redis监听key过期机制
- websocket 连接断路机制
四、方案分析:
方案一:
用户浏览器在登录后,前端js有个定时器,定时向后端提交一个请求,表示该用户浏览器正在这个页面上,后端定义一个池子,就根据用户id区分记录本次和上次发送时间的时间差, 如果时间小于15分钟就累加 如果大于15分钟就重新开始累计时长,
那假设 原本5分钟发一次, 客户端下线了, 后端现在收不到消息了,需要再起定时任务收集这些超过15分钟没有收到消息的用户和时长记录下来
小结:是个办法 不过这样频繁的请求给服务器带来额外压力,并且如果分布式环境下需要考虑池子定义的位置、前端定时发送的时间长短影响着服务器的压力和统计的及时性。
方案二:
redis 监听过期key ,redis组件提供一个监听器 KeyExpirationEventMessageListener ,可以在用户登录时,创建一个过期时间15分钟的缓存记录,当缓存失效时会触发监听器,通过当前时间减去起始时间,可以计算出在线时长。
方案步骤:
- 用户登录成功, 创建一个redisA (key-value) 不设置失效时间 key为 token, value为用户信息(refere , loginTime等) 同时创建一个 redisB(key-value) key为 token vlue为null 失效时间为15分钟
- 用户操作 更新以用户id为key的redisB记录的失效时间15分钟
- 用户退出登录,更新以用户id为key的redisB记录过期时间为1s
- 用户15分钟不操作, 监听器捕获到失效的key redisB的token 根据此token 查询redisA 知道下线用户的具体信息 完成
方案不足:
- 这个监听器的触发不稳定,并发量大时有延迟 。(参考文章:请勿过度依赖Redis的过期监听-阿里云开发者社区 (aliyun.com))
- 并且在监听器里只能拿到redis的key 拿不到value,需要额外建立一个相同的key-value保存数据
- 并且监听器不支持事务,可能导致两个redis列表不一致 如:如果用两个key-value 就会出现一个删掉了另一个还没删掉时宕机了 导致不一致 。 或 redisB失效前服务器宕机了,重启后redisB已经失效,但是另一个key-value却没有清除 等异常问题,需要补充大量策略
优化方案步骤:
- 用户登录成功, 创建一个redis (key-value) 失效时间15分钟 key为 【用户id_登录时间戳_refere】 value为用户信息 (只创建一个缓存列表存储,省去列表不对照问题)
- 用户操作 更新以用户id为key的记录的失效时间15分钟
- 用户退出登录,更新以用户id为key的记录过期时间为1s
- 用户15分钟不操作, 监听器捕获到失效的key (用户id )知道此用户下线了
- 只要知道用户上线的时间(也存在key中),就可以用当前时间减去上线时间, 然后加上当前用户id 保存完整记录
优化方案存在问题:
- 这个方案避免了上述缓存列表的不一致产生的问题,不用补充策略,但是key上能存储的信息有限
- 并且考虑到安全性,建议将userid加密后再使用
- 分布式情况下还存在多个监听器同时监听到失效的key 会执行多次业务的问题 (可以考虑将多个服务监听的结果存进redis 如hset : (name : key :value) 来去重
方案三:
通过websocket实现, 在登录成功后,前端发起一个长连接,连接监听 onclose事件内记录时长。
存在的问题:
- 每个客户端都建立连接,要建立太多的长连接,资源损耗严重。
- 并且关闭页签就触发了onclose,重新打开页签时业务上是免登陆的, 但是没有触发登录的事件,没办法继续累计时长。
- 如果业务中有打开新的页面,原始页面关闭会导致长连接中断一样会计时错误。
- chrome浏览器某些版本无法触发onclose事件 ,需要另外定义一个小的心跳请求作为中断监听。
小结:好像问题比较多,未知问题也比较多,不建议。
总结:根据不同的项目可以选择不同的方案,目前来看redis监听key失效的方案相对较优,但当出现并发量更大时,需要再具体升级解决方案。最终感谢大佬 国哥 的理论分析支持~~
关于B/S架构 如何做在线时长的统计分析方案, 也希望大家能给出更好的建议
如何统计网站在线人数?
参考技术A Redis字符串中的setbit key offset value(0,1)命令可以对字符串对象对应的位进行二进制赋值。用户的登陆状态可以用一个bit来表示,这样1亿个用户所需的内存空间仅为10M左右。具体实现:首先在redis中初始化字符串:setbit loginstatus 10000 0。在中间件上,当用户登陆认证完成时,获取用户uid并在redis上设置登陆状态setbit loginstatus uid 1。获取在线用户数量实现:bitcount loginstatus,前端ajax轮询访问接口获取数据。
# 计算出 7 天都在线的用户BITOP"AND""7_days_both_online_users""day_1_online_users""day_2_online_users"..."day_7_online_users"# 计算出 7 在的在线用户总人数BITOP"OR""7_days_total_online_users""day_1_online_users""day_2_online_users"..."day_7_online_users"# 计算出两天当中只有其中一天在线的用户BITOP"XOR""only_one_day_online""day_1_online_users""day_2_online_users"
以上是关于B/S架构如何统计用户在线时长在线人数?的主要内容,如果未能解决你的问题,请参考以下文章