【问题标题】:Connection Pool Empty Hibernate 4, but Unable to Find the Culprit连接池为空 Hibernate 4,但无法找到罪魁祸首
【发布时间】:2015-05-13 21:04:21
【问题描述】:

我每 5 分钟监控一次 SQL 数据库的连接。几天来,它会徘徊在 5 个连接(我的空闲)左右,然后突然我达到 50。显然这是一个递归问题,因为我不明白为什么我会在 5 分钟内从 5 跳到 50,流量为零。

我正在使用 Hibernate 4 和 Tomcat,我知道 Hibernate 中的一个问题已在 4.3.2 中进行了修补,但我使用的是 4.3.5

更多详情: 每天晚上 7:13:20 都会发生池空事件……听起来太自动了。我正在使用 Quartz,它每 1 分钟运行一次,但我看不出它们之间的关系。

我的属性:

jmxEnabled = true
initialSize = 5
maxActive = 50
minIdle = 5
maxIdle = 25
maxWait = 10000
maxAge = 10 * 60000
timeBetweenEvictionRunsMillis = 5000
minEvictableIdleTimeMillis = 60000
validationQuery = "SELECT 1"
validationQueryTimeout = 3
validationInterval = 15000
testOnBorrow = true
testWhileIdle = true
testOnReturn = false
jdbcInterceptors = "ConnectionState"
defaultTransactionIsolation = java.sql.Connection.TRANSACTION_READ_COMMITTED

环境:

  • Tomcat 7.0.59
  • java 1.7.0 更新76
  • SQL Server 2012

更多信息: 我将石英工作频率降低到每 5 分钟一次。当我在应用程序中加载页面/视图时,该事件仍然发生。这大约是晚上 7 点 14 分。 我即将降级到休眠 3。

更新 今天下午 6:50 我在 Tomcat 管理器中重新加载了应用程序,但事件仍然发生。 Thread Dump

【问题讨论】:

  • 我删除了 parent->child tomcat 守护进程,现在我只有 10 个适当命名的quartz-workers。
  • 你使用的是什么类型的连接池?我发现有时尝试 Hikari 或其他 CP 提供商可以帮助自己调试语句以跟踪这些类型的问题。在测试环境中试一试可能是个好主意。
  • @bphilinyc 除了 tomcat 之外,我还没有尝试过其他提供商。但是,我确实部署到了 QA 环境,但没有遇到同样的问题。非常本地化,很可能是外部的。

标签: hibernate tomcat transactions sql-server-2012 connection-pooling


【解决方案1】:

啊,那些错误很有趣。显然,我们无法为您指出确切的罪魁祸首(除非有人在您提到的库中挖掘了错误),所以让我们看看如何调试它。虽然细节取决于您的环境,但大致从易到难。

  1. 您有非常有用的信息:问题总是同时发生。这暗示了两种选择:您使用 Quartz 运行的一项作业占用了连接,或者当时正在发生某些事情(可能是外部的)导致您的代码占用连接。显然,您应该检查您的作业配置和 cron 作业或在数据库中配置的作业或类似的潜在罪魁祸首。请注意,它们可能会提前相当长的时间开始,稍后才到达该临界状态,因此据我们所知,该作业可能会提前 2 小时开始。

  2. 检查您的日志、系统日志和数据库日志,了解当时或之前发生的任何事情。

  3. 如果它总是返回连接,请仔细检查获得连接的所有内容。特别是当抛出异常时。一种失败的经典方法是这样的构造(类似java的伪代码):

    Connection con;
    
    try {
        con = getConnection();
        Statement = stmnt = con.createStatement();
        ....
    } finally (Exception ex){
        if (stmnt != null) stmnt.close();
        if (con != null) con.close(); // this will never happen if stmnt.close throws an exceptions
    
    }
    
  4. 建立日志记录,让您查看何时未返回确切的连接。在你的应用程序中启动任何东西的所有东西都应该通过某种包装器(AOP 围绕 Aspect、Servlet 过滤器或类似的)。该包装器应执行以下操作:为操作 (UUID) 创建一个唯一 id 并放入 MDC of your logging framework。在 id 再次被删除的操作结束时。所有其他日志记录都应包含该 ID。包装你的连接池。跟踪请求连接的时间,包括时间戳、id 和可能的堆栈跟踪(通过创建和存储异常)。记录下来。每次返回连接时都会记录它的使用时间。此外,每次请求连接时,请检查是否有任何连接的使用时间超过某个阈值。

  5. 隔离事物:设置第二台服务器,在其中运行应用程序。它有同样的问题吗?仅在两台服务器之一上运行某些部分,它们仍然有问题吗?继续排除候选人,直到只剩下一个。

【讨论】:

  • #3 中的示例代码在每个 close() 调用周围缺少 try/catch 块。如果调用close() 抛出异常,它将(a) 屏蔽原始异常,(b) 如果Statement.close() 失败,连接不会关闭。
  • @ChristopherSchultz 正是,这就是示例代码的重点。
  • 这会使代码变得脆弱。您应该在现有的 try/catch 块中有两个嵌套的 try/catch 块。
  • @ChristopherSchultz 抱歉,你在看我写的吗?这就是这个例子的重点。这是 OP 应该寻找的问题。这就是它有注释的原因: // 如果 stmnt.close 抛出异常,这将永远不会发生
  • 是的,我正在阅读您所写的内容。仅仅记录它不会发生是不够的。你应该有一个嵌套的 try/catch 来保证如果stmnt.close 抛出异常,它仍然会发生。此外,如果stmnt.close()(或con.close())抛出异常,任何原始的运行中异常都将丢失,从而掩盖可能更大的问题。我只是认为,如果您要展示执行此类代码的“正确”方式的示例,您不妨发布一个示例……好吧,正确
【解决方案2】:

如果我遇到这样的问题,我会尽力获取 maxActive 连接数达到 50 时的线程转储。 您可以尝试增加此 maxActive 限制以检查应用程序是否有更高的峰值。

如果尚未使用连接池提供程序,例如 c3p0,我还将配置 tomcat。然后,我将创建一个自定义钩子类,如下节所述: http://www.mchange.com/projects/c3p0/#connection_customizers

使用这个自定义类,可以保持正在获取和释放的连接的运行计数器。当此数字接近或达到限制时,以编程方式启动线程转储。这可以按照以下页面中的说明完成: http://crunchify.com/how-to-generate-java-thread-dump-programmatically/ 分析此线程转储以检查连接源。

此信息不仅有助于解决您当前的问题,还有助于解决未来的性能问题。

【讨论】:

    【解决方案3】:

    我构建了一个名为 FlexyPool 的 Connection Pool monitoring tool,它可能会帮助您找出罪魁祸首。它也支持 TomcatCP,您可以将其指标与您当前使用的其他日志关联起来,

    connection lease time histogram 应该告诉您连接保持了多长时间,这意味着您可能会遇到一些缓慢的查询。

    concurrent connections histogram 告诉您一个连接使用了多少个,如果少于 50 个,则说明存在连接泄漏问题。

    【讨论】:

      【解决方案4】:

      首先我要感谢大家提供您的答案。就像@JensSchauder 建议的那样,我正在努力找出问题所在。想知道为什么我在 QA 中没有遇到问题,但在生产中却遇到了。

      尽管我跟进了我的网络运营团队,但直到我最终得到我需要的日志之前,没有任何人参与其中。

      我们使用名为 Alert Logic 的产品来扫描和识别安全漏洞,但不幸的是,直到我能够将 Apache 访问日志追踪到某个 IP 地址后,才发现它是罪魁祸首。 whois 从 Rackspace 主机中识别出源自 Alert Logic 软件的 IP。

      应用程序服务器是新的,由新的架构映像组成。事实证明,Alert Logic 遇到了一个漏洞。然后这导致连接池清空(保释?)

      直到上周中旬,我才知道 Alert Logic 甚至在等式中。事实上,现在,我正在与 Network Operations 合作,以便更好地观察该产品,因为它已经失效了。

      本周晚些时候,我将在 QA 期间发布漏洞调查结果(因为修补生产是优先事项)。

      【讨论】:

        猜你喜欢
        • 2015-04-09
        • 1970-01-01
        • 2012-05-23
        • 2015-04-04
        • 1970-01-01
        • 2022-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多