为什么PHP偶尔挂在session_start()上

时间:2014-09-24 12:49:42

标签: php magento session

注意这是不是 PHP session_start() causing HTTP requests to hang(以及其他类似命名的问题)的欺骗,因为我的挂起是偶然的,而不是永久性的。

使用Ubuntu 12.04, MagentoPHP-FPM (5.4)和默认的PHP会话处理程序(包含ext4上的文件)。

顺便说一下(once per month)所有PHP进程都挂在session_start()上(根据fpm-slow.log):

[24-Sep-2014 11:03:04]  [pool www] pid 24259
script_filename = /data/web/public/index.php
[0x00007f00b4ec6480] session_start() /data/web/public/includes/src/__default.php:7687
[0x00007f00b4ec6130] start() /data/web/public/includes/src/__default.php:7730
[0x00007f00b4ec5fb8] init() /data/web/public/includes/src/__default.php:8086
[0x00007f00b4ec5e30] init() /data/web/public/includes/src/__default.php:33902
[0x00007f00b4ec5bd0] __construct() /data/web/public/includes/src/__default.php:23841
[0x00007f00b4ec5ae8] getModelInstance() /data/web/public/app/Mage.php:463
[0x00007f00b4ec59c8] getModel() /data/web/public/app/Mage.php:477
[0x00007f00b4ec49a0] getSingleton() /data/web/public/includes/src/__default.php:14044
[0x00007f00b4ec4848] preDispatch() /data/web/public/includes/src/Mage_Adminhtml_Controller_Action.php:160
[0x00007f00b4ec3b00] preDispatch() /data/web/public/includes/src/__default.php:13958
[0x00007f00b4ec26e0] dispatch() /data/web/public/includes/src/__default.php:18331
[0x00007f00b4ec20c0] match() /data/web/public/includes/src/__default.php:17865
[0x00007f00b4ec1a98] dispatch() /data/web/public/includes/src/__default.php:20465
[0x00007f00b4ec1908] run() /data/web/public/app/Mage.php:684
[0x00007f00b4ec17f8] run() /data/web/public/index.php:87

Lsof说:

COMMAND    PID USER   FD   TYPE DEVICE SIZE/OFF    NODE NAME
php5-fpm 24259  app   10uW  REG  202,1    82492 1220594 /data/web/public/var/session/sess_gr2clur9icgd7s2j9linag7ue6
php5-fpm 24262  app   10u   REG  202,1    82492 1220594 /data/web/public/var/session/sess_gr2clur9icgd7s2j9linag7ue6
php5-fpm 24351  app   10u   REG  202,1    82492 1220594 /data/web/public/var/session/sess_gr2clur9icgd7s2j9linag7ue6
php5-fpm 24357  app   10u   REG  202,1    82492 1220594 /data/web/public/var/session/sess_gr2clur9icgd7s2j9linag7ue6
php5-fpm 24358  app   10u   REG  202,1    82492 1220594 /data/web/public/var/session/sess_gr2clur9icgd7s2j9linag7ue6
php5-fpm 25563  app   10u   REG  202,1    82492 1220594 /data/web/public/var/session/sess_gr2clur9icgd7s2j9linag7ue6
php5-fpm 25564  app   10u   REG  202,1    82492 1220594 /data/web/public/var/session/sess_gr2clur9icgd7s2j9linag7ue6

根据strace,所有这些进程都在等待fl (LOCK_EX),甚至是在上面的lsof输出中有W标志的那个。

此事件期间的CPU使用率接近0.

那么为什么第一个session_start会挂起,即使它似乎已经在会话文件上获得了写锁定?我怎么能进一步调试呢?

以下是一个名为“race condition with ajax and php sessions”的讨论。事实上,触发上述问题的请求是一致的AJAX调用。但是,本文指出:

  

如果您使用过PHP的内置默认会话处理(使用   文件),你永远不会遇到这个问题。

所以目前我无法去寻找下一个目标。

7 个答案:

答案 0 :(得分:1)

我发现最好将会话存储在本地磁盘上而不是数据库中。

在根目录下创建一个名为'sessions'的目录,然后在调用“session_start()”

之前将以下代码放在脚本顶部,让所有会话都写在那里
$session_path = $_SERVER['DOCUMENT_ROOT']; //this session path assumes you are not using a subdomain
ini_set('session.save_path', $session_path.'/sessions/');

从文件加载比从数据库加载更快。并且php管理它都是一样的,所以我选择速度。

答案 1 :(得分:1)

未知的东西阻挡了第一个脚本,它阻止了其余的脚本。

PHP保持会话文件打开以便写入,直到脚本终止。这意味着如果脚本卡住或陷入缓慢的事情,依赖于会话的所有其他请求将被阻止,直到完成为止。

两个最佳实践 - 在您需要之前不启动会话,并在您完成更改时明确地使用session_write_close()结束会话,尤其是在做一些缓慢或可能有错误的事情之前。

然后你只会有一个卡住的进程,而不是一个被锁定的用户。

答案 2 :(得分:0)

在你的Ajax调用中,我猜你在该文件中有session_start,而你的ubuntu php中的/ tmp目录中的某个地方正在保存其会话。要解决您的问题,您需要针对这些脚本运行负载测试,它也可能是数据库,可能是您无法用肉眼看到的因素。

尝试这样的事情:http://smartbear.com/products/qa-tools/load-testing-tool/ajax-load-testing/作为试用版,也许你可以找到问题的根源。您还需要深入研究会话,包括那些使用ajax调用的单个文件。

您应该针对发生问题时可以运行的后端调用设置某种类型的性能测试。这些层是PHP,PHP-FPM,Magento,我猜MySQL,Ubuntu,网络连接和Apache?

答案 3 :(得分:0)

当您的导入脚本需要很长时间才能执行时,浏览器似乎已锁定,您无法再访问该网站。这是因为请求正在读取并锁定会话文件以防止损坏。

你也可以 - 使用session_set_save_handler()使用不同的会话处理程序 - 一旦你不再需要会话,就在导入脚本中使用session_write_close()(最好的时刻就在部分发生之前的最长时间),你可以在任何你想要的时候使用session_start,如果你需要你可以多次使用session_start脚本需要更改会话变量。

http://php.net/manual/en/function.session-start.php

答案 4 :(得分:0)

我建议检查关于magento的会话表... 因为它在mysql表上存储会话,所以你的数据库可能有问题......

答案 5 :(得分:0)

一个好的做法是为php安装memcached,然后设置这些值:

session.save_handler = memcache
session.save_path = “tcp://127.0.0.1:11211″

答案 6 :(得分:0)

我只是在不同的平台上阅读,因为面临相同的问题。我在几页上读到,当您调用“ session_start()”时,将开始清理会话文件的过程。您可以在the ini directives of php

中控制垃圾清理器(gc)清理的频率和方式