【问题标题】:HikariCP - Load testing degrades performance to a haltHikariCP - 负载测试使性能下降到停止
【发布时间】:2018-11-16 05:40:42
【问题描述】:

我一直在我的 Spring Boot 应用程序上使用 HikariCP,我开始使用 JMeter 进行一些负载测试。

我注意到我第一次运行测试时运行良好,每个请求大约需要 30 毫秒。

但是每次我针对同一个应用程序实例再次运行我的测试时,响应时间会变得更糟,直到它冻结并且我得到很多

Caused by: java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30019ms.
    at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:583)
    at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:186)
    at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:145)
    at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:112)
    at sun.reflect.GeneratedMethodAccessor501.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at net.bull.javamelody.JdbcWrapper$3.invoke(JdbcWrapper.java:805)
    at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:286)
    at com.sun.proxy.$Proxy102.getConnection(Unknown Source)
    at org.springframework.jdbc.datasource.DataSourceTransactionManager.doBegin(DataSourceTransactionManager.java:246)
    ... 108 common frames omitted

我什至将应用程序搁置了一天并再次尝试,但测试显示性能下降和相同的错误。

只有当我关闭应用程序时,它才能再次运行我的测试,但只有一次负载(1200 多个请求)。

当我开发测试时,我使用 H2 数据库运行本地应用程序,直到我将应用程序部署到运行 postgresql 的服务器上后才发现性能下降。

所以为了消除这个变量,我让 JMeter 在我的本地 H2 应用程序上运行,并且性能下降。

这是我在本地应用程序(H2 数据库)上运行的测试场景,默认 HikariCP 轮询大小 (10),使用 10 个线程。在应用程序停止响应之前,我设法运行了 25000 多个请求。

我绘制了请求:

此外,测试包括对 Spring Boot @RestController 的请求。

我的控制器调用了一个在开始时具有 @Transactional 的服务(我调用了一些需要事务存在的遗留 API,因此我立即打开它)。

假设我的测试并行请求此端点 10 次。假设我的代码可能还有其他点用@Transactional 注释。 10 个投票大小就足够了吗?

此外,任何投票规模是否都足够,尽管性能很差,还是“正常”出现这种投票只是太忙而“锁定”的情况?

我也尝试将投票大小增加到 50,但问题仍然存在。它接近之前测试的 25000 个请求(轮询大小为 10),并且如前所述失败。

【问题讨论】:

  • 您检查过没有连接泄漏吗?
  • 应用程序重启立即消除问题?
  • 问题可能(几乎可以肯定)不在于池。检查数据库上发生了什么。你能启用慢查询日志吗?是否发生死锁?
  • @user7294900 我不知道如何检查它。我确实启用了 HikariCP leakDetectionThreshold,但它所做的只是在应用程序已经显示降级时记录“检测到可能的泄漏”。
  • @MikhailKholodkov 确实如此。

标签: java multithreading performance spring-boot hikaricp


【解决方案1】:

HikariCP 建议使用一个由等待连接的线程饱和的固定大小的小型池。 As per the docs the suggested pool size:

连接数 = ((core_count * 2) + Effective_spindle_count)

多年来在许多基准测试中都表现良好的公式是 为了获得最佳吞吐量,活动连接的数量应该在某个地方 附近 ((core_count * 2) + Effective_spindle_count)。核心数不应包括 HT 线程,即使启用了超线程。有效主轴计数为零,如果 活动数据集被完全缓存,并接近实际的主轴数 随着缓存命中率下降。 ......到目前为止还没有任何分析 该公式在 SSD 上的效果如何。

具有小型数据集的内存 H2 将比在不同服务器上运行的独立数据库更快。即使您在同一个数据中心运行,服务器之间的往返时间通常在 0.5-1 毫秒左右。

尝试先找到当前的瓶颈。如果应用程序服务器没有用完 CPU,那么问题出在其他地方,例如数据库服务器。如果您无法弄清楚当前的瓶颈在哪里,您最终可能会在错误的地方进行优化。

【讨论】:

  • 我正在做很多测试来试图找出这个问题。我将我的应用程序堆大小从 1024m 增加到 2048m,它能够在停止之前以两倍的速度响应。我认为这可能是内存泄漏,但我没有看到通常的“内存不足错误”。关于如何找到可能的内存泄漏的任何想法?
  • @Saita 盲目调整可能会带来改进,但这不是正确的方法。调整前测量。如果您正在优化 GC,请查看 Tuning Espresso’s JVM Performance
【解决方案2】:

所以,这毕竟是内存泄漏。与 HikariCP 无关。

我们有一些 Groovy 脚本使用 @Memoized 和一些非常糟糕的缓存键(巨大的对象),并且缓存不断变大,直到没有剩余内存。

【讨论】:

    猜你喜欢
    • 2012-06-06
    • 1970-01-01
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多