我们的php应用程序在apache下运行,有时会试图锁定已删除的会话文件,这会挂起apache进程,最终我们会耗尽进程。
证据:
strace : flock(89, LOCK_EX -----stuck in flock for File Descriptor 89
然后:
lsof,对于相同的过程:
httpd 22161 apache 89u ... /var/lib/php/session/sess_mf7svvirg7rbu9l0m5999pm6h4 (deleted)
关于为什么会发生这种情况,有什么想法吗?我们能做些什么来防止它?
我遇到过一个与您的症状相同的问题,只是会话文件是否被删除无关紧要(可能对您来说也是如此——您有证据表明会话文件的删除与flock
有关吗?)。
在我的案例中,这是两个脚本之间访问同一会话文件的竞争条件:
/page1.php
在加载时执行良好。它包括对/background.php
执行XMLHttpRequest的javascript- 当访问
/background.php
时,它运行readfile(http://remote.url)
,这是一个不存在的URL - 当导航到
/page2.php
时,脚本将被搁置。strace显示flock(89, LOCK_EX
,lsof表示它正在等待对会话文件的读/写访问
在这种情况下,/page2.php
和/background.php
都在等待同一个会话文件,但后者无法这样做,因为它在等待readfile()
超时。我在php_error_log
:中得到了这个
PHP Warning: readfile(http://remote.url): failed to open stream: Connection timed out in […]/background.php on line […]
因此,问题出在一个与被认为是罪魁祸首的剧本完全不同的剧本上。
您可以通过grepping php会话文件的所有打开的文件来快速检查这个问题,以查看哪个httpd进程正在使用它:
$ sudo lsof | grep sess_it9q6kkvf83gcj72vu05p9fcad7
httpd 31325 apache 74u REG 8,5 410 11634061 /var/lib/php/session/sess_it9q6kkvf83gcj72vu05pfa543
httpd 31632 apache 74uW REG 8,5 410 11634061 /var/lib/php/session/sess_it9q6kkvf83gcj72vu05pfa543
如果两个httpd进程正在访问同一个会话文件,那么这可能是您的问题。现在,您可以使用strace检查这些过程在做什么,或者在我的情况下,使用apachectl fullstatus
:就足够了
$ sudo apachectl fullstatus | grep 31632
5-7 31632 0/1/1169 _ 0.05 6 30692 0.0 0.02 3.45 111.222.333.444 www.example.com.com /background.php
是否有任何巨大的(客户端)需要删除会话文件?你不应该那样做。PHP本身实现了一种垃圾收集机制来删除不起作用的会话文件。它将比使用PHP编写的任何其他东西都要高效得多。
您可以使用:
- session_destroy--销毁注册到会话的所有数据
- session_unset-释放所有会话变量
然后再次执行session_start()。
点击此处查看更多信息。
更新:
PHP是一个非常干净的脚本引擎,它不会在您的系统中留下垃圾!达到会话超时后,会话文件将自动删除。session-timeout
可能是你的系统的情况,我想是的。因此,如果超时设置为20分钟,文件将在上次访问后20分钟被删除。饼干也是如此。每次请求页面时,cookie ttl都设置为现在+20分钟。
查看一些配置指令。很可能您已经将gc_maxlifetime设置为一个非常高的值,而它们根本没有达到要自动收集的"过期"限制。您应该检查您的应用程序,以确保它们在运行时没有为会话设置(使用ini_set()
)设置奇怪的值。
PHP有一个在session_start()
上运行的内部算法,它决定是否应该运行垃圾清理并删除旧的会话文件。出于性能原因,我认为每次运行的默认机会是1%,因此平均每100个session_start()调用中就会启动一次垃圾收集例程。如果发现这还不够,可以将gc_disper设置提高到高于1的值。
这可能更适合您的情况,但为什么不将会话从文件系统完全迁移到数据库呢?
你可以在这里获得更多信息http://php.net/manual/en/function.session-set-save-handler.php
你试过读取那两个打开的bug吗?
https://bugs.php.net/bug.php?id=47640https://bugs.php.net/bug.php?id=32092
试着调用session_write_close()(丑陋的解决方法)作为最后一行,或者升级PHP。
不知道您的案例的原因。
这个问题得到了一些很好的建议。。。
您是否尝试重新安装环境,或移动到其他服务器?如果您否决了默认的会话处理程序,并使用fopen($file,'w')而不是fopen($file,'x'),它会起作用吗?
此外,实现基于数据库的会话处理程序的解决方法,例如,有一百万左右的指南来设置"php和mysql会话处理程序"。