如何高效限制网页最大在线用户数?现有实现方案是否可行?
原方案评估
该方案能实现基础的限制逻辑,但存在严重的性能和可靠性缺陷,不适合生产环境使用:
- 性能极低:每次请求都查持久化数据库,IO延迟高,高并发场景下很容易把数据库打垮,完全撑不起稍大的访问量。
- 核心逻辑不可靠:你不可能在middleware层捕获用户离开页面的动作,用户直接关闭浏览器、断网、页面崩溃时,后端收不到任何通知,数据库里的访问记录会永久留存,时间久了会出现实际在线人数远低于阈值,但所有新用户都被拦截的问题。
- 计数不准:没有做并发控制,多个请求同时查询记录数时,可能都得到未超过阈值的结果,随后同时插入记录,最终实际在线人数超过阈值,限制逻辑失效。
更优实现方案
推荐用Redis + 心跳续期的方案,既保证性能,又解决可靠性问题:
核心逻辑
- 针对每个受限页面,在Redis中创建独立的
Set集合,命名格式示例:restricted:page:[路由标识],集合内存储当前在线用户的唯一标识(推荐用用户ID:设备指纹的格式,避免同一用户多端登录占用多个名额),同时为每个页面单独配置最大在线阈值。 - 每次请求经过middleware时,若为受限路由,直接调用Redis的
SCARD命令查询对应集合的成员数:- 若成员数 ≥ 阈值,直接拦截请求返回提示
- 若成员数 < 阈值,调用
SADD命令将当前用户标识加入集合,同时给该用户标识设置过期时间(比如3分钟)
- 前端受限页面每隔1分钟(短于过期时间即可)向后端发送一次心跳请求,后端收到请求后对应用户在集合内的过期时间重置,只要用户停留在页面上,就不会被自动清理。
- 若用户主动关闭/离开页面,前端可主动发起退出请求,后端调用
SREM将用户标识从集合中移除,加快名额释放。
优势
- 性能提升10倍以上:Redis是纯内存操作,单实例QPS轻松超过10万,完全不会成为性能瓶颈,远优于查持久化数据库的方案。
- 可靠性拉满:即使用户非正常退出,没有发送心跳,对应的用户标识到期后会自动从集合中删除,不会出现永久占坑的问题。
- 天然并发安全:Redis的
SCARD、SADD都是原子操作,不会出现并发场景下计数不准的问题,无需额外加锁。
如果你的场景不需要区分用户,只需要限制页面的总同时在线人数,也可以直接用Redis的INCR/DECR计数器实现,性能更高。
内容的提问来源于stack exchange,提问作者user2810895
相关产品推荐
相关产品推荐

