一个利用redis zset统计在线用户数的方法.

摘要: 对于物联网设备,现在的应用程序倾向于使用Heartbeat来识别用户是否在线。用户登录后,每隔一段时间向服务器推送一条消息,表示当前用户在线。服务端可以定义一个时间差,例如:如果在5分钟内收到客户端的心跳消息,则视为在线用户

对于物联网设备,现在的应用程序倾向于使用Heartbeat来识别用户是否在线。用户登录后,每隔一段时间向服务器推送一条消息,表示当前用户在线。服务端可以定义一个时间差,例如:如果在5分钟内收到客户端的心跳消息,则视为在线用户。


一. 用数据库实现

这是一种比较偷懒的方法,服务端每次收到心跳,就更新数据库表的记录,特别是最后更新时间字段。当查询有多少设备在线的时候,只需要用SQL 语句筛选出最后更新时间在最近5分钟时间之内即可。但这种方式,不是很好的方式,数据库表更新频繁,效率低下。因为心跳导致索引经常在更新。


二. 用Redis zset实现

这是一个比较理想的实现方式,redis基于内存读写,性能自然比关系型数据库好很多,而且它提供的Zset为在线用户搭建统计服务非常方便。

zset 里面有一个score,表示权重,用它来存储心跳的时间。那么判断用户设备是否在线,完全可以通过查询zset里面是否有这个记录,并用score与当前时间对比,在心跳间隔范围内,那么就当做在线的。如果要查询所有的在线设备列表,完全可以通过zset zrange 命令获取在一定区间内的score的成员列表。而且还可以做到分页查询。


zset 基本用法:

添加元素

ZADD key score member [score member ...]

一次向集合中添加一个或多个元素,如果member已经存在,则当前score 进行叠加

计算所有元素 ZCARD key

统计分值在 min 和 max 之间的元素个数

ZCOUNT key min max

删除分值在 min 和 max 之间的元素

ZREMRANGEBYSCORE key min max

利用zset提供的方法,自己写一个类:

@Component
public class OnlineUserStatsService {
    
    private static final String ONLINE_USERS = "onlie_users";

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    
    // 增加在线用户
    public Boolean online(Integer userId) {
        return this.stringRedisTemplate.opsForZSet().add(ONLINE_USERS, userId.toString(), Instant.now().toEpochMilli());
    }
    
    // 特定时间范围内的数量
    public Long count(Duration duration) {
        LocalDateTime now = LocalDateTime.now();
        return this.stringRedisTemplate.opsForZSet().count(ONLINE_USERS, 
                                    now.minus(duration).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), 
                                    now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
    }
    
    // 总数量,与时间无关
    public Long count() {
        return this.stringRedisTemplate.opsForZSet().zCard(ONLINE_USERS);
    }
    
    // 清除时间范围内的数据。
    public Long clear(Duration duration) {
        return this.stringRedisTemplate.opsForZSet().removeRangeByScore(ONLINE_USERS, 0, 
                LocalDateTime.now().minus(duration).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
    }
}

调用方法就可以实现统计在线用户总数,分页,删除等操作。

另外为了防止zset里面数据过多,可以在每天晚上空闲时间,删除过期的数据。做一个定时任务来操作。

上一篇: springboot 读取资源文件
下一篇: Redis与lua脚本配合操作zset的简单例子
 评论 ( What Do You Think )
名称
邮箱
网址
评论
验证
   
 

 


  • 微信公众号

  • 我的微信

站点声明:

1、一号门博客CMS,由Python, MySQL, Nginx, Wsgi 强力驱动

2、部分文章或者资源来源于互联网, 有时候很难判断是否侵权, 若有侵权, 请联系邮箱:summer@yihaomen.com, 同时欢迎大家注册用户,主动发布无版权争议的 文章/资源.

3、鄂ICP备14001754号-3, 鄂公网安备 42280202422812号