连接池清空 Hibernate 4,但无法找到罪魁祸首
Connection Pool Empty Hibernate 4, but Unable to Find the Culprit
我每 5 分钟监控一次 SQL 数据库的连接。几天来它会徘徊在 5 个连接左右(我的空闲),然后突然我变成了 50。显然这是一个递归问题,因为我不明白为什么我会在 5 分钟内在零流量的情况下从 5 跳到 50。
我正在使用 Hibernate 4 和 Tomcat 我知道 Hibernate 中的一个问题已在 4.3.2 中修补,但我使用的是 4.3.5
更多详情:
池清空事件每天恰好在 7:13:20PM 发生...听起来太自动了。我正在使用 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 服务器 2012
更多信息:
我将石英工作频率降低到每 5 分钟一次。当我在应用程序中加载 page/view 时,事件仍然发生。这大约是在 7:14 下午。
我正处于降级到休眠 3 的边缘。
更新
今天我在 Tomcat 下午 6:50 管理器中重新加载了应用程序,但事件仍然发生。
Thread Dump
啊,那种 bug 很有趣。显然,我们无法指出确切的罪魁祸首(除非有人在您提到的库中发现错误),所以让我们看看如何调试它。大致从易到难,但具体取决于您的环境。
您提供了非常有用的信息:问题总是同时发生。这暗示了两种选择:您使用 Quartz 运行 的一项工作耗尽了连接,或者当时发生了某些事情(可能是外部的)导致您的代码耗尽了连接。显然,您应该检查您的作业配置和 cron 作业或在数据库中配置的作业或类似的潜在罪魁祸首。请注意,它们可能会提前一段时间开始,稍后才到达该临界状态,因此据我们所知,作业可能会提前 2 小时开始。
检查您的日志、系统日志和数据库日志,了解当时或之前发生的任何事情。
仔细检查所有获得连接的东西,如果它总是 returns 连接。特别是当抛出异常时。失败的一种经典方法是这样的构造(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
}
建立日志记录,让您可以看到确切的连接何时没有返回。在你的应用程序中启动任何东西的一切都应该通过某种包装器(围绕 Aspect、Servlet 过滤器或类似的 AOP)。该包装器应执行以下操作:为操作创建一个唯一 ID (UUID) 并放入 MDC of your logging framework。在操作结束时,id 再次被删除。所有其他日志记录都应包含该 ID。也包装你的连接池。跟踪请求连接的时间,包括时间戳、id 和可能的堆栈跟踪(通过创建和存储异常)。记录那个。每次返回连接时记录它的使用时间。此外,每次请求连接时,检查是否有任何连接使用的时间超过某个阈值。
隔离事物:设置第二个服务器,运行 应用程序。它有同样的问题吗? 运行 某些部分仅在两台服务器中的一台上,他们仍然有问题吗?继续排除候选人,直到只剩下一个。
如果我遇到这样的问题,我会尽力获取最大活动连接数达到 50 时的线程转储。
您可以尝试增加此 maxActive 限制以检查应用程序是否具有更高的峰值。
我还会配置 tomcat 使用连接池提供程序,例如 c3p0,如果它尚未被使用的话。然后,我会创建一个自定义挂钩 class,如以下部分所述:
http://www.mchange.com/projects/c3p0/#connection_customizers
使用此自定义 class 保留获取和释放的连接的 运行 计数器。当此数字接近或达到限制时,以编程方式启动线程转储。这可以按照以下页面中的描述来完成:
http://crunchify.com/how-to-generate-java-thread-dump-programmatically/
分析此线程转储以检查连接源。
此信息不仅对您当前的问题有用,而且对解决未来的性能问题也很有用。
我构建了一个 Connection Pool monitoring tool,称为 FlexyPool,它可能会帮助您找出罪魁祸首。它也支持 TomcatCP,您可以将其指标与您当前使用的其他日志相关联,
connection lease time histogram
应该告诉您连接保持了多长时间,这意味着您可能有一些缓慢的查询。
concurrent connections histogram
告诉您一次使用了多少个连接,如果少于 50 个,则存在连接泄漏问题。
首先感谢大家提供的答案。就像@JensSchauder 建议的那样,我正在努力找出问题所在。想知道为什么我在 QA 中没有问题,但在生产中却出现了。
尽管我与我的网络运营团队进行了跟进,但在我最终获得我需要的日志之前,没有人注意到它。
我们使用一个名为 Alert Logic 的产品来扫描和识别安全漏洞,但不幸的是,直到我能够追踪 Apache 访问日志到一个 IP 地址,它才被发现是罪魁祸首。 whois 识别出来自 Rackspace 主机的 Alert Logic 软件的 IP。
应用程序服务器是新的,由新的体系结构映像组成。事实证明,Alert Logic 发现了一个漏洞。然后这导致连接池清空(bailing?)
直到上周中旬,我才知道 Alert Logic 甚至在等式中。事实上,现在,我正在与网络运营部门合作,以便更好地观察产品失效后的情况。
本周晚些时候,我将在 QA 期间发布该漏洞的调查结果(因为修补生产是优先事项)。
我每 5 分钟监控一次 SQL 数据库的连接。几天来它会徘徊在 5 个连接左右(我的空闲),然后突然我变成了 50。显然这是一个递归问题,因为我不明白为什么我会在 5 分钟内在零流量的情况下从 5 跳到 50。
我正在使用 Hibernate 4 和 Tomcat 我知道 Hibernate 中的一个问题已在 4.3.2 中修补,但我使用的是 4.3.5
更多详情: 池清空事件每天恰好在 7:13:20PM 发生...听起来太自动了。我正在使用 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 服务器 2012
更多信息: 我将石英工作频率降低到每 5 分钟一次。当我在应用程序中加载 page/view 时,事件仍然发生。这大约是在 7:14 下午。 我正处于降级到休眠 3 的边缘。
更新 今天我在 Tomcat 下午 6:50 管理器中重新加载了应用程序,但事件仍然发生。 Thread Dump
啊,那种 bug 很有趣。显然,我们无法指出确切的罪魁祸首(除非有人在您提到的库中发现错误),所以让我们看看如何调试它。大致从易到难,但具体取决于您的环境。
您提供了非常有用的信息:问题总是同时发生。这暗示了两种选择:您使用 Quartz 运行 的一项工作耗尽了连接,或者当时发生了某些事情(可能是外部的)导致您的代码耗尽了连接。显然,您应该检查您的作业配置和 cron 作业或在数据库中配置的作业或类似的潜在罪魁祸首。请注意,它们可能会提前一段时间开始,稍后才到达该临界状态,因此据我们所知,作业可能会提前 2 小时开始。
检查您的日志、系统日志和数据库日志,了解当时或之前发生的任何事情。
仔细检查所有获得连接的东西,如果它总是 returns 连接。特别是当抛出异常时。失败的一种经典方法是这样的构造(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 }
建立日志记录,让您可以看到确切的连接何时没有返回。在你的应用程序中启动任何东西的一切都应该通过某种包装器(围绕 Aspect、Servlet 过滤器或类似的 AOP)。该包装器应执行以下操作:为操作创建一个唯一 ID (UUID) 并放入 MDC of your logging framework。在操作结束时,id 再次被删除。所有其他日志记录都应包含该 ID。也包装你的连接池。跟踪请求连接的时间,包括时间戳、id 和可能的堆栈跟踪(通过创建和存储异常)。记录那个。每次返回连接时记录它的使用时间。此外,每次请求连接时,检查是否有任何连接使用的时间超过某个阈值。
隔离事物:设置第二个服务器,运行 应用程序。它有同样的问题吗? 运行 某些部分仅在两台服务器中的一台上,他们仍然有问题吗?继续排除候选人,直到只剩下一个。
如果我遇到这样的问题,我会尽力获取最大活动连接数达到 50 时的线程转储。 您可以尝试增加此 maxActive 限制以检查应用程序是否具有更高的峰值。
我还会配置 tomcat 使用连接池提供程序,例如 c3p0,如果它尚未被使用的话。然后,我会创建一个自定义挂钩 class,如以下部分所述: http://www.mchange.com/projects/c3p0/#connection_customizers
使用此自定义 class 保留获取和释放的连接的 运行 计数器。当此数字接近或达到限制时,以编程方式启动线程转储。这可以按照以下页面中的描述来完成: http://crunchify.com/how-to-generate-java-thread-dump-programmatically/ 分析此线程转储以检查连接源。
此信息不仅对您当前的问题有用,而且对解决未来的性能问题也很有用。
我构建了一个 Connection Pool monitoring tool,称为 FlexyPool,它可能会帮助您找出罪魁祸首。它也支持 TomcatCP,您可以将其指标与您当前使用的其他日志相关联,
connection lease time histogram
应该告诉您连接保持了多长时间,这意味着您可能有一些缓慢的查询。
concurrent connections histogram
告诉您一次使用了多少个连接,如果少于 50 个,则存在连接泄漏问题。
首先感谢大家提供的答案。就像@JensSchauder 建议的那样,我正在努力找出问题所在。想知道为什么我在 QA 中没有问题,但在生产中却出现了。
尽管我与我的网络运营团队进行了跟进,但在我最终获得我需要的日志之前,没有人注意到它。
我们使用一个名为 Alert Logic 的产品来扫描和识别安全漏洞,但不幸的是,直到我能够追踪 Apache 访问日志到一个 IP 地址,它才被发现是罪魁祸首。 whois 识别出来自 Rackspace 主机的 Alert Logic 软件的 IP。
应用程序服务器是新的,由新的体系结构映像组成。事实证明,Alert Logic 发现了一个漏洞。然后这导致连接池清空(bailing?)
直到上周中旬,我才知道 Alert Logic 甚至在等式中。事实上,现在,我正在与网络运营部门合作,以便更好地观察产品失效后的情况。
本周晚些时候,我将在 QA 期间发布该漏洞的调查结果(因为修补生产是优先事项)。