关于php session文件锁机制引发的问题和定位过程
2016-06-14 14:38
537 查看
关于php session文件锁机制引发的问题和定位过程
1. 问题描述
php提供一个web服务,接受客户端请求后,用curl同时发出约10个web请求,请求的是同一个主域名下的服务。但是,该域名只有一台机器。2. 问题现象
php接受到请求后,用curl将web请求并发发出去后,无法收到回包数据,所有请求无一成功。curl_multi_exec 貌似无法从该函数中得到错误码(待确认),排查起来不太方便。3. 解决过程
3.1. 看log发现封装的curl并发库没打log,无法知道curl到底有啥错误原因。事实上curl似乎也没有什么地方可以打出有价值的log
3.2. 抓包
第一次抓包就不上图了,因为很简单:域名解析失败。请求的域名是公司内部域名,在机器上没有配host时是访问不了的。两个解决方法:1. 在curl内指定ip访问,带上host信息,需要改代码,而且有点死板;2. 找运维在内部dns服务器上加上域名信息。
选第二种吧。
3.3. 域名解决后,还是失败。继续抓包
这次截图下来,以便记录。注意:一个是请求时间,一个是错误码。错误码499(客户端主动关闭边接),发送客户端的字节数为0。时间对不上,抓包看到的请求到达nginx的时间与nginx打印access log的时间差了10秒。这10秒刚好是请求方curl中设置的默认超时时间。
于是情况基本认定是:客户端用curl并发发出请求,请求正常到达nginx端,但请求送到后端php后而一直在等待。而后客户端超时,主动关闭连接。nginx收到关闭连接的请求,结束往后端php的发送,打印access log,错误码为499。
php为什么挂起着,无法处理请求?
因为并发了有10个请求过来,难道是php-fpm进程不够,处理不了?按理即便处理不了,也不至于10个请求无一成功。但不管它,在开发环境先修改php-fpm.conf配置,调大进程数。果然错误依旧。
继续排查,php-fpm进程到底在干啥?
上strace吧。找一个php-fpm进程,查看进程号,starce -v -tt -p {进程号} ,结果如下(略去一堆前置后置信息,主要看请求到nginx的这个时间点,它在干啥):
.
看时间点差不多,其实php已经收到请求了,那它在干啥?再往下,
就是在这里了!从11秒到22秒,堵了10秒多的时间!flock 显而易见,这是在加锁。什么操作会加锁?往上看到有 open("/tmp/sess_...") 的文件操作,这是php的session文件(php的session机制,session默认保存在本机文件,如果没指定目录,默认在/tmp/目录下)。open session文件是什么时候操作的?session_start() 函数。该函数会检查传入的session_id,如果传入有session_id,那么尝试从session文件中还原session信息。如果没有则新创建一个。这个是php
session机制决定的。
为什么会加锁?回想起来,因为需要登录态,那10来个并发的curl请求都设置了cookie信息,都是同一个帐号的cookie信息,并且因为只有1台web服务器,所有的请求最终都落在同一台机器上,就是发起者自身这台机器,而发起者在发出curl请求之前,已经session_start()了。难道是发起者session_start() 后,会锁定session文件,等请求结束后才会释放?如果是这样,就可以解释为什么所有发出的curl请求都失败了,因为php收到curl的请求都,调用session_start()后,获得session信息,然后尝试加锁,但失败了!全部都锁在这行
flock 上了!
赶紧查下session_start 函数的信息。本来想查看源码,但这个好像比较痛苦,php函数对应的c++源码,层层跟进不太易找(主要是之前没太找过,不熟悉这个套路),先php.net看看手册:http://php.net/manual/zh/function.session-start.php:
看样子确实有锁机制!我们的session_start没有传参数,read_and_close 默认选项是False?
关键字 session_start read_and_close 来google,搜到如下信息(url不贴了,里面有不少广告):
发现原来这个配置是从php7才开始的,我们才php5。看到有 session_write_close() 函数,跟 read_and_close 效果类似,拿来试试,在发起curl 请求前一试,果然成功!
那么问题就在这里了。再google多一点,发现一篇文章:
http://konrness.com/php5/how-to-prevent-blocking-php-requests/ 讲得通俗易懂。
可以收工了。但回想起来,为什么查了这么久?还是因为对 php 的 session 机制不够熟悉,不然一切都不需要了。
问题虽然解决了,但session还有几种不同的处理方式,比如自定义handler等,其实顺便也可以一并了解清楚,说不定以后再踩坑呢。
相关文章推荐
- 一个关于if else容易迷惑的问题
- Linux socket 初步
- Linux Kernel 4.0 RC5 发布!
- linux lsof详解
- linux 文件权限
- Linux 执行数学运算
- 10 篇对初学者和专家都有用的 Linux 命令教程
- PHP5.2.*防止Hash冲突拒绝服务攻击的Patch
- 深入理解PHP之匿名函数
- Linux 与 Windows 对UNICODE 的处理方式
- Ubuntu12.04下QQ完美走起啊!走起啊!有木有啊!
- 解決Linux下Android开发真机调试设备不被识别问题
- 运维入门
- 运维提升
- Linux 自检和 SystemTap
- Ubuntu Linux使用体验
- 在软件部署中使用 strace 进行调试