Do you think PHP will continue to perform after deep analysis of the browser exit _php instance

Source: Internet
Author: User
Tags flock flush fpm php script sleep

Premise: Here is the typical LNMP structure, the NGINX+PHP-FPM model

If I have a PHP program executing very slowly, even in the Code sleep (), and then the browser connected to the service, will start a php-fpm process, but this time, if the browser is closed, then ask, this time the service side of the PHP-FPM process will continue to run it?

Today is the solution to this problem.

The simplest experiment.

The easiest way to do this is to do the experiment, and we'll write a program that writes file_put_contents to the log before and after the sleep:

<?php
file_put_contents ('/tmp/test.log ', ' 11111 '. Php_eol, File_append | LOCK_EX);
Sleep (3);
File_put_contents ('/tmp/test.log ', ' 2222 '. Php_eol, File_append | LOCK_EX);

The result of the actual operation is that we close the client browser during the server sleep, and 2222 is written to the log.

Does that mean that PHP will continue to run when the browser is closed?

Ignore_user_abort

Lao Wang and Diogin remind that this may be related to PHP's Ignore_user_abort function.

So I changed the code a little bit like this:

<?php
Ignore_user_abort (false);
File_put_contents ('/tmp/test.log ', ' 11111 '. Php_eol, File_append | LOCK_EX);
Sleep (3);
File_put_contents ('/tmp/test.log ', ' 2222 '. Php_eol, File_append | LOCK_EX);

Discovery does not have any soft use, regardless of set ignore_user_abort why value, will continue to execute.

But here's a question: what is User_abort?

The document is very clear about the CLI mode abort, when the PHP script executes, the user terminates the script, it triggers the abort. The script then depends on Ignore_user_abort to determine whether to continue execution.

But the official document does not describe the abort of the CGI model clearly. Feel that even if the client disconnects, PHP in CGI mode will not receive abort.

Does Ignore_user_abort have no effect in the CGI mode?

Is it the heartbeat problem?

The first thought is not the heartbeat problem? We disconnect the browser client, which is equal to disconnect the client without close, and the server waits for the TCP keepalive to arrive long before it is detected.

OK, you need to first exclude the browser settings keepalive problem.

Discard the browser, simply write a client program: After the program connected to the HTTP service, send a header, sleep1 seconds active close connection, and this program does not have the HTTP keepalive header.

The procedure is as follows:

Package main

Import "net"
import "FMT"
Import "Time"

func main () {
  conn, _: = Net. Dial ("TCP", "192.168.33.10:10011")
  FMT. fprintf (conn, "get/index.php http/1.0\r\n\r\n") Time
  . Sleep (1 * time. Second)
  Conn. Close ()
  return
}

Service-Side programs:

<?php
Ignore_user_abort (false);
File_put_contents ('/tmp/test.log ', ' 11111 '. Php_eol, File_append | LOCK_EX);
Sleep (3);
File_put_contents ('/tmp/test.log ', ' 2222 '. Php_eol, File_append | LOCK_EX);

Found still the same, PHP or whether or not set Ignore_user_abort, will continue to complete the entire script. It seems that Ignore_user_abort is still not in force.

How to Trigger Ignore_user_abort

So how do you trigger the Ignore_user_abort? Service side How do you know this socket is not available? Lao Wang and Diogin said is not the need for service-side active and socket to interact, will determine whether this socket can be used?

In addition, we also found that PHP provides Connection_status and connection_aborted two methods, both of which can detect the current connection state. So our log of the line of code can be changed to:

File_put_contents ('/tmp/test.log ', ' 1 Connection Status: ' 
. Connection_status () 
. "Abort:" 
. Connection_aborted () 
. Php_eol, File_append | LOCK_EX);

According to the manual connection processing shows we can print out the status of the current connection.

Below also lacks a procedure which interacts with the socket, we use echo, and incidentally remember to bring the flush, excluding the influence of flush.

The procedure is changed into

<?php
Ignore_user_abort (true);
File_put_contents ('/tmp/test.log ', ' 1 Connection Status: '. Connection_status (). "Abort:". Connection_aborted (). Php_eol, File_append | LOCK_EX);

Sleep (3);

for ($i = 0; $i < $i + +) {
    echo "22222";
    Flush ();
    Sleep (1);
    File_put_contents ('/tmp/test.log ', ' 2 connection Status: '. Connection_status (). "Abort:". Connection_aborted (). Php_eol, File_append | LOCK_EX);

}

Well, execute the client we wrote earlier. Observation log:

1 Connection status:0abort:0
2 connection status:0abort:0
2 connection status:1abort:1
2 connection Status : 1abort:1
2 Connection status:1abort:1
2 connection status:1abort:1
2 connection status:1abort:1
2 Co Nnection status:1abort:1
2 connection status:1abort:1
2 connection status:1abort:1
2 connection status:1 Abort:1

Finally made a abort. The log also shows that the abort state of the following several times is 1.

But here's a strange place, why the first 2 connection status is 0 (NORMAL).

Rst

We use Wireshark to look at the entire client and server interaction process

This whole process only send 14 packets, we look at the first time the server sent 22222, the client returned is RST. Subsequent package requests are not followed.

It follows that the approximate interaction process between the client and the service side is:

When the server sends 2222 for the first time in the loop, the client returns a RST because it is disconnected, but the sending process is a successful request. Until the second server to the socket again to write operations, this socket will not be network transmission, directly returned to say connection state has been abort. So there is the above situation, the first 222 is the status of 0, the second time to appear abort.

Strace for verification

We can also use strace php-s xxx for verification.

The entire process strace the following log:

Close (5) = 0 Lstat ("/tmp/test.log", {st_mode=s_ifreg|0644, st_size=49873651, ...}) = 0 open ("/tmp/test.log ", o_wronly| O_creat| O_append, 0666) = 5 Fstat (5, {st_mode=s_ifreg|0644, st_size=49873651, ...}) = 0 lseek (5, 0, seek_cur) = 0 Lseek (5                 , 0, seek_cur) = 0 flock (5, LOCK_EX) = 0 Write (5, "1 connection status:0abort:0\n",) = Close (5) = 0 sendto (4, "http/1.0 ok\r\nconnection:clo" ..., 0, NULL, 0) = SendTo (4, "111111111", 9, 0, N ull, 0) = 9 rt_sigprocmask (Sig_block, [chld], [], 8) = 0 rt_sigaction (sigchld, NULL, {SIG_DFL, [], 0}, 8) = 0 RT_SIGPROCM Ask (Sig_setmask, [], NULL, 8) = 0 Nanosleep ({3, 0}, 0x7fff60a40290) = 0 sendto (4, "22222", 5, 0, NULL, 0) = 5 open (" /tmp/test.log ", o_wronly| O_creat| O_append, 0666) = 5 Fstat (5, {st_mode=s_ifreg|0644, st_size=49873681, ...}) = 0 lseek (5, 0, seek_cur) = 0 Lseek (5 , 0, seek_cur) = 0 flock (5, LOCK_EX) = 0 Write (5, "2 connection status:0abort:0\n = + Close (5) = 0 Rt_sigprocmask (sig_block, [chld], [], 8) = 0 rt_sigaction (sigchld, NULL, {SIG_DFL, [], 0}, 8) = 0 Rt_sigprocmask (sig_setmask, [], NULL, 8) = 0 Nanosleep ({1, 0}, 0x7fff60a40290) = 0 sendto (4, " 22222 ", 5, 0, NULL, 0) =-1 epipe (broken pipe)---sigpipe {si_signo=sigpipe, Si_code=si_user, si_pid=2819, si_uid=0} ---open ("/tmp/test.log", o_wronly| O_creat| O_append, 0666) = 5 Fstat (5, {st_mode=s_ifreg|0644, st_size=49873711, ...}) = 0 lseek (5, 0, seek_cur) = 0 Lseek (5                 , 0, seek_cur) = 0 flock (5, LOCK_EX) = 0 Write (5, "2 connection status:1abort:1\n",) = Close (5) = 0 Rt_sigprocmask (sig_block, [chld], [], 8) = 0 rt_sigaction (sigchld, NULL, {SIG_DFL, [], 0}, 8) = 0 rt_s Igprocmask (Sig_setmask, [], NULL, 8) = 0 Nanosleep ({1, 0}, 0x7fff60a40290) = 0 Open ("/tmp/test.log", o_wronly| O_creat|   O_append, 0666) = 5 Fstat (5, {st_mode=s_ifreg|0644, st_size=49873741, ...}) = 0 lseek (5, 0, Seek_cur)       = 0 Lseek (5, 0, seek_cur) = 0 flock (5, LOCK_EX) = 0 Write (5, "2 Connection status:1abort:1\n", = Close (5) ...

We looked at where the status changed from 0 to 1.                ... sendto (4, "22222", 5, 0, NULL, 0) = 5 ... write (5, "2 connection status:0abort:0\n",) = Close (5) = 0 Rt_sigprocmask (sig_block, [chld], [], 8) = 0 rt_sigaction (sigchld, NULL, {SIG_DFL, [], 0}, 8) = 0 Rt_sigprocmask (S Ig_setmask, [], NULL, 8 = 0 Nanosleep ({1, 0}, 0x7fff60a40290) = 0 sendto (4, "22222", 5, 0, NULL, 0) =-1 Epipe (Bro Ken Pipe)---sigpipe {si_signo=sigpipe, Si_code=si_user, si_pid=2819, si_uid=0}---open ("/tmp/test.log", o_wronly| O_creat| O_append, 0666) = 5 Fstat (5, {st_mode=s_ifreg|0644, st_size=49873711, ...}) = 0 lseek (5, 0, seek_cur) = 0 Lseek (5   , 0, seek_cur) = 0 flock (5, LOCK_EX) = 0 Write (5, "2 connection status:1abort:1\n",) = Close (5)

The second time you send 2222 to the socket, the broken pipe is displayed. This is the program tells us that this socket is no longer available, and in the way PHP Connection_status will be set to 1. Subsequent writes will no longer be executed.

Summarize

Normally, if client-side exceptions are rolled out, the server's programs continue to execute until two interactions with IO. The server discovers that the client is disconnected, and this time triggers a user_abort, and if this is not set Ignore_user_abort, then the PHP-FPM program will be interrupted.

At this point, the problem is closed.

This in-depth analysis of the browser after the exit PHP will continue to implement it is small to share all the content of everyone, hope to give you a reference, but also hope that we support the cloud-dwelling community.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.