产生原因之一
该连接超过空闲等待时间(wait_timeout
,默认8小时),服务端主动关闭该连接,此时客户端再执行query,则mysql client返回该错误。
研究
设置mysql
wait_timeout
为5s,方便复现set global wait_timeout=5;
客户端首先建立好连接
18:07:19.831124 IP localhost.46740 > localhost.mysql: Flags [S], seq 424450064, win 43690, options [mss 65495,sackOK,TS val 357860862 ecr 0,nop,wscale 7], length 0 18:07:19.831158 IP localhost.mysql > localhost.46740: Flags [S.], seq 2970334829, ack 424450065, win 43690, options [mss 65495,sackOK,TS val 357860862 ecr 357860862,nop,wscale 7], length 0 18:07:19.831179 IP localhost.46740 > localhost.mysql: Flags [.], ack 1, win 342, options [nop,nop,TS val 357860862 ecr 357860862], length 0 ...
5s后,发现服务端主动断开连接(关闭了),服务端关闭了写通道
18:07:24.902120 IP localhost.mysql > localhost.46740: Flags [F.], seq 233, ack 704, win 350, options [nop,nop,TS val 357865933 ecr 357860968], length 0 18:07:24.943661 IP localhost.46740 > localhost.mysql: Flags [.], ack 234, win 342, options [nop,nop,TS val 357865974 ecr 357865933], length 0 [I] wallace@centos:/m/s/W/p/B/p/b/B/judge_server> ss -aon|grep 3306 tcp CLOSE-WAIT 1 0 127.0.0.1:46739 127.0.0.1:3306 timer:(keepalive,120min,0) tcp LISTEN 0 80 :::3306 :::* tcp FIN-WAIT-2 0 0 ::ffff:127.0.0.1:3306 ::ffff:127.0.0.1:46739 timer:(timewait,56sec,0) 观看连接状态,发现服务端socket状态已变为`FIN-WAIT-2`,60s后超时关闭,服务端socket关闭连接后; 此后客户端进入了半连接状态,若客户端继续发送数据,则会收到`RST`,客户端读返回-1,errno=ECONNRESET, `mysql connector c`会将该错误作为`CR_SERVER_LOST`
客户端发送数据
18:13:23.289923 IP localhost.46740 > localhost.mysql: Flags [P.], seq 704:737, ack 234, win 342, options [nop,nop,TS val 358224321 ecr 357865933], length 33
18:13:23.289935 IP localhost.mysql > localhost.46740: Flags [R], seq 2970335063, win 0, length 0
gdb源码跟踪(
mysql-connector-c-6.1.5-src
)sql-common/client.c:957
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24ulong
cli_safe_read_with_ok(MYSQL *mysql, my_bool read_ok)
{
NET *net= &mysql->net;
ulong len=0;
MYSQL_TRACE(READ_PACKET, mysql, ());
if (net->vio != 0)
len=my_net_read(net); // <= 此调用失败
if (len == packet_error || len == 0) // len == packet_error 成立
{
DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %lu",
vio_description(net->vio),len));
if (net->vio && (net->last_errno == ER_NET_READ_INTERRUPTED))
return (packet_error);
end_server(mysql);
set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate); // 设置错误代码为:CR_SERVER_LOST
return (packet_error);
}Breakpoint 3, cli_safe_read_with_ok (mysql=0xb99e80, read_ok=0 '\000') at /media/sf_E_DRIVE/Soft/mysql-connector/mysql-connector-c-6.1.5-src/sql-common/client.c:976 976 set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ? (gdb) bt #0 cli_safe_read_with_ok (mysql=0xb99e80, read_ok=0 '\000') at /media/sf_E_DRIVE/Soft/mysql-connector/mysql-connector-c-6.1.5-src/sql-common/client.c:976 #1 0x00000000004183da in cli_safe_read (mysql=0xb99e80) at /media/sf_E_DRIVE/Soft/mysql-connector/mysql-connector-c-6.1.5-src/sql-common/client.c:1047 #2 0x0000000000421f0b in cli_read_query_result (mysql=0xb99e80) at /media/sf_E_DRIVE/Soft/mysql-connector/mysql-connector-c-6.1.5-src/sql-common/client.c:4711 #3 0x000000000042275c in mysql_real_query (mysql=0xb99e80, query=0x59c2db "SELECT age, name FROM test.a", length=28) at /media/sf_E_DRIVE/Soft/mysql-connector/mysql-connector-c-6.1.5-src/sql-common/client.c:4802 #4 0x000000000040ad7b in mysql::Connection::Query (this=0xba01d0, sql=...) at Beme4wdServer/lily/mysql/connection.cpp:89