繁体   English   中英

php正在锁定已删除的会话文件

[英]php is locking a deleted session file

我们的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吗?)。

就我而言,在两个脚本之间访问同一会话文件是一种竞争条件:

  1. /page1.php在加载时执行正常。 它包括对/background.php执行XMLHttpRequest的javascript。
  2. 当访问/background.php ,它运行readfile(http://remote.url) ,这是一个不存在的URL。
  3. 导航到/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 […]

所以问题在于与完全不同的脚本而不是感知到的罪魁祸首。

您可以通过浏览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自己编写的任何其他内容更有效

您可以使用:

  1. session_destroy - 销毁注册到会话的所有数据
  2. session_unset - 释放所有会话变量

并再次执行session_start()。

在这里查看更多。

更新:

PHP是一个非常干净的脚本引擎,它不会在您的系统上留下垃圾! 达到会话超时后会自动删除会话文件。 session-timeout可能是您的系统的情况我认为如此。 因此,如果超时设置为20分钟,则文件将在上次访问后20分钟删除。 对于cookie也是如此。 每次请求页面时,cookie-ttl设置为现在+ 20分钟。

查看一些配置指令 可能性是您已将gc_maxlifetime设置为非常高的值,并且它们根本没有达到“到期”限制以自动收集。 您应该检查您的应用程序,以确保它们没有在运行时为会话设置设置奇怪的值(使用ini_set() )。

PHP有一个内部算法,在session_start()上运行,决定它是否应该执行垃圾清理运行并删除旧的会话文件。 出于性能原因,我认为每次运行的默认机会是1%,因此平均每100个session_start()调用将启动一次垃圾收集例程。 如果您发现这还不够,可以将gc_divisor设置提高到高于1的值。

不知道为什么你的情况。

这个问题得到了一些好的建议......

您是否尝试重新安装环境或迁移到其他服务器? 如果你否决了默认会话处理程序并使用fopen($ file,'w')而不是fopen($ file,'x'),它会工作吗?

此外,基于数据库实现会话处理程序的解决方法,例如,有一百万左右的指南来设置“php和mysql会话处理程序”。

对于您的情况,这可能更像是一种解决方法,但为什么不将会话从文件系统迁移到数据库呢?

你可以在这里获得更多信息http://php.net/manual/en/function.session-set-save-handler.php

你有没有尝试过阅读这两个漏洞?

https://bugs.php.net/bug.php?id=47640 https://bugs.php.net/bug.php?id=32092

尝试调用session_write_close()(丑陋的解决方法)作为最后一行或升级PHP。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM