连接MySQ时报错:Host X is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'

今天来了解一下performance_schema库中的 host_cache表。这个表记录了 host 的缓存内容,缓存信息包括主机名和 IP,用于避免 DNS 查找。这个表的记录,可以在需要的时候协助排查连接问题。

要开启这个功能,要保障参数 performance_schema的状态 是开启的。

另外,MySQL 启动时若带有参数–skip-name-resolve,或者配置文件里有参数skip-name-resolve,则,即使performance_schema=on,表 host_cache 也不会缓存主机信息。

 

前几天碰到一个问题,主要就是这个功能的基础导致的。

问题:

昨天开发同事在使用 MySQL 连接数据库的时候,客户端无法连接上数据库。当时数据库的时候报错如下:

Caused by: com.mysql.cj.exceptions.CJException: null,  message from server: "Host ' xxx' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'"

Caused by: com.mysql.cj.exceptions.CJException: null,  message from server: "Host 'xxx' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'" at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:1.8.0_66]

解决办法:

在调整 max_connect_erros 从 100 到 300以后,能连上数据库了:

mysql> show variables like '%max%connect%er%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| max_connect_errors | 300   |
+--------------------+-------+
1 row in set (0.06 sec)

这是一个治标不治本的临时解决办法。

 

果然接着发生问题:

过了一段时间,开发同事表示应用服务器又连不上数据库了。报错如下:

Failed to initialize pool: Could not create connection to database server. Attempted reconnect 3 times. Giving up.
2019-10-21 10:26:03.021 main      
         ERROR o.s.b.SpringApplication 842 reportFailure - Application run failed org.springframework.context.
         ApplicationContextException: Unable to start web server;
nested exception is org.springframework.boot.web.server.WebServerException: Unable to start embedded Tomcat
……
Caused by: com.mysql.cj.exceptions.CJException: null,  message from server: "Host '92.168.225.131' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts'"

解决办法:

最终处理办法,方法有多种:

mysql> flush hosts;
## 或者
mysql> truncate Performance_chema.host_cache;

或者找到mysqladmin

[root@my571 ~]#  whereis mysqladmin
mysqladmin: /usr/bin/mysqladmin /usr/share/man/man1/mysqladmin.1.gz
[root@my571 ~]# /usr/bin/mysqladmin flush-hosts  #清除hosts缓存

或者调整参数:

root@localhost|performance_schema> set global host_cache_size=0;

原因:

当时应用报这种错误的原因,其实是应用到 MySQL 服务器的网络延迟太大:

64 bytes from xxx: icmp_seq=50 ttl=64 time=24031 ms
64 bytes from xxx: icmp_seq=51 ttl=64 time=23008 ms
64 bytes from xxx: icmp_seq=52 ttl=64 time=21984 ms
64 bytes from xxx: icmp_seq=53 ttl=64 time=20960 ms
64 bytes from xxx: icmp_seq=54 ttl=64 time=19936 ms
64 bytes from xxx: icmp_seq=55 ttl=64 time=18912 ms
64 bytes from xxx: icmp_seq=56 ttl=64 time=17888 ms
64 bytes from xxx: icmp_seq=57 ttl=64 time=16864 ms
64 bytes from xxx: icmp_seq=58 ttl=64 time=15840 ms
64 bytes from xxx: icmp_seq=59 ttl=64 time=14815 ms

 

跟这种情况的报错的相关参数:max_connect_errors & connect_timeout。

数据库的connect_timeout = 10,网络延迟基本在 14 秒以上。参数max_connect_errors控制同一个 IP连接连续错误次数多过参数max_connect_errors的值时,这之后的连接mysql会阻止。

# 原文参考地址:

https://dev.mysql.com/doc/refman/5.6/en/blocked-host.html

The value of the max_connect_errors system variable determines how many successive interrupted connection requests are permitted. 

After max_connect_errors failed requests without a successful connection, mysqld assumes that something is wrong (for example, that someone is trying to break in),

 

解决这种问题的方法通常有以下几种:

1、调大 max_connect_errors;

2、flush hosts 或 mysqladmin flush-hosts 或者 truncate host_cache 表;

3、变量 host_cache_size 置为零。

方法一:只是延迟了这个错误再触发的阈值,当此 IP 再次连接 MySQL 失败次数达到参数max_connect_errors的新值,又会报同样的错误了。

方法二:是清理掉 MySQL 中记录的对应的IP主机相关cache记录,从零开始,达到 max_connect_errors 值大小,依旧会报错。

方法三:是临时禁用了host 的缓存功能,只是不记录 host cache 了,每次客户端连接,都会执行 DNS 查找。

# host  cache相关介绍官档连接
https://dev.mysql.com/doc/refman/5.7/en/host-cache.html

官方资料介绍,host_cache的字段SUM_CONNECT_ERRORS是统计被视为“阻塞”的连接错误的数量(根据max_connect_errors系统变量进行评估)。 只计算协议握手错误,并且仅用于通过验证的主机(HOST_VALIDATED = YES)。

MySQL客户端与数据库建立连接需要发起三次握手协议,正常情况下,这个时间非常短,但是一旦网络异常,网络超时等因素出现,就会导致这个握手协议无法完成,

MySQL有个参数connect_timeout,它是MySQL服务端进程mysqld等待连接建立完成的时间,单位为秒。如果超过connect_timeout时间范围内,仍然无法完成协议握手话,MySQL客户端会收到异常,异常消息类似于: Lost connection to MySQL server at 'XXX', system error: errno,该变量默认是10秒。

参数--skip-host-cache的功能类似于 设置参数 host_cache_size=0,但是 host_cache_size更灵活。 host_cache_size能在 MySQL运行时通过修改全局参数调整是否缓存、缓存的大小。

即使启动 MySQL 服务时,加上了--skip-host-cache参数,在数据库运行时也是可以如常修改参数host_cache_size的值,只不过修改不会生效。

 

 

以下来验证 host_cache 中 sum_connect_errors 列的值与 max_connect_errors 参数:

1、主机名my 571 的为 MySQL 服务器,IP:131;主机名为 my80的做应用客户端,IP:129。

构造网络延迟的场景验证:

[root@my80 ~]# tc qdisc add dev eth0 root netem delay 11000ms

2、此时从 my80 上 ping MySQL 服务器:

[root@my80 ~]#  ping 192.168.225.131

PING 192.168.225.131 (192.168.225.131) 56(84) bytes of data.
64 bytes from 192.168.225.131: icmp_seq=1 ttl=64 time=11000 ms
64 bytes from 192.168.225.131: icmp_seq=2 ttl=64 time=11001 ms
64 bytes from 192.168.225.131: icmp_seq=3 ttl=64 time=11001 ms
64 bytes from 192.168.225.131: icmp_seq=4 ttl=64 time=11001 ms
64 bytes from 192.168.225.131: icmp_seq=6 ttl=64 time=11001 ms
64 bytes from 192.168.225.131: icmp_seq=7 ttl=64 time=11001 ms
64 bytes from 192.168.225.131: icmp_seq=5 ttl=64 time=11001 ms
64 bytes from 192.168.225.131: icmp_seq=6 ttl=64 time=11001 ms

延迟基本是 11 秒左右,目前 my571 的数据库的参数 connect_timeout =10,连接是会超时的。

3、my80 上连接 MySQL 服务器,仅执行一次:

[root@my80 ~]# mysql -h192.168.225.131 -uroot -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2026 (HY000): SSL connection error: error:00000000:lib(0):func(0):reason(0)
[root@my80 ~]#

4、查看此时的host_cache 表,结果如下:

此时:sum_connect_errors=1,count_handshake_errors=1。

5、此时继续在my80 上反复登录3次,报错如下:

[root@my80 ~]# mysql -h192.168.225.131 -uroot -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2026 (HY000): SSL connection error: error:00000000:lib(0):func(0):reason(0)
[root@my80 ~]#
[root@my80 ~]# mysql -h192.168.225.131 -uroot -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2026 (HY000): SSL connection error: error:00000000:lib(0):func(0):reason(0)
[root@my80 ~]#
[root@my80 ~]# mysql -h192.168.225.131 -uroot -proot
mysql: [Warning] Using a password on the command line interface can be insecure.
ERROR 2026 (HY000): SSL connection error: error:00000000:lib(0):func(0):reason(0)
[root@my80 ~]#

虽然报错连不上,但是还未出现“ Host '192.168.225.129' is blocked ”。因为当前连续的失败连接数未草果参数 max_connect_errors 的值大小。

此时日志报错信息如下:

2019-10-22T07:51:30.427453Z 11 [Note] Got timeout reading communication packets

6、查看当前参数 max_connect_errors=1+3;当前对应的 host_cache 表记录,如下:

由于参数 connect_timeout=10,网络延时超过10秒,导致连接MySQL失败。

在新增一次失败连接后,MySQL服务器上查询host_cache表的话,就会看到SUM_CONNECT_ERRORS变大 了,在原来的值上加 1,COUNT_HANDSHAKE_ERRORS也变大了1。

7、继续执行,再进行 3 次:

可以看到这次的“三次”连接都报错:“ Host '192.168.225.129' is blocked ”了。

此时仍然,sum_connect_errors=4 && count_handshake_errors=4,均等于 max_connect_errors 参数的设定值,大于这个值的连接都会被拒绝掉,sum_connect_errors 不会变更大,后面三次被拒绝因此报错 “ Host '192.168.225.129' is blocked ”。

此报错的解决办法:

8、然后再在 my80 上尝试登录 my571 的 MySQL:

虽然由于延迟变大,超过 mysql571 的connect_timeout 的限制,但是并未再报错“host xxx is blocked” 了。解决延迟后,就可以继续正常连接数据库了。

9、测试完成后,记得解除延迟 10s 的设置:

[root@my80 ~]# tc qdisc del dev ens33 root netem delay 11000ms


 

额外,参数 count_authentication_errors。

另外,从上面测试案例中看到的 host_cache 表中有一个字段“count_authentication_errors”,这个字段跟 sum_connect_errors 有的人可能会弄混淆。count_authentication_errors 记录的是来自客户端的连接中、输入密码错误的次数。

 

开始测试连接 MySQL 数据库中 count_authentication_errors的变化:

1、先清空 host_cache 的记录:

2、在 my80 上,执行多次错入的密码的数据库连接命令:

3、在 my571 上进入数据库查看表 host_cache:

此时,count_authentication_errors=7,

4、此时数据库相对的错误日志如下:

2019-10-13T07:37:25.282600Z 3 [Warning] IP address '192.168.225.129' could not be resolved: Name or service not known
2019-10-13T07:37:25.308431Z 3 [Note] Access denied for user 'iris'@'192.168.225.129' (using password: YES)
2019-10-13T07:37:26.821914Z 4 [Note] Access denied for user 'iris'@'192.168.225.129' (using password: YES)
2019-10-13T07:37:29.060450Z 5 [Note] Access denied for user 'iris'@'192.168.225.129' (using password: YES)
2019-10-13T07:37:31.075948Z 6 [Note] Access denied for user 'iris'@'192.168.225.129' (using password: YES)
2019-10-13T07:37:32.626528Z 7 [Note] Access denied for user 'iris'@'192.168.225.129' (using password: YES)
2019-10-13T07:37:34.258874Z 8 [Note] Access denied for user 'iris'@'192.168.225.129' (using password: YES)
2019-10-13T07:37:36.540025Z 9 [Note] Access denied for user 'iris'@'192.168.225.129' (using password: YES)

 

总结

本次我们环境的数据库报错,是因为网络环境不好,导致完成连接数据库的时间(即三次握手协议完成的时长)超过MySQL 中定义的参数的 connect_timeout 的值,应用服务器不断尝试连接,最终尝试次数超过了 MySQL 的参数 max_connect_errors 的大小,导致的报错。

参数max_connect_errors决定了 MySQL 允许的每个 IP 持续连接数据库时发生连接错误的次数,对应的是表 host_cache 中的字段 sum_connect_errors 的值的大小,同时也跟 count_handshake_errors 相关;

表host_cache中字段 count_authentication_errors 的值大小,表示连接数据库时使用了错误的密码的次数。目前好像没有参数,可以使用 MySQL 插件控制。

 

 

 

 

  • 20
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值