最近遇到一個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瞭解很少,涉及太廣,無法進一步分析具體緣由了。