数据库连接池提前初始化引发的异常

背景

我们线上一个项目在发版本时,经常会有部分实例无法正常启动的情况,特别是在没有进行灰度发布的场景下,基本上很难正常的启动成功,异常信息如下:

问题分析

看日志可以很容易看出来,启动异常的原因是hikari的配置绑定异常,原因是hikari的连接池已经seal了:The configuration of the pool is sealed once started.

字面意思:连接池配置一旦启动就被密封。那么问题来了,这个状态是怎么设置的?我的服务明明还没有启动;就算设置了,理论上配置初始化应该只会初始经一次,为什么会报错?

sealed状态设置

我们先看一下hikari的源码,找一下连接池的sealed状态是怎么设置的:

HikariConfig中查看设置sealed字段的方法,查看它的调用链路,发现只有两个地方调用了此方法来设置sealed状态为true,一个是构造函数,也就是初始化数据源时:

另一个是获取连接时:

可以看到,在HikariConfig构造函数中,会先初始化连接池,然后设置sealed状态。在getConnection时,会判断连接池是不是已经被初始化了,如果没有,则会初始化连接池,并设置sealed状态。

异常来源

我们现在知道sealed状态的设置时机,那么The configuration of the pool is sealed once started. 这个异常又是什么时候被抛出的呢,同样是在HikariConfig中搜索对应异常,可以看到这个异常都是通过checkIfSealed方法抛出,很明显,这个方法就是检查sealed状态的,查看它的调用链路:

可以看到,在设置HikariConfig的任意属性时,都会先检查状态。这么看来,sealed其实就是为了在连接池初始化完成之后,不允许再动态的去更新配置(可以使用其它的方式),那么理论上来说,Spring容器还在启动过程中, 为什么在设置属性之前,sealed状态就已经被设置的呢?

异常原因

我们回过去再去看一下启动日志,通过上面的源码,我们可以看到在初始化连接池的前后,都会打印INFO日志,那么我们可以搜索对应的日志查看连接池的初始化情况:

从日志中可以看到,我们前面两个数据源都正常初始化完成了(主从数据库),但是后面马上又报错了(Spring绑定属性),好像看不出什么来,但是如果我们关注一下日志打印对应的线程就可以发现,初始化连接池和报错的线程并不是同一个!前面的初始化日志,都是在dubbo线程中打印的,而后面报错的日志,是在main线程中。

这时候就很明显了,上面说到,sealed状态不仅在构造函数中设置,在getConnection时也会去初始化连接池并更新状态。这明显就是spring容器还在初始化中,但是dubbo服务已经提前暴露了,导致有请求进来开始请求DB了。

异常流程

  1. dubbo服务成功暴露
  2. dubbo请求进入,存在DB请求,调用getConnection初始化连接时,sealed = true
  3. spring容器创建数据源,设置属性时发现sealed = true,抛出异常
  4. 服务启动失败

回到最开始的现象,特别是在没有进行灰度发布的场景下,基本上很难正常的启动成功 。在灰度发布时,是服务启动后,才会转发部分流量到灰度容器,所以dubbo是否提前暴露并没有影响,因为在启动过程中并没有请求进入。但是在非灰度发布场景下,由于dubbo服务一暴露,马上就有请求进入,所以导致启动异常。

解决

知道问题产生的原因,就很容易解决问题了,解决方式很简单,让dubbo的服务在spring容器启动后暴露即可,从dubbo的文档可以看到,2.6.5之后不会再出现这种弱智问题了,但是我们的服务比较旧,用的2.6.3的版本,所以需要配置delay=-1,或者设置一个较长的delay时间。

相关推荐
一只叫煤球的猫4 小时前
写代码很6,面试秒变菜鸟?不卖课,面试官视角走心探讨
前端·后端·面试
bobz9655 小时前
tcp/ip 中的多路复用
后端
bobz9655 小时前
tls ingress 简单记录
后端
皮皮林5516 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
你的人类朋友6 小时前
什么是OpenSSL
后端·安全·程序员
bobz9656 小时前
mcp 直接操作浏览器
后端
前端小张同学9 小时前
服务器部署 gitlab 占用空间太大怎么办,优化思路。
后端
databook9 小时前
Manim实现闪光轨迹特效
后端·python·动效
武子康9 小时前
大数据-98 Spark 从 DStream 到 Structured Streaming:Spark 实时计算的演进
大数据·后端·spark
该用户已不存在10 小时前
6个值得收藏的.NET ORM 框架
前端·后端·.net