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