网站首页 > 技术文章 正文
我们线上一个项目在发版本时,经常会有部分实例无法正常启动的情况,特别是在没有进行灰度发布的场景下,基本上很难正常的启动成功,异常信息如下:
问题分析
看日志可以很容易看出来,启动异常的原因是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了。
异常流程
- dubbo服务成功暴露
- dubbo请求进入,存在DB请求,调用getConnection初始化连接时,sealed = true
- spring容器创建数据源,设置属性时发现sealed = true,抛出异常
- 服务启动失败
回到最开始的现象,特别是在没有进行灰度发布的场景下,基本上很难正常的启动成功 。在灰度发布时,是服务启动后,才会转发部分流量到灰度容器,所以dubbo是否提前暴露并没有影响,因为在启动过程中并没有请求进入。但是在非灰度发布场景下,由于dubbo服务一暴露,马上就有请求进入,所以导致启动异常。
解决
知道问题产生的原因,就很容易解决问题了,解决方式很简单,让dubbo的服务在spring容器启动后暴露即可,从dubbo的文档可以看到,2.6.5之后不会再出现这种弱智问题了,但是我们的服务比较旧,用的2.6.3的版本,所以需要配置delay=-1,或者设置一个较长的delay时间。
- 上一篇: Seata源码—6.Seata AT模式的数据源代理一
- 下一篇: 如何优化一个秒杀项目?
猜你喜欢
- 2025-06-07 Tomcat服务器的部署与优化:从入门到精通
- 2025-06-07 连接池之HikariCP:HikariCP框架设计与功能使用分析(第一部分)
- 2025-06-07 一次完整的HTTP请求与响应涉及了哪些知识?
- 2025-06-07 Excel常用技能分享与探讨(5-宏与VBA简介 VBA之用户窗体-一)
- 2025-06-07 编程英文 - 配置/设置/初始化 (configure/setup/initialize)
- 2025-06-07 Qt/C++编写音视频实时通话/画中画/设备热插拔/本地摄像头和桌面
- 2025-06-07 基于c++的数据库连接池的实现与理解
- 2025-06-07 如何优化一个秒杀项目?
- 2025-06-07 Seata源码—6.Seata AT模式的数据源代理一
- 2025-06-07 tornado学习笔记19 Tornado框架分析
- 06-22Python开发工程师必会的3个设计模式(工厂、单例、适配器)
- 06-22创建型设计模式——工厂模式和抽象工厂模式
- 06-221. 工厂模式详解
- 06-22工厂模式详解
- 06-22设计模式问题:说一说简单工厂模式?
- 06-22深入设计模式:工厂方法
- 06-22C++设计模式——简单工厂模式
- 06-22什么是工厂模式?工厂模式有哪些类型?如何使用它们?
- 最近发表
- 标签列表
-
- axure 注册码 (25)
- exploit db (21)
- mutex_lock (30)
- oracleclient (27)
- think in java (14)
- javascript权威指南 (19)
- nfs (25)
- componentart (17)
- yii框架 (14)
- springbatch (28)
- oracle数据库备份 (25)
- iptables (21)
- 自动化单元测试 (18)
- mvc模式 (13)
- python编写软件 (14)
- dir (26)
- connectionstring属性尚未初始化 (23)
- output (32)
- panel滚动条 (28)
- centos 5 4 (23)
- sql学习 (33)
- dfn (14)
- http error 503 (21)
- pop3服务器 (18)
- 图表组件 (17)