当前位置:首页 > 问答 > 正文

怎么用Redis快速查到最近在线的用户,精准又高效的方法分享

要快速精准地查到最近在线的用户,一个在Redis里被广泛使用且高效的方法是使用有序集合(Sorted Set),这个方法的思路非常直接,就像我们给每个用户的最后一次在线时间点贴上一个时间戳标签,然后根据这个时间戳进行排序,轻松找出最新的那些。

核心思想:把时间戳当分数

Redis的有序集合有一个关键特性:集合里的每个成员(member)都对应一个分数(score),并且所有成员会按照这个分数从小到大进行排序,我们可以巧妙地利用这个特性:

  • 成员(member):设置为用户的唯一标识符,比如用户ID(uid)。
  • 分数(score):设置为用户最后一次活动的时间戳,这个时间戳最好用Unix时间戳,也就是从1970年1月1日到现在经过的秒数或毫秒数,它是一个持续增大的数字,非常适合用来排序。

这样,每当用户有任何活动(比如登录、点击页面、发送消息),我们就去更新这个有序集合。

具体操作步骤

  1. 记录用户在线状态: 当用户上线或者有活动时,执行一条Redis命令,根据博客“Redis台湾”和许多开发者社区的讨论,最常用的命令是ZADDZADD recent_users 1717589123 user123 这条命令的意思是,向名为recent_users的有序集合中添加一个成员user123,并将其分数设置为1717589123(这个数字代表某个具体时间点),如果user123已经存在于集合中,这条命令也会更新它的分数为新的时间戳,这正好符合我们的需求:总是记录最近一次的活动时间。

  2. 查询最近在线用户: 现在我们想找出最近10分钟内在线过的用户,假设当前的时间戳是1717589723(即上面例子中的时间点往后大约10分钟)。

    • 计算一个时间点:当前时间戳 - 10分钟(600秒),所以临界时间点就是 1717589723 - 600 = 1717589123
    • 使用Redis的ZREVRANGEBYSCORE命令,这个命令的意思是:在有序集合中,按照分数从大到小(反向排序)的范围查询,因为我们想把最新的(分数最大的)用户排在前面。 命令如下:ZREVRANGEBYSCORE recent_users +inf 1717589123 解释一下:
    • +inf 代表正无穷,意思是分数上限是无限大,即包含所有比临界值大的分数。
    • 1717589123 就是我们计算出的10分钟前的时间戳,作为分数的下限。 这条命令会返回所有在最近10分钟内有活动的用户ID列表,并且是按照活动时间从新到老的顺序排列的。

如何让方案更精准和健壮?

上面的基础方法已经很快了,但为了更精准(避免查到已注销用户)和更高效(避免集合无限膨胀),可以做一些优化,在“付磊和张益军所著的《Redis开发与运维》”一书中提到了类似的思路,并强调了定期清理的重要性。

  1. 处理已注销或无效用户: 如果某个用户注销了账号,我们不应该再在“最近在线用户”里看到他,这时,只需要使用ZREM命令将其从有序集合中移除即可:ZREM recent_users user123,这保证了查询结果的精准性。

  2. 定期清理过期数据(关键优化): 如果网站用户量巨大,且运行时间很长,recent_users这个集合会变得非常大,里面可能保存着好几年前登录过的用户记录,虽然Redis速度很快,但维护一个过大的集合还是会浪费内存,并且查询效率也会逐渐下降。 解决方法很简单:在每次执行查询操作的同时,进行一次数据清理,我们可以修改一下查询命令,一次性完成两件事: ZREMRANGEBYSCORE recent_users -inf (1717589123 这条命令会删除所有分数小于 1717589123(也就是10分钟前)的成员,这里的符号表示不包含临界值本身,避免误删刚好在10分钟整那个时间点活动的用户。 最佳实践是,在查询“最近在线用户”之前之后,先执行这条清理命令,这样,这个有序集合的大小基本会维持在与“最近活跃用户数量”相当的级别,不会无限增长,从而保证了长期运行下的高效性,这个方法在“阿里云开发者社区”的一篇关于用户会话管理的文章中被重点推荐。

为什么这个方法又快又好?

  • 速度快:Redis的所有这些操作(ZADD, ZREVRANGEBYSCORE, ZREMRANGEBYSCORE)的时间复杂度都是O(log(N)),这意味着即使集合里有数百万用户,查找和更新的速度也极其快,因为它是基于跳跃表(Skip List)等高效数据结构实现的。
  • 精准:通过更新时间戳和移除无效用户,可以真实反映最近的活跃用户情况。
  • 节省内存:通过定期清理旧数据,防止了内存的无谓消耗。

总结一下完整流程:

  1. 用户活动时:ZADD recent_users <当前时间戳> <用户ID>
  2. 查询前(可选,用于优化):ZREMRANGEBYSCORE recent_users -inf (<查询时间点> 清理过期用户。
  3. 查询最近N分钟在线的用户:ZREVRANGEBYSCORE recent_users +inf <N分钟前的时间戳>

这个方法被广泛应用于各种需要“最近活跃”、“最新登录”、“实时在线”功能的场景,是经过实践检验的经典方案。

怎么用Redis快速查到最近在线的用户,精准又高效的方法分享