MySQL服務器的日志記錄中看到如下的警告:
2015-11-09 08:37:02 1489 [Warning] IP address '104.223.72.XXX' has been resolved to the host name '104.223.72.XXX.static.quadranet.com', which resembles IPv4-address itself.
分析:104.223.72.XXX經查詢,是美國的IP地址,國內有XX防火牆阻攔,DNS解析不了很正常。由於MySQL服務器在內存中維持了一個Host緩存,用於存儲客戶端的信息,包括:IP地址、Host主機名、錯誤信息等。對於非本地的TCP連接,MySQL服務器都會查詢此緩存。對於使用本地環回地址(比如:127.0.0.1或者::1)的TCP連接、或者是使用Unix套接字文件的TCP連接、命名管道的TCP連接、共享內存的TCP連接,都不會使用Host緩存。
注:Loopback,本地環回接口(或地址),亦稱回送地址。此類接口是應用最為廣泛的一種虛接口,幾乎在每台路由器上都會使用。在Windows系統中,采用127.0.0.1作為本地環回地址。
對於每一個新的客戶端連接,MySQL服務器使用客戶端的IP地址進行檢索,查看客戶端的主機名是否在Host緩存中。如果Host緩存中不存在,MySQL服務器會嘗試解析主機名。首先,MySQL服務器會解析主機名對應的IP地址,並與客戶端的原始IP地址進行比較,確保是同一個IP地址。然後MySQL服務器把這些信息寫入Host緩存中。如果Host緩存已滿,MySQL服務器會使用最近最少使用算法,刪除部分緩存數據。
MySQL服務器執行主機名解析使用了線程安全的gethostbyaddr_r()函數調用和gethostbyname_r()函數調用,只要操作系統支持。否則,執行查找的線程會鎖定一個互斥變量,再調用gethostbyaddr()函數和gethostbyname()函數。在這種情況下,如果主機名不在緩存中,也沒有別的線程能解析主機名,必須等到互斥變量被釋放後才可以。
MySQL服務器使用Host緩存主要有幾個目的:
1)通過緩存的IP和主機名的對應關系,避免了對於客戶端的每個連接都要做DNS查詢。相反,對於給定的主機,只需針對首次連接進行DNS查詢。
2)Host緩存中還保護了連接過程中發生的錯誤信息。有些錯誤可能是“阻塞”信息,對於給定的客戶端如果連續出現這種信息,那麼服務器會阻塞來自此客戶端的進一步的連接。MySQL的系統變量max_connect_errors就描述了這種情況,意思是MySQL服務器在阻塞客戶端連接之前允許客戶端連接錯誤的次數。
要解除已經被阻塞的主機,需要刷新Host緩存,執行語句:
mysql> flush hosts
或者是在Shell環境下執行:
# mysqladmin flush-hosts
Host緩存在MySQL中是默認開啟的,要關閉Host緩存,可以在啟動MySQL時添加–skip-host-cache參數選項。
要禁用DNS主機名查找,可以在啟動MySQL時添加–skip-name-resolve參數選項。在這種情況下,MySQL服務器會只使用IP地址來匹配連接。如果DNS查詢很慢,或者是客戶端非常多,那麼關閉DNS查詢可以改進MySQL服務器的性能。
解決辦法:
修改my.cnf配置文件,找到[mysqld]處,添加:
skip-name-resolve
再重啟MySQL服務。
證明:
mysql> show variables like "%skip%"; +------------------------+-------+ | Variable_name | Value | +------------------------+-------+ | skip_external_locking | ON | | skip_name_resolve | ON | | skip_networking | OFF | | skip_show_database | OFF | | slave_skip_errors | OFF | | sql_slave_skip_counter | 0 | +------------------------+-------+ 6 rows in set (0.00 sec)