一、问题现象
XXL-Job 登录时报错:
org.springframework.jdbc.CannotGetJdbcConnectionException:
Failed to obtain JDBC Connection
继续查看 XXL-Job 应用日志,发现底层异常:
Caused by: com.mysql.cj.exceptions.CJException:
Host '10.0.0.10' is blocked because of many connection errors;
unblock with 'mysqladmin flush-hosts'
XXL-Job 是一个 Java 任务调度应用,xxl-job-admin 通过 JDBC 连接 MySQL。
二、问题原因
MySQL 参数:
SHOW VARIABLES LIKE 'max_connect_errors';
默认通常为:
max_connect_errors = 100
当某个来源 IP 连续发生较多连接异常,达到该阈值后,MySQL 会通过 Host Cache 临时封锁该 IP。
例如:
Host '10.0.0.10' is blocked
这里封锁的是 来源 IP,不是某个数据库账号,也不是某一条 JDBC 连接。
该 IP 被封后,从这个 IP 发起的后续新连接都会受到影响。
三、排查过程
先排除最大连接数问题:
SHOW VARIABLES LIKE 'max_connections';
SHOW GLOBAL STATUS LIKE 'Threads_connected';
SHOW GLOBAL STATUS LIKE 'Max_used_connections';
SHOW GLOBAL STATUS LIKE 'Connection_errors_max_connections';
如果当前连接很少、历史峰值也没有达到 max_connections,则说明不是连接数打满。
继续查看应用日志中的最底层:
Caused by:
最终发现:
Host '10.0.0.10' is blocked because of many connection errors
即可确认是 Host Block。
四、处理方法
建议先查看 Host Cache 留证:
SELECT
IP,
SUM_CONNECT_ERRORS,
COUNT_HOST_BLOCKED_ERRORS,
COUNT_HANDSHAKE_ERRORS,
COUNT_AUTHENTICATION_ERRORS
FROM performance_schema.host_cache;
然后解除封锁:
TRUNCATE TABLE performance_schema.host_cache;
也可以使用:
FLUSH HOSTS;
二选一即可,不需要重启 MySQL。
五、调整参数
为避免少量连接异常过快触发封锁,可以适当提高:
SET GLOBAL max_connect_errors = 1000;
验证:
SHOW VARIABLES LIKE 'max_connect_errors';
同时写入 /etc/my.cnf:
[mysqld]
max_connect_errors=1000
这样当前立即生效,并保证 MySQL 重启后仍然生效。
六、恢复验证
查看应用是否重新连接数据库:
SELECT
USER,
HOST,
DB,
COMMAND
FROM information_schema.PROCESSLIST
WHERE DB='xxl_job';
然后重新访问 XXL-Job 页面验证。
七、注意事项
max_connections 和 max_connect_errors 不是一个概念:
| 参数 | 作用 |
|---|---|
max_connections |
MySQL 最大并发连接数 |
max_connect_errors |
某来源 IP 连续连接异常的封锁阈值 |
本次故障真正相关的是:
max_connect_errors
提高到 1000 只是降低再次被快速封锁的概率,真正根因还需要继续排查:
-
JDBC 连接池频繁重试
-
网络短暂异常
-
MySQL 短暂不可用
-
数据库账号或 Host 授权异常
-
JDBC 握手或 SSL 异常
八、快速排查 SOP
以后再次遇到:
Failed to obtain JDBC Connection
直接按以下顺序:
检查 MySQL 服务
↓
检查当前连接数
↓
排除 max_connections
↓
查看应用日志最底层 Caused by
↓
发现 Host is blocked
↓
查询 host_cache 留证
↓
清理 host_cache
↓
调整 max_connect_errors
↓
验证应用恢复
总结
本次问题本质是:
XXL-Job 连续出现 MySQL 连接异常,达到
max_connect_errors阈值后,MySQL 封锁了来源 IP,导致后续新的 JDBC 连接被拒绝。
应急恢复:
TRUNCATE TABLE performance_schema.host_cache;
优化:
max_connect_errors=1000
最后记住一点:
遇到
Failed to obtain JDBC Connection,不要只看页面报错,要继续找最底层Caused by。