Connection failure problem

example

Redis error:

Configuration item: timeout

Error while reading line from the server

Redis can be configured to close the connection if the client does not send data to the Redis server after a certain number of seconds.

To learn more, please visit:

How to become an architect from a coder

zhuanlan.zhihu.com

My official group click here.

Swoole learning recommended videos

PHP — Swoole Path to the Great God: AV77924246

How to use swoole+websocket to achieve outdoor live monitoring (general set) : AV79087951

Learn how to use Swoole to develop online games: AV79264440

PHP Advanced Technology Handwriting Swoole distributed framework: AV78383962

PHP Advanced Technology Handwriting Swoole distributed framework (ii) : AV78632435

PHP Advanced Technology Handwriting Swoole distributed framework (iii) : AV78748923

PHP Advanced Technology Handwriting Swoole distributed framework (frame optimization): AV78856427

PHP Advanced Technology Handwriting Swoole Distributed framework (distributed RPC): AV79012272

Implement message push with Swoole: AV79874641

Swoole + Docker + Redis master/slave replication and read-write separation AV78781841


MySQL > select * from ‘MySQL’ where error:

Configuration items: wait_timeout & interactive_timeout

Error message: Has gone away

Like Redis servers, MySQL periodically cleans up unusable connections.

How to solve

1. Reconnect when using

2. Send heartbeat periodically to maintain connection

Reconnect when you use it

The advantage is simplicity, but the disadvantage is the problem of short connection.

Send heartbeat periodically to maintain connection

Recommend it.

How do I maintain long connections

Tcp_keepalive in TCP

The operating system provides a set of KEEPalive configurations for TCP:

tcp_keepalive_time (integer; default: 7200; Since Linux 2.2) The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. Keep-alives are sent only when the SO_KEEPALIVE socket option is enabled. The default value is 7200 seconds (2 hours). An idle connection is terminated after approximately an additional 11 minutes (9 probes an interval of 75 seconds apart)  when keep-alive is enabled. Note that underlying connection tracking mechanisms and application timeouts may be much shorter. tcp_keepalive_intvl (integer; default: 75; since Linux 2.4)

The number of seconds between TCP keep-alive probes.

  

tcp_keepalive_probes (integer; default: 9; since Linux 2.2)

The maximum number of TCP keep-alive probes to send before

giving up and killing the connection if no response is obtained

from the other end.

8Copy the code

Swoole exposes these configurations, for example:

? php$server = new \Swoole\Server('127.0.0.1', 6666, SWOOLE_PROCESS);

  

$server->set([

'worker_num'= > 1,'open_tcp_keepalive'= > 1,'tcp_keepidle'=> 4, // corresponds to tcp_keepalive_time'tcp_keepinterval'=> 1, // corresponding to tcp_keepALIve_intvl'tcp_keepcount'=> 5, // Corresponding tcp_keepalive_probes]);Copy the code

Among them:

'open_tcp_keepalive'=> 1, // Main switch to enable tcp_keepalive'tcp_keepidle'=> 4, // 4s Detects no data transmission // Detects the following policies:'tcp_keepinterval'=> 1, // probe once, that is, send a packet to the client every 1s (then the client may return an ACK packet, if the server received this ACK packet, then the connection is alive)'tcp_keepcount'=> 5, // The client does not return the ACK packet after 5 times, then close this connectionCopy the code

The server script is as follows:

<? php$server = new \Swoole\Server('127.0.0.1', 6666, SWOOLE_PROCESS);

  

$server->set([

'worker_num'= > 1,'open_tcp_keepalive'=> 1. // Enable tcp_keepalive'tcp_keepidle'=> 4, // 4s Detects no data transmission'tcp_keepinterval'=> 1, // probe once'tcp_keepcount'=> 5, // Number of probes, no packet is returned after 5 times]);$server->on('connect'.function ($server.$fd) {

var_dump("Client: Connect $fd");

});

  

$server->on('receive'.function ($server.$fd.$reactor_id.$data) {

var_dump($data);

});

  

$server->on('close'.function ($server.$fd) {

var_dump("close fd $fd");

});

  

$server->start();Copy the code

Let’s start this server:

~/codeDir/phpCode/hyperf-skeleton # php server.phpCopy the code

Then tcpdump is used to capture packets:

~/codeDir/phpCode/hyperf-skeleton # tcpdump -i lo port 6666

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes

We are listening for packets on port 6666 on LO.

Then we use the client to connect to it:

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666Copy the code

The server prints a message:

~/codeDir/phpCode/hyperf-skeleton # php server.php

string(17) "Client: Connect 1"Copy the code

The output of tcpdump is as follows:

01:48:40.178439 IP localhost.33933 > localhost.6666: Flags [S], seq 43162537, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 0,nop,wscale 7], Length 0 01:48:40.178484 IP localhost.6666 > localhost.33933: Flags [S.], seq 1327460565, ack 43162538, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 9833698,nop,wscale 7], Length 0 01:48:40.178519 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9833698 ecr 9833698], Length 0 01:48:44.229926 IP localhost.6666 > localhost.33933: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], Length 0 01:48:44.229951 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], Length 0 01:48:44.229926 IP localhost.6666 > localhost.33933: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], Length 0 01:48:44.229951 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9834104 ecr 9833698], Length 0 01:48:44.229926 IP localhost.6666 > localhost.33933: Flags [.], ACK 1, win 342, options [NOp, NOp,TS val 9834104 ECR 9833698], length 0Copy the code

We’ll find the three-handshake package printed at the beginning:

01:48:40.178439 IP localhost.33933 > localhost.6666: Flags [S], seq 43162537, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 0,nop,wscale 7], length 0

01:48:40.178484 IP localhost.6666 > localhost.33933: Flags [S.], seq 1327460565, ack 43162538, win 43690, options [mss 65495,sackOK,TS val 9833698 ecr 9833698,nop,wscale 7], length 0

01:48:40.178519 IP localhost.33933 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9833698 ecr 9833698], length 0Copy the code

Then, it stayed for 4s without any packet output.

After that, it prints a set every 1s or so:

01:52:54.359341 IP localhost.6666 > localhost.43101: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9858736], length 0

 01:52:54.359377 IP localhost.43101 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9855887], length 0Copy the code

In fact, this is the policy we configured:

'tcp_keepinterval'=> 1, // probe once'tcp_keepcount'=> 5, // The number of probes exceeds 5, and no packet is returnedCopy the code

The connection will not be closed after 5 probes because the underlying operating system will automatically ack the client. The underlying operating system continually sends a set of packets:

01:52:54.359341 IP localhost.6666 > localhost.43101: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9858736], length 0

 01:52:54.359377 IP localhost.43101 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 9859144 ecr 9855887], length 0Copy the code

If we want to close the connection after testing 5 probes, we can disable the packet on port 6666:

~/codeDir/phpCode/hyperf-skeleton # iptables -A INPUT -p tcp --dport 6666 -j DROPCopy the code

This will disable all incoming packets from port 6666, so that the server cannot receive ack packets from the client side.

The server then prints close after 5 seconds (the server actively calls the close method and sends the FIN packet to the client) :

~/codeDir/phpCode/hyperf-skeleton # php server.php
string(17) "Client: Connect 1"
string(10) "close fd 1"Copy the code

Let’s restore the iptables rules:

~/codeDir/phpCode # iptables -D INPUT -p tcp -m tcp --dport 6666 -j DROPCopy the code

That is, we set the rules to delete.

Using tcp_keepalive to realize the heartbeat function, the advantage is simple, do not write code to complete this function, and send a small heartbeat packet. The disadvantage is that it depends on the network environment of the system. You must ensure that both the server and the client have implemented such functions, and the client needs to cooperate with sending heartbeat packets.

A more serious drawback is that if the client and server are not directly connected, but are connected through proxies, such as socks5 proxies, which only forward application-layer packets, not the lower level TCP probe packets, the heartbeat function will not work.

So Swoole offers another solution, a set of configurations that detect dead connections.

'heartbeat_check_interval'=> 1, // probe once'heartbeat_idle_time'=> 5, // 5s Close the connection if no data packet is sentCopy the code

Swoole implements heartbeat

Let’s test it out:

<? php$server = new \Swoole\Server('127.0.0.1', 6666, SWOOLE_PROCESS);

  

$server->set([

'worker_num'= > 1,'heartbeat_check_interval'=> 1, // probe once'heartbeat_idle_time'=> 5, // 5s close the connection without sending the packet]);$server->on('connect'.function ($server.$fd) {

var_dump("Client: Connect $fd");

});

  

$server->on('receive'.function ($server.$fd.$reactor_id.$data) {

var_dump($data);

});

  

$server->on('close'.function ($server.$fd) {

var_dump("close fd $fd");

});

  

$server->start();Copy the code

Then start the server:

~/codeDir/phpCode/hyperf-skeleton # php server.phpCopy the code

Then start tcpdump:

~/codeDir/phpCode # tcpdump -i lo port 6666

tcpdump: verbose output suppressed, use -v or -vv for full protocol decode

listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytesCopy the code

Then start the client:

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666Copy the code

At this point, the server side prints:

~/codeDir/phpCode/hyperf-skeleton # php server.php

 string(17) "Client: Connect 1"Copy the code

Then tcpdump prints:

02:48:32.516093 IP localhost.42123 > localhost.6666: Flags [S], seq 1088388248, win 43690, options [mss 65495,sackOK,TS val 10193342 ecr 0,nop,wscale 7], length 0

02:48:32.516133 IP localhost.6666 > localhost.42123: Flags [S.], seq 80508236, ack 1088388249, win 43690, options [mss 65495,sackOK,TS val 10193342 ecr 10193342,nop,wscale 7], length 0

02:48:32.516156 IP localhost.42123 > localhost.6666: Flags [.], ack 1, win 342, options [nop,nop,TS val 10193342 ecr 10193342], length 0Copy the code

This is the three-handshake message.

Then, after 5s, tcpdump prints:

02:48:36.985027 IP localhost.6666 > localhost.42123: Flags [F.], seq 1, ack 1, win 342, options [nop,nop,TS val 10193789 ecr 10193342], length 0


02:48:36.992172 IP localhost.42123 > localhost.6666: Flags [.], ack 2, win 342, options [nop,nop,TS val 10193790 ecr 10193789], length 0

The server sends a FIN packet. Swoole closes the connection because the client is not sending data.

Then the server side prints:

~/codeDir/phpCode/hyperf-skeleton # php server.php

string(17) "Client: Connect 1"

string(10) "close fd 1"Copy the code

TCP Keepalive has a function to keepa connection alive, but TCP Keepalive detects a connection with no data and closes it. It can only be configured on the server side. You can also have the client cooperate to send the heartbeat.

If we don’t want the server to close the connection, we have to keep sending packets in the application layer to keep alive. For example, I keep sending packets in the NC client:

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666

ping

ping

ping

ping

ping

ping

ping

ping

pingCopy the code

I sent nine ping packets to the server. The output of tcpdump is as follows:

IP localhost.44195 > localhost.6666: Flags [P.], seq 1:6, ack 1, win 342, options [nop,nop,TS val 10249525 ecr 10249307], Length 5 02:57:53.697390 IP localhost.6666 > localhost.44195: Flags [.], ack 6, win 342, options [nop,nop,TS val 10249525 ecr 10249525], Length 0 02:57:55.309532 IP localhost.44195 > localhost.6666: Flags [P.], seq 6:11, ack 1, win 342, options [nop,nop,TS val 10249686 ecr 10249525], Length 5 02:57:55.309576 IP localhost.6666 > localhost.44195: Flags [.], ack 11, win 342, options [nop,nop,TS val 10249686 ecr 10249686], Length 0 02:57:58.395206 IP localhost.44195 > localhost.6666: Flags [P.], seq 11:16, ack 1, win 342, options [nop,nop,TS val 10249994 ecr 10249686], Length 5 02:57:58.395239 IP localhost.6666 > localhost.44195: Flags [.], ack 16, win 342, options [nop,nop,TS val 10249994 ecr 10249994], Length 0 02:58:01.858094 IP localhost.44195 > localhost.6666: Flags [P.], seq 16:21, ack 1, win 342, options [nop,nop,TS val 10250341 ecr 10249994], Length 5 02:58:01.858126 IP localhost.6666 > localhost.44195: Flags [.], ack 21, win 342, options [nop,nop,TS val 10250341 ecr 10250341], Length 0 02:58:04.132584 IP localhost.44195 > localhost.6666: Flags [P.], seq 21:26, ack 1, win 342, options [nop,nop,TS val 10250568 ecr 10250341], Length 5 02:58:04.132609 IP localhost.6666 > localhost.44195: Flags [.], ack 26, win 342, options [nop,nop,TS val 10250568 ecr 10250568], Length 0 02:58:05.895704 IP localhost.44195 > localhost.6666: Flags [P.], seq 26:31, ack 1, win 342, options [nop,nop,TS val 10250744 ecr 10250568], Length 5 02:58:05.895728 IP localhost.6666 > localhost.44195: Flags [.], ack 31, win 342, options [nop,nop,TS val 10250744 ecr 10250744], Length 0 02:58:07.150265 IP localhost.44195 > localhost.6666: Flags [P.], seq 31:36, ack 1, win 342, options [nop,nop,TS val 10250870 ecr 10250744], Length 5 02:58:07.150288 IP localhost.6666 > localhost.44195: Flags [.], ack 36, win 342, options [nop,nop,TS val 10250870 ecr 10250870], Length 0 02:58:08.349124 IP localhost.44195 > localhost.6666: Flags [P.], seq 36:41, ack 1, win 342, options [nop,nop,TS val 10250990 ecr 10250870], Length 5 02:58:08.349156 IP localhost.6666 > localhost.44195: Flags [.], ack 41, win 342, options [nop,nop,TS val 10250990 ecr 10250990], Length 0 02:58:09.906223 IP localhost.44195 > localhost.6666: Flags [P.], seq 41:46, ack 1, win 342, options [nop,nop,TS val 10251145 ecr 10250990], Length 5 02:58:09.906247 IP localhost.6666 > localhost.44195: Flags [.], ack 46, win 342, options [nop,nop,TS val 10251145 ecr 10251145], length 0Copy the code

There are 9 packets sent. (Flags [P.] stands for Push)

In this case, the server does not close the connection, and the client keeps the connection alive. Then we stop ping, and after 5 seconds tcpdump will output a set of:

02:58:14.811761 IP localhost.6666 > localhost.44195: Flags [F.], seq 1, ack 46, win 342, options [nop,nop,TS val 10251636 ecr 10251145], length 0


02:58:14.816420 IP localhost.44195 > localhost.6666: Flags [.], ack 2, win 342, options [nop,nop,TS val 10251637 ecr 10251636], length 0

The server sends a FIN packet, indicating that the server has closed the connection. The output from the server side is as follows:

~/codeDir/phpCode/hyperf-skeleton # php server.php

string(17) "Client: Connect 1"

string(5) "ping "

string(5) "ping "

string(5) "ping "

string(5) "ping "

string(5) "ping "

string(5) "ping "

string(5) "ping "

string(5) "ping "

string(5) "ping "

string(10) "close fd 1"Copy the code

Then we close the connection on the client side with CTRL + C:

~/codeDir/phpCode/hyperf-skeleton # nc 127.0.0.1 6666

ping

ping

ping

ping

ping

ping

ping

ping

ping

^Cpunt!

 

~/codeDir/phpCode/hyperf-skeleton #Copy the code

The output of tcpdump is as follows:

03:03:02.257667 IP localhost.44195 > localhost.6666: Flags [F.], seq 46, ack 2, win 342, options [nop,nop,TS val 10280414 ecr 10251636], length 0

03:03:02.257734 IP localhost.6666 > localhost.44195: Flags [R], seq 2678621620, win 0, length 0Copy the code

Application layer heartbeat

1, develop ping/pong protocol (mysql and other built-in ping protocol)

2. The client flexibly sends ping heartbeat packets

3, server OnRecive check availability reply pong

Such as:

$server->on('receive'.function (\Swoole\Server $server.$fd.$reactor_id.$data)

{

if ($data= ='ping')

{

checkDB();

checkServiceA();

checkRedis();

$server->send('pong'); }});Copy the code

conclusion

1. TCP keepalive is the simplest, but it has compatibility problems and is not flexible enough

2. The Keepalive provided by Swoole is the most practical, but requires the cooperation of the client and has moderate complexity

3. Keepalive of the application layer is the most flexible but most troublesome


So that’s a summary of the PHP Swoole Long connection FAQ

To learn more, please visit:

How to become an architect from a coder

zhuanlan.zhihu.com

My official group click here.

Swoole learning recommended videos

PHP — Swoole Path to the Great God: AV77924246

How to use swoole+websocket to achieve outdoor live monitoring (general set) : AV79087951

Learn how to use Swoole to develop online games: AV79264440

PHP Advanced Technology Handwriting Swoole distributed framework: AV78383962

PHP Advanced Technology Handwriting Swoole distributed framework (ii) : AV78632435

PHP Advanced Technology Handwriting Swoole distributed framework (iii) : AV78748923

PHP Advanced Technology Handwriting Swoole distributed framework (frame optimization): AV78856427

PHP Advanced Technology Handwriting Swoole Distributed framework (distributed RPC): AV79012272

Implement message push with Swoole: AV79874641

Swoole + Docker + Redis master/slave replication and read-write separation AV78781841