线上一个client连接失败报错

2020-07-06 14:38:09 浏览数 (1)

//线上一个client连接失败报错//

今天下午,线上的MySQL数据库出现了一个连接中断的报错,大概的报错内容如下:

代码语言:javascript复制
200701 17:57:50 [Warning] Aborted connection 50367424 to db: 'xxxxx' user: 'srv_bigdata_rwh' host: 'xxxxx' (Got an error reading communication packets)
200701 17:57:50 [Warning] Aborted connection 50367424 to db: 'xxxxx' user: 'srv_bigdata_rwh' host: 'xxxxx' (Got an error reading communication packets)
200701 17:57:50 [Warning] Aborted connection 50367424 to db: 'xxxxx' user: 'srv_bigdata_rwh' host: 'xxxxx' (Got an error reading communication packets)
200701 17:57:50 [Warning] Aborted connection 50367424 to db: 'xxxxx' user: 'srv_bigdata_rwh' host: 'xxxxx' (Got an error reading communication packets)
200701 17:57:50 [Warning] Aborted connection 50367424 to db: 'xxxxx' user: 'srv_bigdata_rwh' host: 'xxxxx' (Got an error reading communication packets)
200701 17:57:50 [Warning] Aborted connection 50367424 to db: 'xxxxx' user: 'srv_bigdata_rwh' host: 'xxxxx' (Got an error reading communication packets)
200701 17:57:50 [Warning] Aborted connection 50367424 to db: 'xxxxx' user: 'srv_bigdata_rwh' host: 'xxxxx' (Got an error reading communication packets)

看样子是读取通信包的时候出现的错误。于是我查询了一下MySQL的官方文档,看看这个到底是啥错。

首先来看通信包在MySQL中的定义:

A communication packet is a single SQL statement sent to the MySQL server, a single row that is sent to the client, or a binary log event sent from a master replication server to a slave.

可以理解为是client发送给server的一条SQL、也可以是server发送给client的一条记录,或者是master发送给slave的一个binlog事件。

通信包的大小由max_allowed_packet控制,最大可以设置成1GB,client的默认值是16MB,server的默认值是4MB。

对于通讯报出现错误的情况,MySQL官方文档给出了以下分析方法:

1、分析错误日志或者通用日志

2、分析状态变量 Aborted_xxx 和

Connection_errors_xxx

3、分析performance schema中的host_cache表

如果客户端一开始连接的时候,就发生此类报错,那么报错可能的原因有:

1、客户端尝试连接服务器,但是却没有权限

2、客户端使用了不正确的密码

3、连接的通讯包格式不正确

4、连接时长超过了connect_timeout秒,但是依旧没有获取到通讯包

如果客户端一开始连接没有问题,但是后续连接中断,并报错,伴随abort_clients和connection_erros_xxx变量增长,则有可能是下面的原因:

1、客户端退出后没有调用mysql_close函数

2、客户端已经等待超过wait_timeout或者interactive_timeout秒没有和server交互,MySQL主动回收了连接线程。

3、数据传输过程中,客户端发生了断开的情况

4、max_allowed_packet值设置太小,或者查询需要更多的内存空间

MySQL Client和Server交互原理:

有了上面的这些建议,接下来就是尝试解决问题了。在此之前,我们还应该了解下client和server端利用tcp/ip协议建议连接,然后进行数据交互的原理了:

1、MySQL server端根据client端传来的SQL,获取数据记录,写到net_buffer中,其中net_buffer受参数net_buffer_length控制,默认是16KB

代码语言:javascript复制
mysql> show variables like "%net_buffer%";
 ------------------- ------- 
| Variable_name     | Value |
 ------------------- ------- 
| net_buffer_length | 16384 |
 ------------------- ------- 
1 row in set, 1 warning (0.00 sec)

2、重复获取记录,直到net_buffer写满,然后调用网络接口发送数据,写入linux的本地网络栈

3、net_buffer发送成功,清空net_buffer,接着取剩余的满足条件的数据记录,并写入net_buffer

4、如果Linux的本地网络栈写满了,则net_buffer的发送过程需要等待。

本地网络栈的位置,一般保存在下面的文件中:

代码语言:javascript复制
[root@VM_48_10_centos ~]# cat /proc/sys/net/core/wmem_default
212992

如果Linux本地网络栈被写满,则net_buffer的传输会进入等待状态,此时,在show processlist的state状态中,会出现"sending to client"字样,如果你的系统中经常出现这种字眼,很明显,返回的数据太多了,此时就要评估业务的返回结果是否合理了。适当的调大net_buffer_length的值可以解决本地网络栈被写满的状态。

开始尝试解决问题:

首先我尝试性的修改了server端和client端的max_allowed_packet的参数,原本设置的时间是32MB,我将它改成了64MB,重新查看错误日志,似乎问题没有解决,错误还一直存在。

调整max_allowed_packet的值没有用处,再来调整net_buffer_length的值试试,该值默认是16k,最大值为1MB,将它调大到32k,发现问题已经解决了。

问题虽然通过上面的尝试解决了,还有一点没有想明白,就是在官方文档中有看到说:"每个客户端线程都有一个连接缓冲区和一个结果缓冲区,这两者都以net_buffer_length给定的大小作为初始大小,但可以根据需要动态扩展到max_allowed_packet字节大小。执行完SQL语句后,结果缓冲区会自动缩小为net_buffer_length",这不就意味着max_allow_packet这个参数才是决定通讯包的最终大小的,为什么在我的案例中,第一次调整了max_allowed_packet之后,没有作用,报错依旧,难道是因为响应有滞后?

这个问题后面还得重新排查下。就目前来看,调整max_allowed_packet和net_buffer_length是可以解决此类报错的。

0 人点赞