这两天线上服务报了非常多的Error,具体内容如下:
SQLSTATE[HY000] [2013] Lost connection to MySQL server at 'reading initial communication packet', system error: 104
DBA说没有找到MySQL错误日志,网上搜索了一圈也没有找到满意答案。只好自己动手查MySQL源码,查到如下代码:
./libmysql/client.c
if ((pkt_length=cli_safe_read(mysql)) == packet_error)
{
//调用cli_safe_read,若返回的last_errno是CR_SERVER_LOST,则抛出我遇到的那个错误
if (mysql->net.last_errno == CR_SERVER_LOST)
set_mysql_extended_error(mysql, CR_SERVER_LOST, unknown_sqlstate,
ER(CR_SERVER_LOST_EXTENDED),
"reading initial communication packet",
errno);
goto error;
}
继续跟cli_safe_read函数,是这么定义的:
ulong
cli_safe_read(MYSQL *mysql)
{
NET *net= &mysql->net;
ulong len=0;
init_sigpipe_variables
/* Don't give sigpipe errors if the client doesn't want them */
set_sigpipe(mysql);
//开始读数据
if (net->vio != 0)
len=my_net_read(net);
reset_sigpipe(mysql);
if (len == packet_error || len == 0)
{
DBUG_PRINT("error",("Wrong connection or packet. fd: %s len: %lu",
vio_description(net->vio),len));
#ifdef MYSQL_SERVER
if (net->vio && vio_was_interrupted(net->vio))
return (packet_error);
#endif /*MYSQL_SERVER*/
end_server(mysql);
//当读出的last_errno不是ER_NET_PACKET_TOO_LARGE的,时候,都会置为CR_SERVER_LOST
set_mysql_error(mysql, net->last_errno == ER_NET_PACKET_TOO_LARGE ?
CR_NET_PACKET_TOO_LARGE: CR_SERVER_LOST, unknown_sqlstate);
return (packet_error);
}
if (net->read_pos[0] == 255)
{
if (len > 3)
{
char *pos=(char*) net->read_pos+1;
net->last_errno=uint2korr(pos);
pos+=2;
len-=2;
if (protocol_41(mysql) && pos[0] == '#')
{
strmake(net->sqlstate, pos+1, SQLSTATE_LENGTH);
pos+= SQLSTATE_LENGTH+1;
}
(void) strmake(net->last_error,(char*) pos,
min((uint) len,(uint) sizeof(net->last_error)-1));
}
else
set_mysql_error(mysql, CR_UNKNOWN_ERROR, unknown_sqlstate);
/*
Cover a protocol design error: error packet does not
contain the server status. Therefore, the client has no way
to find out whether there are more result sets of
a multiple-result-set statement pending. Luckily, in 5.0 an
error always aborts execution of a statement, wherever it is
a multi-statement or a stored procedure, so it should be
safe to unconditionally turn off the flag here.
*/
mysql->server_status&= ~SERVER_MORE_RESULTS_EXISTS;
DBUG_PRINT("error",("Got error: %d/%s (%s)",
net->last_errno, net->sqlstate, net->last_error));
return(packet_error);
}
return len;
}
注释是我添加的,继续往下跟my_net_read函数,函数在libmysql/net.c 中,有点长,不全贴出来了。
在my_net_read函数中,有几种情况会报error:
- 啥也没读到,会重试,重试也不行,会报:ER_NET_FCNTL_ERROR、ER_NET_READ_INTERRUPTED或者ER_NET_READ_ERROR
- 读到了,但是package有问题,会报:ER_NET_PACKETS_OUT_OF_ORDER
- 之后在net_realloc的时候,还会报两种错误。
没有环境权限、没法复现,dba说明天抓包分析一下,只能先这样了。