PHP - 会话对象销毁失败

PHP - Session object destruction failed

我在 Symfony 上遇到了一个奇怪的问题:基本上有时,没有任何明显的原因,用户无法加载网页,直到我重新启动 php-fpm 或直到他更改它的 PHPSESSID 加载新会话。反正重启fpm后他的session还是正常的

同时,我收到了来自PHP的2条警告:

PHP Warning: session_start(): Session object destruction failed in /home/unix/releases/1/vendor/symfony/symfony/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php on line 145

PHP Warning: session_start(): Failed to decode session object. Session has been destroyed in /home/unix/releases/1/vendor/symfony/symfony/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php on line 145

考虑到我们谈论的是最多 2-3 个用户同时使用的私人网站,但如果只有 1 个用户在上面导航,也可能会发生这种情况。

当前设置是

我可以通过 apache ab 使用相同的会话 ID 同时调用不同的 URL 来重现该问题。当然在 N 请求后我超时了:

Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
apr_pollset_poll: The timeout specified has expired (70007)
Total of 872 requests completed

现在我正在尝试检查 php 配置,但实际上 "normal" 没有特殊设置,所以我不知道应该尝试或检查什么。有什么想法吗?

问题

终于找到问题所在了。基本上它来自 Symfony 本身,因为默认情况下它似乎也在 Symfony/Component/HttpFoundation/Session/Storage/Handler/StrictSessionHandler.php

中实现了某种 garbage collection logic
public function gc($maxlifetime)
{
    return $this->handler->gc($maxlifetime);
}

如果 /var/lib/php/sessions/ 目录属于 php.ini 中定义的同一用户,或者如果它具有 read 权限,这将不是问题,但是默认该目录属于 root 用户且不可读(因此无法列出文件)。当 Symfony 尝试在当前会话处理程序上调用垃圾收集器时,这会导致异常。


解决方案

有两种解决方法:设置

session:
    gc_probability: ~

在 Symfony config.yml 中或添加 read 权限到 PHP 会话目录(或最终使用 php.ini 中定义的相同更改相关用户).希望它能对某人有所帮助。