- 错误描述如图:
- 错误背景:
使用 SpringBoot + Druid + myqsl 开发应用服务,使用 Nginx 做 4 层代理转发到 Mysql 服务端。服务启动后再 swagger 上第一次访问接口是正常的,但是过了几十秒后再访问就报错了,后面就再也发不通了。一直提示无法建立连接
Communications link failure. The last packet successfully received from the server was 177,731 milliseconds ago. The last packet sent successfully to the server was 177,735 milliseconds ago.
- 初步分析:
作为一名合格的程序员,必须有独立解决问题的能力(当然在我们部门,我也没有可以求救的人了),遇到不认识的异常就要会百度、Google~ 但是我左搜右搜上搜下搜,都找不到正确的解决方案。无奈,只能靠自己了。仔细看了下异常信息,是从 com.alibaba.druid 里抛出来的,难道是连接池的问题?于是我把 Druid 连接池换成了 HikariCP,结果是可以正常访问数据库了,赶紧提交代码,别耽误其他同事的开发。
数据库不可访问的危机是解除了,但是日志里还是会打印一堆 warn 警告。如图:
我是一个略有强迫症的程序员,解决问题必须要知其然且知其所以然,还有 warn 警告,说明问题并没有从根源上解决。于是我又仔细分析了下警告提示 从服务器成功接收到的最后一个数据包是177,731毫秒前。最后一个成功发送到服务器的数据包是177,735毫秒之前)。可以考虑使用更短的maxLifetime值
,难道是配置有问题?我将 max-lifetime
值调小,发现并没有任何作用。
“Communications link failure 是通讯链路故障...接收数据包...发送数据包”,猜想问题可能出在通讯链路上。由于我的 mysql 是在内网服务器上的,没有直接将 msyql 服务器暴露到外网上,所以需要在 nginx 服务器做一个 4 层代理。我开始怀疑是不是 nginx 配置有问题呢,以下是我 nginx 的配置。
proxy_connect_timeout 是 nginx 连接上游服务超时时间,如果配置多个上游服务节点,且 nginx 路由到的第一个上游服务不可用时,连接超过设置的超时时间,nginx 会自动将请求路由到其他上游服务节点。
proxy_timeout 是如果指定时间内,客户端没有请求发送过来,nginx 会断开与上游节点的链接,以节省资源(查了以后才知道的)。
Mysql 客户端与服务端之间是 TCP 长链接,在 Mysql 上是可以看到连接数的。于是我登录了 mysql,进行了连接数的查询。show status like 'Threads%';
当我服务停止时,连接数为 1,当我启动服务并进行一次接口调用后(会访问数据库),连接数变成了 6。说明数据库根据我代码里配置的 minimum-idel
为 5 初始化了 5 个连接。
10s 后再次查看连接数变成了 1,说明数据库认为客户端连接断开了,释放了 5 个连接。
再次访问接口变成了 6,说明 hikariCP 默认实现了自动重连,数据库根据配置又重新创建了 5 个连接。
停止服务又变成了 1,说明数据库识别到客户端断开后,释放了 5 个连接。
我们可以通过 show processlist;
命令看一下数据库进程信息的状态。
最开始连接数为 0,没有任何连接信息,只有执行 show processlist
命令的查询进程。
服务启动后,数据库不会立即创建连接进程,调用一次查询后出现了 5 个进程,并且可以看到用户及其 DB。Time 为进程存在时间
可以看到 Time 增长到 10s 后,会自动消失。
总结
经过上面验证过程后,确定连接断开时间是与 Nginx 的 proxy_timeout 保持一致的,于是我把 proxy_timeout 配置取消后,观察连接是正常的,可持续到我们配置的 interactive_timeout 值。
(1)interactive_timeout:
参数含义:服务器关闭交互式连接前等待活动的秒数。交互式客户端定义为在 mysql_real_connect()中使用 CLIENT_INTERACTIVE 选项的客户端。
参数默认值:28800 秒(8 小时)
(2)wait_timeout:
参数含义:服务器关闭非交互连接之前等待活动的秒数。
在线程启动时,根据全局 wait_timeout 值或全局 interactive_timeout 值初始化会话 wait_timeout 值,取决于客户端类型(由 mysql_real_connect()的连接选项 CLIENT_INTERACTIVE 定义)。
参数默认值:28800 秒(8 小时)
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于