php5.2的卷曲虫服务器被服务器端编程语言(专业超文本预处理器的缩写)进程卡死问题排查
前几天东政同学反馈说利诺德服务器快卡死了,今天有时间排查了一下具体原因,最终原因稍微有点悲壮:文件_获取_内容没有设置超时时间,加上我用的php5.2关于卷曲的代码有个臭虫,于是导致服务器端编程语言(专业超文本预处理器的缩写)进程进入死循环。
今天下午又发现系统负载很高,于是上去看了一下,发现一大坨服务器端编程语言(专业超文本预处理器的缩写)进程没有退出,占用了很多CPU,如图:
问题进程:
后面运行的脚本是我的简易资讯聚合定时更新任务,看来服务器端编程语言(专业超文本预处理器的缩写)代码什么地方有问题,于是strace -p 14043看了一下:
select(5,[4],[4],[],{15,0})=1 (out [4],left {14,99999996 })poll([{ FD=4,events=POLLIN|POLLPRI}],1,0)=0(超时)CLOCK _ gettime(CLOCK _单调,{4582888,760370017 })=0 CLOCK _ gettime(CLOCK _单调,{4582888,760468616)在四号软驱上面死循环了,于是看看软驱是什么:ll /proc/14043/fd
lrwx—— 1吴海文吴海文64 7月21 11:00 4插座:[53176380]
再看了一下原来是在请求CSDN的一个网页的时候死循环了,但不知道什么地方请求的,想到基因组数据库一下服务器端编程语言(专业超文本预处理器的缩写)进程看看英国电信公司显示:
(gdb)Bt # 00x 00007 f 6721 F8 f 013 in _ _ select _ no cancel()at./sysdeps/unix/syscall-template .PHP _ curl _ stream _ read中的s :82 # 1 00000000000481952(stream=02280650,buf=0x 22 ea 5d 0 " 2 fwww。更大队列。com/tag/% E6 % ad % a3 % E5 % 88% 99 ' class=' tag-link-191 ' title=' 3 topics ' style=' font-size:9.0243902439 pt;'>正则 \ '…,计数=8192)在家/吴海文/install/php-env/src/php/PHP-5。2 .8/ext/curl/streams。c :169 # 2 PHP _ stream _ fill _ read _ buffer中的0x 000000006738 F9(流=02280650,大小=4283)在家/吴海文/install/PHP-env/src/PHPJSON/a \ na href=' http://www .更大队列。com/tag/module ' class=' tag-link-43 ' title=' 2 topics ' "……,size=4283)at/home/吴海文/install/PHP-env/src/PHP/PHP-5。2 .8/主干道/溪流/溪流。c :600 # 40x 00000000674 C51 in _ PHP _ stream _ copy _ to _ mem(srmem
看一下当前服务器端编程语言(专业超文本预处理器的缩写)执行的脚步是什么:
(gdb) p *op_array$4={type=2 '\002 ',function _ name=0x1e 54278 ' getContent ',scope=0x1f8e850,fn_flags=257,prototype=0x0,num_args=2,required_num_args=1,arg_info=0x1fd5e20,pass_rest_by_reference=0 '\000 ',return_reference=0 '\000 ',refcount=0x1fd3ab8,操作码=0x 1 FD 3ab back batch _ count=0,done_pass_two=1 '\001 ',使用_ this=0 ' \ 000 ',文件名=0x 1 FD 3b 58 '/home/吴海文/web root/kulvrss/libs/Myrss/Model/URL content er。PHP ',line_start=9,line_end=30,doc_comment=0x0,doc_comment_len=0,保留={0x0,0x0,0x0,0x0}}找到了问题代码位置,原来是一个file_get_contents($url)调用,没有设置超时时间,于是服务器端编程语言(专业超文本预处理器的缩写)卡死在网络请求了。于是用流_上下文_创建设置超时时间搞定。
到这里似乎问题解决了,但是,为什么没有设置超时时间就导致服务器端编程语言(专业超文本预处理器的缩写)进程占用CPU,系统负载那么高?按理说应该等待输入-输出才是呀?看上面中央处理器情况,完全是进入了死循环的节奏。
根据上面的英国电信公司堆栈,首先看倒数第二个函数的调用:
# 1 PHP _ curl _ stream _ read中的0000000000481952(stream=02280650,buf=0x 22 ea 5d 0 " 2fw。序列。com/tag/% E6 % ad % a3 % E5 % 88% 99 ' class=' tag-link-191 ' title=' 3 topics ' style=' font-size:9.0243902439 pt;'>正则\"'…,计数=8192)在家/吴海文/install/PHP-env/src/PHP/PHP-5。2 .8/ext/curl/streams。c :169
看一下代码,我用的事5.2.8版本的PHP,比较老。代码如下:
静态size _ t PHP _ curl _ stream _ read(PHP _ stream * stream,char *buf,size _ t count TSRMLS _ DC){ PHP _ curl _ stream * curl stream=(PHP _ curl _ stream *)stream-抽象;size _ t未读取=0;if(curl stream-read buffer。read pos=curl stream-读取缓冲区。写入pos curl流-挂起){//do {/*从curl */curl _ multi _ fdset(curl stream-multi,curlstream-readfds,curlstream-writefds,curlstream-excfds,curlstream-maxfd)获取描述符;/*如果我们处于阻止模式,请设置超时*/电视。TV _ usec=0;tv.tv _ sec=15/* TODO:允许从脚本中配置此功能*//*等待数据*/switch(select(curl stream-maxfd 1、curlstream-readfds、curlstream-writefds、curlstream-excfds、TV)){ case-1:/* error */return 0;案例0: /*无数据yet:超时*/返回0;default: /*提取数据*/do { curl stream-mcode=curl _ multi _ perform(curl stream-multi,curl stream-pending);} while(curlstream-MC ode==CURLM _ CALL _ MULTI _ PERFORM);} } while(curl流读取缓冲区。read pos=curl stream-读取缓冲区。写入pos curl流-挂起0);}//返回GDB进去发现,代码一直在里面的边做边看里面循环了!心想curl_multi_fdset怎么不用先FD_ZERO清空软驱呢?一般做法都是会先清空的。
莫非是服务器端编程语言(专业超文本预处理器的缩写)的臭虫,于是网上找了一下发现了这个皮尔里克-恰伦的提交,确实是一个臭虫,其实curl_multi_fdset的文档开头写了的:
复制代码代码如下:该函数从给定的多句柄中提取文件描述符信息libcurl .返回其fd_set集。应用程序可以使用这些来选择on(),但是在调用此函数之前,请确保FD_ZERO它们,因为curl_multi_fdset(3)只添加自己的描述符,
好吧,最后用基因组数据库验证一下,我在上面的做下面,curl_multi_fdset调用之前,手动将软驱清空,看看能否退出循环:
(gdb)打印FD_ZERO(curlstream-readfds)当前上下文中没有符号“FD_ZERO”。
FD_ZERO甚至没有。反正本来就是一个宏定义。只需展开:#定义FD _ ZERO (p) bZero ((char *) (p),sizeof (* (p)))
使用call直接修改curl_muti_fdset的三个参数数组,如下所示:
复制代码如下: (gdb)调用bzero((char *)(curl stream-read FDS),sizeof(*(curl stream-read FDS))$ 5=17055392(gdb)调用bzero((char *)(curl stream-write FDS),sizeof(*(curl stream-write FDS))$ 6=17055520(gdb)调用bzero((char *)(curl stream-exc FDS),sizeof
然后GDB介入,按照计划,因为curlstream-pending变成了0,它退出循环,返回到php_stream_fill_read_buffer的大函数
这基本就是结局。有问题的PHP版本应该是5.2。如果不仔细看,读者可以参考上面提交的修改或者直接看看自己的版本代码有没有问题。
版权声明:php5.2的卷曲虫服务器被服务器端编程语言(专业超文本预处理器的缩写)进程卡死问题排查是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。