用Redis怎么快速搞定在线人数统计,实时数据那块其实挺好玩的
- 问答
- 2026-01-12 22:37:37
- 1
这事儿其实挺有意思的,用Redis来做在线人数统计,核心就是利用Redis的两个看家本领:一是速度贼快,所有操作都在内存里完成;二是它提供了几种特别适合这种场景的数据结构,咱们不用扯那些复杂的概念,就聊具体怎么干。
最直接的招数:用 String 类型——简单粗暴
最原始的想法是啥?不就是每个人上线的时候,我在Redis里记录一下,下线的时候删掉嘛,用String类型可以这么玩:给每个用户分配一个唯一的键,user:online:用户ID,值随便设个啥,1”或者“true”,并且给这个键设置一个过期时间,比如30分钟,这个过期时间很关键,它相当于一个“心跳”,如果用户正常下线,我们主动删除这个键;即使用户异常掉线(比如直接关闭浏览器),30分钟后这个键也会自动过期,相当于自动清理。
那统计总在线人数呢?就用Redis的 KEYS 命令,KEYS user:online:*,然后看看返回多少个键就行了。
这个方法有个大问题! KEYS 命令在生产环境是禁用的,因为它会遍历整个数据库的所有键,当你的用户量达到百万、千万级别时,这个操作会直接让Redis卡死,简直就是灾难,这个办法只适合自己写着玩,或者用户量极小的情况,绝对不能用在正经的项目里。

进阶玩法:用 Set 或 Sorted Set——靠谱多了
既然 KEYS 命令不能用,我们就得找能高效统计数量的数据结构,Redis的 Set(集合)就是个好选择。
- 上线:当用户(假设用户ID是123)上线时,执行
SADD online_users 123,这个命令的意思是,向一个名叫online_users的集合里添加成员“123”,如果用户已经在线(即集合里已经有123了),这个操作会自动去重,啥也不干。 - 下线:当用户下线时,执行
SREM online_users 123,从集合里把用户“123”移除。 - 统计:想知道现在有多少人在线?太简单了,执行
SCARD online_users,这个命令能瞬间(O(1)时间复杂度)返回集合里元素的总数,也就是在线人数,速度飞快,不管集合有多大。
这个方法解决了统计的问题,但它还是有个小缺点:依赖客户端“文明”地下线,如果用户突然断网,客户端来不及发送下线的指令,那这个用户就会一直“幽灵在线”,直到你手动处理,为了解决这个问题,我们就需要引入“心跳”机制。
高级玩法:Sorted Set(有序集合)—— 实时性的精髓

这就是你说的“实时数据那块挺好玩的”核心所在了。Sorted Set 不仅能存成员,还能给每个成员关联一个分数(score),我们可以巧妙地利用这个分数来做时间戳。
-
上线和心跳:我们不再区分严格的上线下线动作,而是让用户的浏览器每隔一段时间(比如15秒)就向服务器发一个请求,说“我还活着”,服务器收到这个请求后,就执行一个命令:
ZADD online_users 当前时间戳 用户IDZADD online_users 1717589100 123这个命令的意思是,把用户“123”放入online_users这个有序集合,并且把他的分数设置为当前的时间戳(比如1717589100),如果用户已经存在,ZADD会更新他的分数为最新的时间戳。 -
统计在线人数:什么算在线?我们定义一个规则:最近60秒内有过心跳的用户,就算在线,那么统计命令就变成了:
ZCOUNT online_users (当前时间戳 - 60) +inf解释一下:ZCOUNT是统计分数在某个区间内的成员数量。(1717589100 - 60)表示60秒前的时间戳(注意小括号表示开区间,不包含这个临界值),+inf表示正无穷,这个命令的意思就是:找出所有分数大于60秒前时间戳的成员,也就是所有在最近60秒内更新过心跳的用户,然后统计他们的数量,这个操作也非常高效。 -
自动清理僵尸用户:有了时间戳,我们还可以定时任务,自动清理那些长时间没有心跳的“僵尸用户”:
ZREMRANGEBYSCORE online_users -inf (当前时间戳 - 60)这个命令会删除所有分数小于60秒前时间戳的成员,也就是清理掉超过60秒没心跳的用户,保持集合的干净。
这个方法的好处是真正的实时和健壮,它不依赖用户的正常下线,能容忍网络抖动,只要用户还在活跃,他的时间戳就会不断刷新;一旦他失联,超过指定时间就会被自动移出在线列表。
再来个妙用:HyperLogLog——海量数据的统计神器
你可能不需要知道精确的“此时此刻”的在线人数,而是想统计“今天一天的独立在线用户数”这种指标,用户量特别大的时候,用Set或Sorted Set可能会占用很多内存,这时候就可以祭出Redis的“概率性数据结构”——HyperLogLog。
HyperLogLog的特点是:它用来统计一个集合中不重复元素的个数,但牺牲了精确度,换来了极小的内存占用(每个HyperLogLog键只需要约12KB内存,就能统计接近2^64个不重复元素)。
- 操作:每天创建一个新的HyperLogLog键,
uv:20240605,每当有用户访问时,就执行PFADD uv:20240605 用户ID。 - 统计:一天结束后,执行
PFCOUNT uv:20240605,就能得到当天的去重在线用户数,这个数字可能有个1%左右的误差,但在亿级流量的场景下,用微小的误差换来巨大的内存节省和性能提升,是完全值得的。
总结一下
所以你看,用Redis搞在线人数统计,就像玩积木一样,有不同的组件可以选择:
- 要简单、精确地统计当前在线人数,用 Set,配合上下线通知。
- 要做得更实时、更健壮,能应对异常掉线,用 Sorted Set,配合心跳机制,这是最好玩也最常用的方式。
- 要统计海量数据下的历史独立用户数(比如日活),不计较一点点误差,就用 HyperLogLog 来省内存。
这些东西组合起来,就能轻松应对各种场景下的计数需求了,而且速度都飞快,这正是Redis的魅力所在。
本文由寇乐童于2026-01-12发表在笙亿网络策划,如有疑问,请联系我们。
本文链接:https://haoid.cn/wenda/79571.html
