用 set 维护在线用户统计需以唯一 id(如 userid、jwt sub)为键,通过 add/delete 实时更新;配合心跳机制防误判离线;集群部署须用 redis 替代内存 set 或结合 pub/sub 同步;id 必须服务端校验,避免客户端伪造。

用 JavaScript 的 Set 维护在线用户统计,核心是利用其自动去重、O(1) 查找与增删的特性,配合实时事件(如连接建立/断开、心跳上报)动态更新。
用 Set 存储用户唯一标识
每个用户用稳定且全局唯一的 ID 标识,比如后端下发的 userId、JWT 中解析出的 sub,或 WebSocket 连接时分配的会话 ID。避免用临时生成的随机数或客户端 IP(易重复或不准确)。
- 初始化一个全局
Set:const activeUsers = new Set(); - 用户上线(如 WebSocket
connection事件触发):activeUsers.add(userId); - 用户下线(
close或disconnect事件):activeUsers.delete(userId);
结合心跳机制防误判离线
单纯依赖连接关闭事件不可靠(网络闪断、客户端崩溃无通知)。需搭配定时心跳:
- 客户端每 15–30 秒发送一次
ping心跳包,服务端记录该用户的最后活跃时间 - 另起一个定时器(如每分钟执行),遍历所有已知用户,检查
lastActiveTime是否超时(如 > 60 秒) - 对超时用户调用
activeUsers.delete(userId),并清理其状态缓存
注意跨实例部署时的共享问题
单机 Node.js 进程中的 Set 是内存级的,无法在多进程或多服务器间同步。生产环境必须外置共享存储:
- 用 Redis 的
SET数据结构替代 JSSet:使用redis.sadd("active_users", userId)和redis.srem("active_users", userId) - 若仍想用 JS
Set做本地缓存,可配合 Redis Pub/Sub:各实例监听用户上下线事件,本地Set仅作快速读取副本,写操作统一走 Redis - 绝对不要在集群中各自维护独立的
Set并直接返回size—— 结果会严重失真
安全与边界处理
用户 ID 必须由服务端可信来源生成或校验,不能直接信任客户端传入的字段:
- WebSocket 握手时通过 token 验证身份,再提取真实
userId - 每次
add前可做基础校验(如非空、字符串长度、正则格式),防止异常值污染集合 - 定期用
activeUsers.size输出日志或上报监控,发现突增突降时及时排查(如爬虫伪造连接、前端 bug 导致重复登录)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











