如何用 PHP 统计网站当前在线人数_基于 Redis 的 Set 集合实现

云杰君_6094

云杰君_6094

2026-04-23

617人浏览

原创

不能直接用$_session统计在线人数,因其依赖文件存储、gc机制不可控、多机不共享,且session_start()不等价于用户在线;redis set配合ttl实现“写入即续期”,scard可准确获取实时在线数。

如何用 php 统计网站当前在线人数_基于 redis 的 set 集合实现

为什么不能直接用 $_SESSION 统计在线人数 PHP 的 $_SESSION 默认存文件,生命周期依赖 session.gc_maxlifetime,但实际用户关闭浏览器后 session 文件不会立刻删除,且多机部署时 session 文件不共享。更关键的是,session_start() 本身不等于“用户在线”——可能只是偶然刷新、爬虫触发、或 AJAX 心跳未清理。 Redis 的 SET 集合天然适合去重 + 过期管理:每个用户用唯一标识(如 user:123sess:abc456)作为成员,设置 TTL,到期自动剔除,SCARD 一次返回准确基数。

实操建议:

  • 不要用 IP 做 key —— 内网 NAT、移动网络出口 IP 大量复用,会导致严重低估
  • 优先用登录态中的 user_id;未登录用户可用 session_id() + setcookie() 确保客户端持久携带
  • 每次用户有活跃行为(页面加载、API 请求)都执行一次 SETEXEXPIRE 延长 TTL,而非只在首次访问设值

如何用 Redis SET 实现带心跳的在线统计 核心逻辑是“写入即续期”,不是“上线写、下线删”。因为 HTTP 无连接状态,你无法可靠捕获“下线”事件,但可以高频确认“还活着”。

示例代码片段(PHP + predis):

// 每次请求都执行(放在公共入口或中间件)
$redis = new Predis\Client(['scheme' => 'tcp', 'host' => '127.0.0.1', 'port' => 6379]);
$userKey = 'online:user:' . ($userId ?: 'guest:' . session_id());
$redis->setex($userKey, 300, 1); // 5 分钟过期

// 统计总数(注意:这是实时近似值,非强一致)
$onlineCount = $redis->scard('online:set'); // ❌ 错!SET 集合名不能和成员混用

正确做法是把所有在线 key 归到一个集合里:

Redis Skill - 高性能缓存管理
Redis Skill - 高性能缓存管理

Redis 缓存和数据结构管理技能。通过自然语言操作 Redis,支持 String、Hash、List、Set、ZSet、Stream 等数据结构操作。当用户提到 Redis、缓存、消息队列、会话存储时使用此技能。

下载
  • SADD online:users $userKey 添加成员(不是 setex)
  • 同时用 EXPIRE $userKey 300 单独设 TTL
  • 但这样需额外维护:当 $userKey 过期,它不会自动从 online:users 中移除

更稳妥的方案是放弃集合嵌套,改用 SCAN 扫描前缀 + TTL 校验(适合中小流量),或直接用 KEYS online:user:*(仅开发环境,生产禁用)。

高并发下 SCARD 不准?那是 key 设计错了 常见错误是把所有用户塞进同一个 Redis SET,比如 SADD online:all user:1 user:2 user:3,然后靠 SCARD online:all 获取总数。这看似合理,但问题在于:

Redis 的 SET 成员是字符串,如果你用 user:1 作为 member,那没问题;但若误写成 SADD online:all "user:1"(加了引号),实际存的是带引号的字符串,导致重复添加不生效。

  • 检查是否真正在添加:用 SMEMBERS online:all 查看实际成员
  • 避免用动态拼接导致空格/换行混入:trim($uid) 必须做
  • 如果用 user_id,注意类型统一——123"123" 在 Redis 是两个不同 member
  • 别在循环里反复 SCARD,它 O(1),但频繁调用仍增加 Redis 负载;可考虑每 10s 缓存一次结果到本地变量或 APCu

线上必须加的兜底与监控项 Redis 故障时,SCARD 报错或返回 0,不能让整个网站挂掉或显示“0 人在线”。

实操建议:

  • 封装统计函数,捕获 Predis\Connection\ConnectionException,降级返回缓存值或 -1(表示不可用)
  • INFO keyspace 定期检查 db0:keys=xxx,expires=yyy,确保过期 key 数量接近总 key 数,否则说明续期逻辑失效
  • 给每个 online:user:* key 设置相同 TTL 后,观察 redis-cli --bigkeys 是否出现异常大 key —— 可能是未登录用户疯狂刷出新 session_id
  • 如果用 Nginx + PHP-FPM,注意 session.cookie_httponlysession.cookie_samesite 配置,否则跨域请求拿不到 session_id,导致 guest 用户重复计入
Redis 的 SET 看似简单,但在线统计真正难的不是命令怎么写,而是“什么才算在线”这个定义是否经得起压测、断网、多标签页、隐身模式的反复验证。多数线上事故,都出在续期时机太松或 key 命名太随意。

php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!

相关文章

PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

php redis

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
php文件怎么打开
php文件怎么打开

打开php文件步骤:1、选择文本编辑器;2、在选择的文本编辑器中,创建一个新的文件,并将其保存为.php文件;3、在创建的PHP文件中,编写PHP代码;4、要在本地计算机上运行PHP文件,需要设置一个服务器环境;5、安装服务器环境后,需要将PHP文件放入服务器目录中;6、一旦将PHP文件放入服务器目录中,就可以通过浏览器来运行它。

2023.09.01

9064

6

php怎么取出数组的前几个元素
php怎么取出数组的前几个元素

取出php数组的前几个元素的方法有使用array_slice()函数、使用array_splice()函数、使用循环遍历、使用array_slice()函数和array_values()函数等。本专题为大家提供php数组相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

5501

5

php反序列化失败怎么办
php反序列化失败怎么办

php反序列化失败的解决办法检查序列化数据。检查类定义、检查错误日志、更新PHP版本和应用安全措施等。本专题为大家提供php反序列化相关的文章、下载、课程内容,供大家免费下载体验。

2023.10.11

2015

5

php怎么连接mssql数据库
php怎么连接mssql数据库

连接方法:1、通过mssql_系列函数;2、通过sqlsrv_系列函数;3、通过odbc方式连接;4、通过PDO方式;5、通过COM方式连接。想了解php怎么连接mssql数据库的详细内容,可以访问下面的文章。

2023.10.23

3408

4

php连接mssql数据库的方法
php连接mssql数据库的方法

php连接mssql数据库的方法有使用PHP的MSSQL扩展、使用PDO等。想了解更多php连接mssql数据库相关内容,可以阅读本专题下面的文章。

2023.10.23

4074

6

html怎么上传
html怎么上传

html通过使用HTML表单、JavaScript和PHP上传。更多关于html的问题详细请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.03

3191

9

PHP出现乱码怎么解决
PHP出现乱码怎么解决

PHP出现乱码可以通过修改PHP文件头部的字符编码设置、检查PHP文件的编码格式、检查数据库连接设置和检查HTML页面的字符编码设置来解决。更多关于php乱码的问题详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.09

4537

8

php文件怎么在手机上打开
php文件怎么在手机上打开

php文件在手机上打开需要在手机上搭建一个能够运行php的服务器环境,并将php文件上传到服务器上。再在手机上的浏览器中输入服务器的IP地址或域名,加上php文件的路径,即可打开php文件并查看其内容。更多关于php相关问题,详情请看本专题下面的文章。php中文网欢迎大家前来学习。

2023.11.13

3542

8

sprintf函数用法详解
sprintf函数用法详解

sprintf函数的用法:1、格式化字符串;2、指定输出宽度和精度;3、返回值。更多关于sprintf函数用法详解的内容,大家可以阅读下面的文章。

2023.11.27

11582

4

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
墨刀帮助中心
墨刀帮助中心

共0课时 | 0人学习

MyEclipse学习中心
MyEclipse学习中心

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习