session_start()卡死、session锁定导致并发阻塞 解决办法
今天测试网站多并发的时候,发现网站好卡的,感觉php不能够这么慢呀,然后拼命找原因
通过php-fpm慢日志查看发现:
Fatal error: Maximum execution time of 30 seconds exceeded in thinkphp\library\think\Session.php on line 534
找到第534行
/**
* 启动session
* @access public
* @return void
*/
public function start()
{
session_start();
$this->init = true;
}
通过上图就知道我使用的ajax进行异步获取数据时,一个页面中存在2个ajax异步执行!
根据观察ajax.php:
第一个ajax请求发起成功,这个请求得php运算100秒后才返回结果。
第二个ajax在第一个请求发起后也跟随发起请求,第二个请求php运算10秒就可以发回结果,但是结果却是得第一个请求完全执行完成返回结果后第二个才跟随返回。
原因:
原因在于:执行session_start()后,对应的session文件是被锁定的,直到当前脚本结束才会解锁。
session数据被锁定以防止并发写入,所以任何时候只有一个脚本可以在session上运行。
定期间,另一个进程访问相同session id 要等文件解锁后session_start()才会开始。
为了证明猜测是对的
写了一下两个文件
index1.php
<?php
echo 123;
session_start();
sleep(60*60);
echo 456;
die;
index2.php
<?php
echo 789;
session_start();
echo 456789;
die;
先执行 index1.php, 然后在执行index2.php
以下是index2.php的执行结果,因为index1.php需要执行1小时.
789
Fatal error: Maximum execution time of 30 seconds exceeded in E:\phpStudy\WWW\index2.php on line 3
解决办法
办法也非常简单,开启session后,做了相应的操作,一定要关闭session;
例如:只需要在 session 设置好数据后调用, session_write_close() 将数据写入文件并且结束session;
PHP示例代码如下:
<?php
session_start();
$_SESSION["count"]=1;
session_write_close();
sleep(10);
如果不加入session_write_close();并发3个进程访问该页面,第一个进程执行10秒 第二个执行20秒 第三个执行30秒。
加入session_write_close()后 ,并发3个进程会同时在10秒后执行完成!
要么你就把session存redis或者memcache,这样不会出现文件锁,这种最保险了.