spring - Spring Java 应用程序更改如何导致“无法验证连接”Hikari 池错误?
问题描述
我的团队本周在部署看似无害的代码更改期间遇到了一系列奇怪的错误,我正在寻找可能发生的事情的指针。我们无法在非生产环境中重现该问题,并且在我们了解该问题之前不愿重新部署。
我们正在使用 Java Spring Boot、Hibernate、Postgres 和 Hikari。代码更改是一种非功能性重构,将大型服务类FooService
拆分为两个类FooReadService
和FooUpsertService
. 所有这三个都在班级级别上用@Transactional
.
以下是我们在部署这些更改后立即观察到的日志系列。如您所见,第一个错误与验证 Hikari 数据库连接失败有关。随后的错误是关于无法建立数据库连接,然后在只读事务中执行写入。
有趣的是,在只读事务中执行写入的错误发生在几个与此特定更改完全无关的代码路径中。在事件期间,读取似乎工作成功。这是我们在生产运行大约一年后第一次看到这样的错误。
理论
@Transactional
与将带有注释的单个类拆分为两个类有关的事情会导致数据库连接问题。也许事务边界没有被重用?我们没有改变默认的传播行为REQUIRED
。- 在我们的部署管道中发生了与此 PR 完全无关的事情,导致此特定部署出现问题。
- 仅在高请求量时才表现出来的东西。(在此部署窗口期间请求量很典型,但这可能解释了本地与生产行为之间的差异。)
问题
- Hikari 出现“无法验证连接”错误的可能根本原因是什么?
- 所有其他错误是否只是此错误的下游后果?“无法验证连接”错误如何导致“无法执行 SELECT FOR UPDATE”错误?
- 哪些类型的 Java 应用程序逻辑更改可能会导致这些类型的错误?
- 单元测试、集成测试、本地开发测试会成功但生产会失败的一些原因是什么?(不同的环境配置,不同的流量……)
- 我们可以做些什么来证明或反驳上述理论?
我的下一步是模拟应用此更改的本地实例的更多流量,并查看这是否会导致问题出现。但非常感谢任何指点。
事件期间的日志
2021-03-24 15:30:38 - 无法验证连接
com.zaxxer.hikari.pool.PoolBase: HikariPool-1 - Failed to validate connection org.postgresql.jdbc.PgConnection@3e1fe46b (This connection has been closed.). Possibly consider using a shorter maxLifetime value.
2021-03-24 15:30:53 - 无法获取 JDBC 连接
org.springframework.dao.DataAccessResourceFailureException: Unable to acquire JDBC Connection; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
2021-03-24 15:30:55 - 无法打开 JPA EntityManager 进行交易
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
2021-03-24 10:35:54 - 无法在只读事务中执行 SELECT FOR UPDATE
o.h.engine.jdbc.spi.SqlExceptionHelper: ERROR: cannot execute SELECT FOR UPDATE in a read-only transaction
org.springframework.orm.jpa.JpaSystemException: could not extract ResultSet; nested exception is org.hibernate.exception.GenericJDBCException: could not extract ResultSet
解决方案
推荐阅读
- jquery - jQuery:从元素中提取值并将其插入可重复列表表单字段的字段中
- tensorflow - 如何确保训练阶段不会面临OOM?
- java - 如何在Java中通过增加循环来获取数量增加的变量(以获取所述变量的值)?
- asp.net-mvc - 自定义身份用户
- sql-server - 每周获取最新的数量更新
- flutter - Flutter中如何在NetworkImage()中添加网络图片列表
- javascript - 使用 Vue js 的单页应用程序的 Web 堆栈
- algorithm - 什么是容器,与其他数据结构有什么区别?
- docker - Traefik 实例无法解析 TLS 握手,如何从 v1.7.17 重新配置到 v2.0.2?
- c# - 如何通过 UIViewController 将表格置于后台?