最近遇到一个MySQL链接的问题,远程链接MySQL时遇到“ERROR 2013 (HY000): Lost connection to MySQL server at 'reading authorization packet', system error: 0”错误,以下所示:html
[root@DB-Server ~]# mysql -h 10.13.65.93 -u onecard -pmysql
Enter password: sql
ERROR 2013 (HY000): Lost connection to MySQL server at 'reading authorization packet', system error: 0数据库
这个测试的MySQL位于阿里云Kubernetes(K8s)中Docker容器里面,并且在远程链接MySQL出现上面错误的时候,Docker也会出现下面错误。服务器
通常出现“ERROR 2013 (HY000): Lost connection to MySQL server at 'reading authorization packet'”错误的缘由较多:网络
1:网络异常或时延很是高的时候, 超过链接时间限制(系统变量connect_timeout)会致使这个错误。MySQL客户端与数据库创建链接须要发起三次握手协议,正常状况下,这个时间很是短,可是一旦网络异常,网络超时等因素出现,就会致使这个握手协议没法完成,MySQL有个参数connect_timeout,它是MySQL服务端进程mysqld等待链接创建完成的时间,单位为秒。若是超过connect_timeout时间范围内,仍然没法完成协议握手话,MySQL客户端会收到异常。 更多详细信息能够参考我这篇博客“MySQL参数max_connect_errors分析释疑”,可是当前这个案例中,不存在网络延时状况,以下所示:app
[root@DB-Server ~]# ping 10.13.65.93
PING 10.13.65.93 (10.13.65.93) 56(84) bytes of data.
64 bytes from 10.13.65.93: icmp_seq=1 ttl=97 time=36.1 ms
64 bytes from 10.13.65.93: icmp_seq=2 ttl=97 time=36.3 ms
64 bytes from 10.13.65.93: icmp_seq=3 ttl=97 time=36.1 ms
64 bytes from 10.13.65.93: icmp_seq=4 ttl=97 time=36.0 ms
64 bytes from 10.13.65.93: icmp_seq=5 ttl=97 time=36.1 ms
64 bytes from 10.13.65.93: icmp_seq=6 ttl=97 time=36.2 ms
64 bytes from 10.13.65.93: icmp_seq=7 ttl=97 time=36.1 ms
64 bytes from 10.13.65.93: icmp_seq=8 ttl=97 time=36.2 ms
--- 10.13.65.93 ping statistics ---
8 packets transmitted, 8 received, 0% packet loss, time 7003ms
rtt min/avg/max/mdev = 36.092/36.205/36.354/0.205 ms
2:域名解析会致使这个问题。当客户端链接上来,服务器端都会对客户端进来的IP地址进行DNS解析,来得到客户端的域名或主机名,若是DNS解析出了问题或DNS解析至关慢,就会致使链接验证用户出现问题。而skip-name-resolve这个参数的意义就是禁止域名解析。官方文档解释以下:测试
For each new client connection, the server uses the client IP address to check whether the client host name is in the host cache. If so, the server refuses or continues to process the connection request depending on whether or not the host is blocked. If the host is not in the cache, the server attempts to resolve the host name. First, it resolves the IP address to a host name and resolves that host name back to an IP address. Then it compares the result to the original IP address to ensure that they are the same. The server stores information about the result of this operation in the host cache. If the cache is full, the least recently used entry is discarded.this
The server handles entries in the host cache like this:阿里云
当有一个新的客户端链接经过TCP进来时,MySQL Server会为这个IP在host cache中创建一个新的记录,包括IP,主机名和client lookup validation flag,分别对应host_cache表中的IP,HOST和HOST_VALIDATED这三列。第一次创建链接由于只有IP,没有主机名,因此HOST将设置为NULL,HOST_VALIDATED将设置为FALSE。
MySQL Server检测HOST_VALIDATED的值,若是为FALSE,它会试图进行DNS解析,若是解析成功,它将更新HOST的值为主机名,并将HOST_VALIDATED值设为TRUE。若是没有解析成功,判断失败的缘由是永久的仍是临时的,若是是永久的,则HOST的值依旧为NULL,且将HOST_VALIDATED的值设置为TRUE,后续链接再也不进行解析,若是该缘由是临时的,则HOST_VALIDATED依旧为FALSE,后续链接会再次进行DNS解析。
若是在处理来自给定IP地址的传入客户端链接时发生错误,则服务器会更新该IP条目中的相应错误计数器。 有关记录的错误的说明,请参见第26.12.17.1节“host_cache表”。
这个案例里面,由于MySQL位于阿里云Kubernetes(K8s)中Docker容器里面,对公司内部的IP地址进行DNS解析确实会出现问题。咱们在配置文件设置skip_name_resolve后,确实解决了这个问题。而后原本觉得找到了缘由的我,在本地两台机器上测试时发现(一台MySQL版本为5.6.41, 一台MySQL版本为5.6.23),即便两台服务器相互不能作DNS解析,以下截图所示,可是从192.168.27.180链接DB-Server时,并不会报这个错误。Why? 即便我将connect_timeout调整为2,依然不会出现这个错误。看来MySQL的链接不像咱们表面看的那样简单。仍是至关复杂。只是目前的技术水平,还作不到进一步分析!
另外,在这个案例的测试过程当中,发现skip_name_resolve为OFF的状况下,将connect_timeout设大,也不会出现这个错误
mysql> show variables like '%connect_timeout%';
+-----------------+-------+
| Variable_name | Value |
+-----------------+-------+
| connect_timeout | 10 |
+-----------------+-------+
1 row in set (0.01 sec)
mysql> set global connect_timeout=30;
Query OK, 0 rows affected (0.00 sec)
mysql>
而后从客户端链接MySQL数据库就成功了,以下所示,只是IP地址并非客户端的IP地址,而是Port IP。
固然这种状况下Kubernetes(K8s)中Docker下MySQL并无挂掉,反而当系统变量connect_timeout=10的状况下,若是没有开启系统变量skip_name_resolve,每次远程链接MySQL就会出现Kubernetes(K8s)中Docker下MySQL挂掉,重启的过程,因此极度怀疑是疑由于在链接过程,Docker下MySQL挂掉重启才出现这个错误。可是对K8s了解很少,涉及太广,无法进一步分析具体缘由了。