android wtf_WTF连接池

android wtf

让我们谈谈连接池。

我声称:

大多数流行的连接池的默认设置都很差!

对您来说,这意味着:

去查看您的连接池设置。

如果您依赖默认设置,则可能会遇到问题。 您可能有内存泄漏和应用程序无响应(即使负载根本不高)。

下面,我将显示一些最重要的设置以及我的建议,这些设置应如何配置。

什么是连接池?

一个普通的Web应用程序需要从数据库写入或读取数据,它是这样的:

  1. 打开与数据库的连接//需要N毫秒
  2. 读/写数据
  3. 关闭连接

(顺便说一下,在旧的良好CGI应用程序中,这是唯一可能的方法)

在许多情况下,此方法非常好。 而且您可能不需要更多。 但这对于高性能系统有一些缺点

  • 步骤1可能需要一些时间。 大概几十或几百毫秒(当然要取决于它)。
  • 很容易忘记第3步(关闭连接),这会导致连接泄漏 (导致内存泄漏和其他问题)。

新英雄

这就是诞生另一种方法的原因:应用程序可能会预先打开一堆连接并一直保持打开状态。 一堆打开的连接称为连接池 然后任何操作如下所示:

  1. 在大多数情况下,从池中//快速建立数据库连接
  2. 读/写数据
  3. 将连接返回到池

看起来很酷。 但是,新的力量总是意味着新的问题。

…以及新问题

使用连接池时,我们需要(至少)解决以下问题

  • 我们应该保持多少连接?
  • 应该保留多长时间?
  • 如果它们看起来坏了怎么办?
  • 如果应用程序需要的连接数超过当前池的数量,该怎么办?
  • 如果有人忘记将连接恢复到池怎么办?

为了回答这些问题,连接池有很多设置。 而且它们的默认值大多不好。 感兴趣吗? 让我展示。

基本设置

我将考虑Java世界中2个最流行的连接池:

  • C3P0( https://www.mchange.com/projects/c3p0/ )
  • HikariCP( https://github.com/brettwooldridge/HikariCP )

原因的基本参数是:

  • 最小大小(随时应打开的最小连接数)
  • 初始大小(启动时打开了多少个连接应用程序)
  • 最大大小(池中的最大连接数)

顺便说一下,这些是唯一具有合理默认值的设置。 他们来了:

c3p0 光ikaCP
最小尺寸 3 10
初始尺寸 3 10
最大尺寸 15 10

让我们继续进行更多有问题的设置。

关键设置

结帐超时

应用程序可以等待多长时间,直到它从池中获得连接。

  • c3p0设置:checkoutTimeout
  • HikariCP设置:connectionTimeout

默认值:

c3p0 光ikaCP 我建议
checkoutTimeout 30秒 1毫秒

这两个默认值都只是灾难。

正如我提到的,在大多数情况下,从池中获得连接非常快。 除非池中没有打开的连接。 然后,池需要获取一个新的连接(通常需要不到一秒钟的时间)。 但是,如果达到maxSize,则池无法打开新的连接,而只是等到有人将其连接返回到池中。 但是,如果应用程序发生连接泄漏(阻止连接返回的错误),则池将永远无法恢复连接!

那会发生什么呢?

对于c3p0,我们最终将所有线程冻结为以下状态:

"qtp1905485420-495 13e09-3211" #495 prio=5 os_prio=0 tid=0x00007f20e078d800 nid=0x10d7 in Object.wait() [0x00007f204bc79000]

   java.lang.Thread.State: WAITING (on object monitor)

at java.lang.Object.wait(Native Method)

at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable()

- locked <0x00000000c3295ef8> (a com.mchange.v2.resourcepool.BasicResourcePool)

at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource()

    …

    at org.hibernate.jpa.internal.QueryImpl.getResultList()

    at domain.funds.FundsRepository.get()

    …

似乎HikariCP的默认“ 30秒”要好一些。 不,它在高性能应用程序中并没有真正帮助。 在这30秒内,可能会收到许多新请求,并且所有请求都被冻结。 显然,应用程序将很快收到OutOfMemory错误。 任何等待只会将应用程序的终止延迟几秒钟。

这就是为什么我建议将checkoutTimeout设置为最小可能值:1ms。 不幸的是,我们不能将其设置为0,因为0意味着无尽的等待&#55357;&#56898; 我们越早失败,我们给工作线程完成工作的机会就越大。 而且我们可以清楚地通知用户该应用程序当前已超载,他应该稍后再试。

在结帐时测试连接

有时池中的连接可能会死。 数据库可以主动关闭它们,或者系统管理员可以断开网络电缆。 这就是池应该监视连接活动性的原因。

最简单的设置是c3p0中的“ testConnectionOnCheckout”(我在HikariCP中没有找到类似的设置,它似乎始终处于启用状态)。

默认值:

c3p0 光ikaCP 我建议
testConnectionOnCheckout 真正? 真正

当然,默认情况下应该启用它

否则,您将在日志中最终遇到许多此类异常:

org.hibernate.TransactionException: Unable to rollback against JDBC Connection
at o.h.r.j.i.AbstractLogicalConnectionImplementor.rollback()
at o.h.r.t.b.j.i.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.rollback(JdbcResourceLocalTransactionCoordinatorImpl.java:294)

PS如果要获得更好的性能,可以考虑在后台而不是在结帐时测试连接:

  • testConnectionOnCheckout = false
  • testConnectionOnCheckin = true
  • idleConnectionTestPeriod = 10

首选测试查询

但是池应该如何准确地测试连接?

问题在于它取决于数据库。

默认情况下,两个池都通过执行以下测试来测试连接

  • “ connection.isValid()”(对于JDBC4),或者
  • “ connection.getMetaData()。getTables()”(对于JDBC3)

这可能很慢,因为“ getTables()”每次都检索有关所有表的元信息。 推荐值类似于

  • “ SELECT 1”(对于MySql),或者
  • “从双重选择1”(对于Oracle)等

通过执行此简单而快速的查询,池可以检查连接是否仍处于活动状态。

最大空闲时间

未使用的连接可以在池中保留多长时间

  • c3p0设置:maxIdleTime
  • HikariCP设置:idleTimeout

默认值:

c3p0 光ikaCP 我建议
maxIdleTimeout 10分钟 1..10分钟

可能没什么大不了的,但是每个打开的连接

  • 在数据库中保存一些资源
  • 防止其他系统获得到同一数据库的连接(每个数据库都有最大可能连接数的限制)

因此,关闭未使用的(空闲)连接是个好主意。 我建议将此值设置为无限期。 大概几分钟是合理的。

最小泳池大小

应始终具有多少个连接池(即使未使用)。

  • c3p0设置:minPoolSize
  • HikariCP设置:minimumIdle

默认值:

c3p0 光ikaCP 我建议
maxIdleTimeout 3 最大游泳池 0…N

出于同样的原因,关闭未使用的连接可能是一个好主意。 在大多数情况下,我会将此值设置为0或1。 如果某些用户意外决定在午夜登录到您的应用程序,那么他将只等待几毫秒。 没什么大不了的。

最大连接年龄

连接在池中可以存在多长时间(无论它是空闲还是已使用)

  • c3p0设置:maxConnectionAge
  • HikariCP设置:maxLifetime

默认值:

c3p0 光ikaCP 我建议
maxIdleTimeout 30分钟 比方说30分钟

以防万一,不时关闭连接可能是一个好主意。 可能有助于避免某些内存泄漏。

来自HikariCP文档的报价:

“我们强烈建议设置此值,它应该比任何数据库或基础架构施加的连接时间限制短几秒钟。”

未返回的连接超时

典型的问题之一是连接泄漏。 一些错误的代码从池中获取了一个连接,但没有返回它。 如何发现这个问题?

幸运的是,在这种情况下,我们有一个很好的设置:

  • c3p0设置:unreturnedConnectionTimeout
  • HikariCP设置:leakDetectionThreshold

默认值:

c3p0 光ikaCP 我建议
maxIdleTimeout 残障人士 残障人士 5分钟?

如果任何错误代码接受了连接但在5分钟内未返回连接,则池将强制返回连接并发出如下警告:

[C3P0PooledConnectionPoolManager Logging the stack trace by which the overdue resource was checked-out.
java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace.
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource()
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1885)
at domain.application.ApplicationReportSender.sendWeeklyReport(ApplicationReportSender.java:63)

这将帮助您找出有罪代码在哪里。

结论

我概述了一些连接池设置。 还有更多。 根据我的经验,我给出了一些合理的建议。 但是您的应用程序可能具有不同的负载。 您的用户可能会有不同的行为。 我的建议对您来说似乎很愚蠢。

没问题。 不要相信我 但也请不要相信默认值。

去检查你的游泳池设置!

翻译自: https://www.javacodegeeks.com/2018/12/wtf-connection-pools.html

android wtf

你可能感兴趣的:(android wtf_WTF连接池)