场景
机器A上的一个模块连接机器B上的MySQL,在实验室网络环境下正常;同样A、B两台机器,网络环境切换为与外界隔离的一个小型局域网环境,A上的模块与B上MySQL建立连接非常慢。
环境
SuSE 11 x64,MySQL 5.1
分析
A上的模块启动以后长时间无响应,不能提供服务,由于模块代码编写不具备充分的调试信息,不知道程序阻塞在什么地方。于是,使用gdb进行调试,中断程序以后,执行bt查看调用栈,程序调用mysql_real_connect与MySQL建立连接,在mysql_real_connect中调用read接收MySQL服务器返回的数据,程序就卡在read调用上。
在A上用telnet连接B上的MySQL 3306端口,建立网络连接正常。但是在A上用MySQL客户端访问B上的MySQL则建立MySQL连接(包括建立网络连接及进行用户认证等)的时间很长,在此期间,使用netstat查看网络连接,确认A上的MySQL客户端与B上的MySQL服务器网络连接已经建立。因此,问题应该出在客户端与MySQL服务器进行后续协议交互的过程中。
仔细对比了前后两个网络环境,唯一的区别在于出问题的网络环境不能访问外网,其余环境都相同,甚至连机器IP都是一样的。这时我想起以前在局域网内使用Oracle时也出现过类似的问题,当时将Oracle所在机器的DNS配置(/etc/resolv.conf)清空以后就好了。于是我出于侥幸心理,将B机器的DNS配置清空,重新启动A上的模块,一切都正常了。
继续分析问题,发现之前配置的DNS是外网地址,在实验室网络环境下是可以访问的,在后面的小型局域网环境不能访问。推测是MySQL在用户建立连接时使用了DNS,由于配置的DNS无法访问,MySQL会一直等待网络超时。
网上找了一下相关资料,发现MySQL确实会在用户登陆过程中对客户端IP进行DNS反查。为了避免这个反查过程,可以在MySQL的配置文件my.cnf中做如下配置:
[mysqld]
skip-name-resolve
如果由于DNS反查导致登陆很慢,那么在MySQL服务器上使用show processlist会看到类似如下连接:
|592|unauthenticated user|192.168.3.20:35320|NULL|Connect| |login|NULL|
|593|unauthenticated user|192.168.3.20:35321|NULL|Connect| |login|NULL|
|594|unauthenticated user|192.168.3.20:35322|NULL|Connect| |login|NULL|
解决方案
1. 使用skip-name-resolve指令;
2. 配置一个可访问的DNS地址,或直接清空DNS配置。
Reference
1. MYSQL大量UNAUTHENTICATED USER. http://www.cnblogs.com/ericstone57/archive/2009/06/02/mysql_unauthenticated_user.html
2. MySQL的DNS查询关闭. http://timnity.iteye.com/blog/526331