B/S架构如何统计用户在线时长、在线人数?

目录

一、问题背景:       

二、需求梳理:

三、提供3个方案思路,由简到繁,根据项目情况选择:

四、方案分析:

        方案一:

        方案二:

        方案三:


一、问题背景:
       

        项目上想要统计用户的平均在线时长,和在线人数,同时做到用户15分钟不操作后,自动掉线, 保存用户在线时长。本文仅提供问题分析思路,具体实现方式自行百度。

二、需求梳理:

  1. 用点击登录开始计时
  2. 用户退出登录或不操作15分钟后结束计时
  3. 用户关闭浏览器,再打开浏览器,间隔不超过15分钟记为同一次登录,累加时间

三、提供3个方案思路,由简到繁,根据项目情况选择:

  1. 心跳机制,前端页面定时发送心跳到后端服务。
  2. redis监听key过期机制
  3. websocket  连接断路机制

四、方案分析:

        方案一:

        用户浏览器在登录后,前端js有个定时器,定时向后端提交一个请求,表示该用户浏览器正在这个页面上,后端定义一个池子,就根据用户id区分记录本次和上次发送时间的时间差, 如果时间小于15分钟就累加 如果大于15分钟就重新开始累计时长,

那假设 原本5分钟发一次, 客户端下线了, 后端现在收不到消息了,需要再起定时任务收集这些超过15分钟没有收到消息的用户和时长记录下来

小结:是个办法 不过这样频繁的请求给服务器带来额外压力,并且如果分布式环境下需要考虑池子定义的位置、前端定时发送的时间长短影响着服务器的压力和统计的及时性。         

        方案二:

        redis 监听过期key  ,redis组件提供一个监听器 KeyExpirationEventMessageListener ,可以在用户登录时,创建一个过期时间15分钟的缓存记录,当缓存失效时会触发监听器,通过当前时间减去起始时间,可以计算出在线时长。

方案步骤:

  1. 用户登录成功, 创建一个redisA (key-value) 不设置失效时间   key为 token, value为用户信息(refere , loginTime等)  同时创建一个 redisB(key-value)  key为 token  vlue为null  失效时间为15分钟
  2. 用户操作 更新以用户id为key的redisB记录的失效时间15分钟
  3. 用户退出登录,更新以用户id为key的redisB记录过期时间为1s
  4. 用户15分钟不操作, 监听器捕获到失效的key  redisB的token 根据此token 查询redisA 知道下线用户的具体信息 完成

方案不足:

  • 这个监听器的触发不稳定,并发量大时有延迟 。(参考文章:请勿过度依赖Redis的过期监听-阿里云开发者社区 (aliyun.com))
  • 并且在监听器里只能拿到redis的key 拿不到value,需要额外建立一个相同的key-value保存数据  
  • 并且监听器不支持事务,可能导致两个redis列表不一致  如:如果用两个key-value 就会出现一个删掉了另一个还没删掉时宕机了 导致不一致 。 或 redisB失效前服务器宕机了,重启后redisB已经失效,但是另一个key-value却没有清除 等异常问题,需要补充大量策略  

优化方案步骤:

  1. 用户登录成功, 创建一个redis (key-value) 失效时间15分钟   key为  【用户id_登录时间戳_refere】 value为用户信息  (只创建一个缓存列表存储,省去列表不对照问题)
  2. 用户操作 更新以用户id为key的记录的失效时间15分钟
  3. 用户退出登录,更新以用户id为key的记录过期时间为1s
  4. 用户15分钟不操作, 监听器捕获到失效的key (用户id  )知道此用户下线了
  5. 只要知道用户上线的时间(也存在key中),就可以用当前时间减去上线时间, 然后加上当前用户id 保存完整记录   

优化方案存在问题:

  • 这个方案避免了上述缓存列表的不一致产生的问题,不用补充策略,但是key上能存储的信息有限
  • 并且考虑到安全性,建议将userid加密后再使用
  • 分布式情况下还存在多个监听器同时监听到失效的key 会执行多次业务的问题 (可以考虑将多个服务监听的结果存进redis 如hset : (name : key :value) 来去重

        方案三:

         通过websocket实现, 在登录成功后,前端发起一个长连接,连接监听 onclose事件内记录时长。

        存在的问题:

  •  每个客户端都建立连接,要建立太多的长连接,资源损耗严重。
  •  并且关闭页签就触发了onclose,重新打开页签时业务上是免登陆的, 但是没有触发登录的事件,没办法继续累计时长。
  • 如果业务中有打开新的页面,原始页面关闭会导致长连接中断一样会计时错误。
  • chrome浏览器某些版本无法触发onclose事件 ,需要另外定义一个小的心跳请求作为中断监听。

小结:好像问题比较多,未知问题也比较多,不建议。

总结:根据不同的项目可以选择不同的方案,目前来看redis监听key失效的方案相对较优,但当出现并发量更大时,需要再具体升级解决方案。最终感谢大佬 国哥 的理论分析支持~~


关于B/S架构 如何做在线时长的统计分析方案, 也希望大家能给出更好的建议

 

你可能感兴趣的:(学习记录,架构,前端)