You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP自定义会话清理函数触发unlink文件不存在警告的排查求助

问题原因

生产环境下php-fpm是多进程模式,多个请求会同时执行自定义会话清理函数,这会触发竞态条件:

  • 进程A通过glob获取到会话文件列表,包含文件X
  • 进程A执行file_exists($file)时返回true,但在调用unlink($file)之前,进程B(或PHP自身的会话GC进程)已经删除了文件X
  • 进程A执行unlink时文件已不存在,因此触发警告

另外,PHP默认的会话垃圾回收机制(session.gc_probability默认不为0)会随机启动清理逻辑,也会和自定义清理逻辑产生冲突,进一步增加报错概率。

解决方案

1. 给unlink添加错误抑制

既然文件不存在属于并发场景下的预期情况,可以直接抑制该警告:

@unlink($file);

2. 删除前再次检查文件状态

在执行unlink前再次验证文件存在性,能大幅降低报错概率:

if ($now - $mfile_time >= SESSION_EXPIRE_SECONDS) {
    // 再次确认文件是普通文件且存在
    if (is_file($file)) {
        unlink($file);
    }
}

3. 禁用PHP默认会话GC

由于已经实现自定义清理逻辑,建议在php.ini或.user.ini中关闭默认GC,避免冲突:

session.gc_probability = 0

4. 改用定时任务清理(推荐)

不在每个请求中执行清理逻辑,改用系统定时任务定期处理,从根源避免并发问题:

  1. 编写独立清理脚本clean_sessions.php:
define("SESSION_SAVE_PATH", "/tmp/my_php_sessions"); 
define("SESSION_EXPIRE_SECONDS", 36000);

if (!is_dir(SESSION_SAVE_PATH)) {
    mkdir(SESSION_SAVE_PATH, 0777, true);
}

$files = glob(SESSION_SAVE_PATH . '/sess_*');
$now = time();
foreach ($files as $file) {
    if (is_file($file) && ($now - filemtime($file) >= SESSION_EXPIRE_SECONDS)) {
        @unlink($file);
    }
}
  1. 添加cron任务,每小时执行一次:
0 * * * * php /path/to/clean_sessions.php
额外排查建议

开发环境无法复现是因为并发量不足,可使用压力测试工具(如ab、wrk)模拟多请求并发,触发竞态条件验证问题。

内容的提问来源于stack exchange,提问作者Sbraaa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 15:15:11