简体   繁体   English

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

[英]Why does PHP occasionally hang on session_start()

NB This is not a dupe of PHP session_start() causing HTTP requests to hang (and other similarly named questions on SO), as my hang is occasional, not permanent. 注意:这不是欺骗PHP session_start()导致HTTP请求挂起 (以及SO上的其他类似命名的问题),因为我的挂起是偶然的,而不是永久性的。

Using Ubuntu 12.04, Magento , PHP-FPM (5.4) and default PHP session handler (with files on ext4). 使用Ubuntu 12.04, MagentoPHP-FPM (5.4)和默认的PHP会话处理程序(ext4上的文件)。

Incidentally (once per month) all PHP processes hang on session_start() (according to fpm-slow.log): 顺便说一句(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 says: 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

According to strace, all these processes are waiting for flock (LOCK_EX) , even the one who has the W flag in the lsof output above. 根据strace,所有这些进程都在等待flock (LOCK_EX) ,甚至是在上面的lsof输出中具有W标志的那个进程。

The CPU usage during this incident is near 0. 此事件期间的CPU使用率接近0。

So why does the first session_start hang, even though it seems to have acquired a write lock on the session file? 那么为什么第一个session_start挂起,即使它似乎已经在会话文件上获得了写锁定? How could I debug this further? 我怎么能进一步调试呢?

Here is a discussion called " race condition with ajax and php sessions ". 这是一个名为“ 带有ajax和php会话的竞争条件 ”的讨论。 In fact, the requests that trigger the problem above, are consistenly AJAX calls. 事实上,触发上述问题的请求是一致的AJAX调用。 However, this article states that: 但是,本文指出:

If you've used PHP's built-in, default session handling (that uses files), you'll never come across the problem. 如果您使用了PHP的内置默认会话处理(使用文件),您将永远不会遇到问题。

So currently I'm at a loss where to look next. 所以目前我不知道接下来要去哪看。

I find it best to store sessions on a local disk and not the database. 我发现最好将会话存储在本地磁盘上而不是数据库中。

Create a directory named 'sessions' at the root directory, and then have all of your sessions write there by putting the following code at the top of scripts right before you call "session_start()" 在根目录下创建一个名为“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/');

Loading from file is faster than loading from a database. 从文件加载比从数据库加载更快。 And php manages it all the same, so I opt for speed. 并且php管理它都是一样的,所以我选择速度。

Something unknown is blocking the first script, and it is blocking the rest. 一些未知的东西阻塞了第一个脚本,它阻止了其余的脚本。

PHP keeps the session file open for writing until after the script terminates. PHP保持会话文件打开以便写入,直到脚本终止。 That means if a script gets stuck or caught up doing something slow, all other requests dependent on the session will be blocked until it finishes. 这意味着如果脚本卡住或陷入缓慢的事情,依赖于会话的所有其他请求将被阻止,直到完成为止。

Two best practices - don't start the session until you need it, and explicitly end the session with session_write_close() when you're done changing it, especially before doing something slow or potentially buggy. 两个最佳实践 - 在您需要之前不要启动会话,并在完成更改后明确地使用session_write_close()结束会话,特别是在执行缓慢或可能错误的操作之前。

Then you'll only have 1 stuck process, instead of a locked out user. 那么你只会有一个卡住的进程,而不是一个被锁定的用户。

On your Ajax calls I'm guessing in that file you have session_start and somewhere in your /tmp directory in your ubuntu php is saving its sessions. 在你的Ajax调用中,我猜你在该文件中有session_start,而你的ubuntu php中的/ tmp目录中的某个地方正在保存其会话。 To solve your issue you need to run load testing against those scripts, it can also be the db that could be a factor in which you can't see with naked eye. 要解决您的问题,您需要针对这些脚本运行负载测试,它也可能是数据库,可能是您无法用肉眼看到的因素。

Try something like this: http://smartbear.com/products/qa-tools/load-testing-tool/ajax-load-testing/ as a trial maybe you can get to the bottom of the problem. 尝试这样的事情: http//smartbear.com/products/qa-tools/load-testing-tool/ajax-load-testing/作为试用,也许你可以找到问题的根源。 You also need to dig deeper into the sessions for that matter including those individual files that uses ajax calls. 您还需要深入研究会话,包括那些使用ajax调用的单个文件。

You should setup some type of performance testing against those calls to the backend that you can run when the problem occurs. 您应该针对发生问题时可以运行的后端调用设置某种类型的性能测试。 The layers are PHP, PHP-FPM, Magento, Im guessing MySQL, Ubuntu, network connection and Apache? 这些层是PHP,PHP-FPM,Magento,我猜MySQL,Ubuntu,网络连接和Apache?

When you have an import script that takes long to execute, the browser seem to lock up and you cannot access the website anymore. 如果您的导入脚本需要很长时间才能执行,那么浏览器似乎已锁定,您无法再访问该网站。 this is because a request is reading and locking the session file to prevent corruption. 这是因为请求正在读取并锁定会话文件以防止损坏。

you can either - use a different session handler with session_set_save_handler() - use session_write_close() in the import script as soon you don't need session anymore (best moment is just before the long during part takes place), you can session_start when ever you want and as many times you like if your import script requires session variables changed. 您可以 - 使用不同的会话处理程序与session_set_save_handler() - 在导入脚本中使用session_write_close(),因为您不再需要会话(最佳时刻就在部分发生之前的最长时刻),您可以在任何时候使用session_start如果您的导入脚本需要更改会话变量,您希望和您喜欢多次。

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

我建议检查magento上的会话表...因为它在mysql表上存储会话你可能有你的db的问题...

A good practice is to install memecached for php and then just set these values: 一个好的做法是为php安装memecached,然后设置这些值:

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

I just read across different platforms because facing the same problem. 我只是阅读不同的平台,因为面临同样的问题。 I read on several pages that the process to clean up the session files is started when you call "session_start()". 我在几个页面上读到,当你调用“session_start()”时,会启动清理会话文件的过程。 You can control how often and in which way the garbage cleaner (gc) cleans in the ini directives of php 您可以控制垃圾清理器(gc)在php的ini指令中清除的频率和方式

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

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