A few days ago Dong classmate Feedback said Linode server Fast card died, today have time to check the specific reasons, the ultimate reason slightly a bit solemn and stirring: file_get_contents did not set the timeout time, Plus the php5.2 I used for the Curl code has a bug that causes the PHP process to go into a dead loop.
This afternoon again found the system load is very high, so went up to look, found a large pile of PHP process did not quit, occupy a lot of CPU, as shown:
Issue process:
After running the script is my RSS Timer update task, it seems that the PHP code where there is a problem, so strace-p 14043 looked at:
Select (5, [4], [4], [], {, 0}) = 1 (out [4], left {999996})
poll ([{fd=4, events=pollin| POLLPRI}], 1, 0) = 0 (Timeout)
clock_gettime (clock_monotonic, {4582888, 760370017}) = 0
clock_gettime (clock_ Monotonic, {4582888, 760468615}) = 0
clock_gettime (clock_monotonic, {4582888, 760565053}) = 0
Select (5, [4], [4] , [], {0}) = 1 (out [4], left {14, 999997})
The cycle is dead on the 4th fd, so see what FD is: ll/proc/14043/fd
Lrwx--1 Wuhaiwen Wuhaiwen 64 July 11:00 4-> socket:[53176380]
Again look at the original is in the request csdn a Web page when the dead loop, but do not know what place to request, think of gdb a look at the PHP process, BT display:
(GDB) bt
#0 0x00007f6721f8f013 in __select_nocancel (). /sysdeps/unix/syscall-template. s:82
#1 0x0000000000481952 in Php_curl_stream_read (stream=0x2280650,
Buf=0x22ea5d0 "2fwww.laruence.com%2ftag%2f%25e6%25ad%25a3%25e5%2588%2599%27+class%3d%27tag-link-191%27+title%3d %273+topics%27+style%3d%27font-size%3a+9.0243902439pt%3b%27%3e%e6%ad%a3%e5%88%99%3c%2fa%3e%3c%2ftags%3e\ "" ..., count=8192) at/home/wuhaiwen/install/php-env/src/php/php-5.2.8/ext/curl/streams.c:169
#2 0x00000000006738f9 in Php_stream_fill_read_buffer (stream=0x2280650, size=4283) at/home/wuhaiwen/install/php-env/ src/php/php-5.2.8/main/streams/streams.c:554
#3 0x0000000000673c39 in _php_stream_read (stream=0x2280650,
Buf=0x2301fd5 "f= ' Http://www.laruence.com/tag/json ' class= ' tag-link-79′title= ' 3 topics ' style= '" Font-size: 9.0243902439pt; ' >json</a>\n<a href= ' http://www.laruence.com/tag/module ' class= ' tag-link-43′title= ' 2 topics ' "..., size= 4283) at/home/wuhaiwen/install/php-env/src/php/php-5.2.8/main/streams/streams.c:600
#4 0x0000000000674c51 in _php_stream_copy_to_mem (src=0x2280650, buf=0x7fff376ed898, maxlen=<optimized Out> persistent=0)
at/home/wuhaiwen/install/php-env/src/php/php-5.2.8/main/streams/streams.c:1267
#5 0x00000000005fdb85 in zif_file_get_contents (ht=<optimized out>, return_value=0x2223da0, return_value_ptr= <optimized Out>, this_ptr=<optimized out>, return_value_used=<optimized out>)
at/home/wuhaiwen/install/php-env/src/php/php-5.2.8/ext/standard/file.c:565
#6 0x00000000006c2a59 in Zend_do_fcall_common_helper_spec (EXECUTE_DATA=0X7FFF376EDC60) at/home/wuhaiwen/install/ php-env/src/php/php-5.2.8/zend/zend_vm_execute.h:200
#7 0x00000000006c239f in Execute (op_array=0x1f26730) at/home/wuhaiwen/install/php-env/src/php/php-5.2.8/zend/zend_ vm_execute.h:92
·············
#16 0x0000000000730d8e in Main (argc=4, argv=0x7fff376f2468) At/home/wuhaiwen/install/php-env/src/php/php-5.2.8/sapi /cli/php_cli.c:1133
Take a look at the current steps in PHP execution:
(GDB) p *op_array
$ = {type = 2 ' \002 ', function_name = 0x1e54278 "GetContent", scope = 0x1f8e850, Fn_flags = 257, PR Ototype = 0x0, Num_args = 2, Required_num_args = 1, Arg_info = 0x1fd5e20,
pass_rest_by_reference = 0 ' \000 ', return_re ference = 0 ' \000 ', refcount = 0x1fd3ab8, opcodes = 0X1FDDCC8, last =, size =, VARs = 0x1fd3cc0, Last_var = 6, Size_ var = =, T =
Brk_cont_array = 0x0, Last_brk_cont = 0, Current_brk_cont = 4294967295, Try_catch_array = 0x0, last_ Try_catch = 0, Static_variables = 0x0, Start_op = 0x0, Backpatch_count = 0,
done_pass_two = 1 ' \001 ', uses_this = 0 ' \ , filename = 0x1fd3b58 "/home/wuhaiwen/webroot/kulvrss/libs/myrss/model/urlcontenter.php", Line_start = 9, Line_ end = Doc_comment = 0x0,
doc_comment_len = 0, reserved = {0x0, 0x0, 0x0, 0x0}}
Found the problem code location, originally a file_get_contents ($url) call, did not set the timeout time, so PHP card died in the network request. Then use stream_context_create set timeout time to fix.
It seems to be a problem here, but why is the timeout not set to cause the PHP process to occupy CPU, the system load is so high? I'm supposed to be waiting for I/O, right? Look at the above CPU situation, is completely into the rhythm of the dead cycle.
Based on the above BT Stack, first look at the last call to the second function:
#1 0x0000000000481952 in Php_curl_stream_read (stream=0x2280650,
Buf=0x22ea5d0 "2fwww.laruence.com%2ftag%2f%25e6%25ad%25a3%25e5%2588%2599%27+class%3d%27tag-link-191%27+title%3d %273+topics%27+style%3d%27font-size%3a+9.0243902439pt%3b%27%3e%e6%ad%a3%e5%88%99%3c%2fa%3e%3c%2ftags%3e\ "" ..., count=8192) at/home/wuhaiwen/install/php-env/src/php/php-5.2.8/ext/curl/streams.c:169
Look at the code, I used the thing 5.2.8 version of PHP, relatively old. The code is as follows:
Static size_t Php_curl_stream_read (Php_stream *stream, Char *buf, size_t count tsrmls_dc) {Php_curl_stream *curlstre
AM = (Php_curl_stream *) stream->abstract;
size_t didread = 0; if (curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pending) {/
/········ Do {/* get the descriptors from Curl * * Curl_multi_fdset (Curlstream->multi, &CURLSTREAM-&G
T;readfds, &curlstream->writefds, &curlstream->excfds, &CURLSTREAM->MAXFD);
/* If we are in blocking mode, set a timeout */tv.tv_usec = 0; Tv.tv_sec = 15; /* Todo:allow this to is configured from the script *///wait for data */switch (select Curlstr
EAM->MAXFD + 1, &curlstream->readfds, &curlstream->writefds, &curlstream->excfds, &TV)) {
CASE-1: * * error/Return 0; Case 0:/* No data yet:timed-out * * return 0; Default:/* Fetch the data */do {Curlstream->mcode =
Curl_multi_perform (Curlstream->multi, &curlstream->pending);
while (Curlstream->mcode = = Curlm_call_multi_perform); } while (Curlstream->readbuffer.readpos >= curlstream->readbuffer.writepos && curlstream->pe
nding > 0);
}
//··········
return didread; }
GdB went in to find that the code has been inside the do-while inside the loop! Thought Curl_multi_fdset why not first Fd_zero empty the FD? The general practice is to be emptied first.
Is it a PHP bug, so the internet to find a bit found this pierrick-charron commit, is indeed a bug, in fact, curl_multi_fdset the beginning of the document wrote:
Copy Code code as follows:
This function extracts the file descriptor information from a given multi_handle. Libcurl returns its fd_set sets. The application can use is on, but is sure to fd_zero them before calling this function as Curl_multi_fdset (3) only adds its own descriptors,
OK, finally with GDB to verify that I am in the above do, Curl_multi_fdset, before the call, manually empty the FD to see if you can exit the loop:
(gdb) Print Fd_zero (&curlstream->readfds)
No symbol "Fd_zero" in the current context.
Fd_zero unexpectedly did not, regardless of, it is a macro definition, expand on the line: #define Fd_zero (P) bzero ((char *) (p), sizeof (* (P))
The three parameter arrays that directly modify Curl_muti_fdset with Call are as follows:
Copy Code code as follows:
(GDB) Call Bzero ((char *) (&CURLSTREAM->READFDS), sizeof (* (&CURLSTREAM->READFDS))
$ = 17055392
(GDB) Call Bzero ((char *) (&CURLSTREAM->WRITEFDS), sizeof (* (&CURLSTREAM->WRITEFDS))
$ = 17055520
(GDB) Call Bzero ((char *) (&CURLSTREAM->EXCFDS), sizeof (* (&CURLSTREAM->EXCFDS))
$ $ = 17055648
GdB then steps forward, as scheduled due to the curlstream->pending into 0, thus exiting the loop, back to the Php_stream_fill_read_buffer large function
To this end basically. The PHP version of the problem should be 5.2. The reader can refer to the above submission changes or directly to see if there is a problem with your version code.