【问题标题】:java connection pool, how many max connections in a multithreaded batch?java连接池,多线程批处理中有多少个最大连接?
【发布时间】:2012-02-29 17:38:14
【问题描述】:

我有一个 Java 批处理,它使用大的结果集进行选择(我使用 Spring 回调处理程序处理元素)。 回调处理程序将任务放入固定线程池中以处理该行。 我的 poolsize 固定在 16 个线程上。 结果集包含大约 100k 个元素。 所有数据库访问代码都通过 JdbcTemplate 或 Hibernate/Spring 处理,不存在手动连接管理。 我已经尝试使用 Atomikos 和 Commons DBCP 作为连接池。

现在,我认为我的连接池中最多 17 个连接足以完成这批。一个用于选择,16 个用于连接池中更新某些行的线程。然而这似乎太天真了,因为我必须指定一个更大的最大池大小(没有尝试过确切的值),首先我尝试了 50 ,它在我的本地 Windows 机器上工作,但似乎不是在我们的 Unix 测试环境中已经足够了。在那里我必须指定 128 才能使其工作(同样,我什至没有尝试 50 到 128 之间的值,我直接选择了 128)。

这正常吗?我缺少连接池的一些基本机制吗?我发现很难调试它,因为我不知道如何查看打开的连接会发生什么。我尝试了各种 log4j 设置,但都没有得到满意的结果。

编辑,附加信息:当连接池大小似乎太低时,批处理似乎挂起。如果我对进程执行 jstat,我可以看到所有线程都在等待新连接。起初我没有在 dbcp 连接池上指定 maxWait 属性,这会导致线程在新连接上无限期地等待,我注意到批处理一直挂起。所以没有释放连接。但是,这只发生在处理 +-70k 行之后,这以某种方式消除了我最初的连接泄漏预感。

edit2:我忘了提到我已经在我的任务中重写了更新部分。我在 ConcurrentLinkedQueue 中查询我的更新,我清空了 1000 个元素。所以我实际上只做了大约 100 次更新。

edit3:我正在使用 Oracle,并且正在使用并发工具。所以我有一个配置为 16 的固定池大小的执行器。我在这个执行器上提交我的任务。我不在我的任务中手动使用连接,我使用线程安全的 jdbctemplate 并询问它来自连接池的连接。我想 Spring/DBCP 处理连接/线程问题。

【问题讨论】:

    标签: java spring atomikos


    【解决方案1】:

    如果您使用的是 linux,您可以尝试使用 MySQL 管理员以图形方式监控您的连接状态,前提是您使用的是 MySQL。

    尽管如此,对于大型企业应用程序来说,即使是 100 个连接并不少见,每分钟处理几千个请求。

    但是,如果请求很少或者每个请求不需要唯一的事务,那么我建议您在线程内调整您的操作。

    也就是说,您如何将 100k 元素分配给 16 个线程? 如果您每次从共享位置(或缓冲区)读取一行时都尝试获取连接,那么预计会花费一些时间。

    看看这是否有帮助。

    1. 获取连接
    2. 对于每个元素,直到缓冲区大小变为零
    3. 处理它。
    4. 如果需要更新,
    5. 开启交易
    6. 更新
    7. 提交/回滚事务
    8. 转到第 2 步
    9. 释放连接

    您可以使用java.util.concurrent collections同步缓冲区

    不要为每个元素使用一个 Runnable/Callable。这会降低性能。 另外你是如何创建线程的?使用 Executors 来运行你的 runnable/callable。还要记住,数据库连接不应该跨线程共享。因此,一次在 1 个线程中使用 1 个连接。

    例如。创建一个 Executor 并提交 16 个 runnalble,每个都有自己的连接。

    【讨论】:

    • 我用更多信息编辑了我的问题。即使我创建了一个 Runnable / 行,性能实际上也非常好。
    • 试用 Netbeans 分析器。它为您提供有关线程的实时统计信息,例如等待 CPU、等待锁定、等待 IO 等。如果结果显示线程正在等待 DB 连接,则最好增加池大小。否则优化瓶颈。 profiler.netbeans.org
    • 我为此使用了 jvisualvm。不幸的是,我无法将分析器连接到发生问题的 unix 环境,它是一个锁定的环境。但是我对调整我的池大小并不感兴趣,它现在可以使用 128 并且我的源数据大小是恒定的,所以应该很好。然而,我的问题是,17 应该不够吗?如果不是,为什么?
    • 我没有直接回答您的最后一个问题,因为这是基于您的应用程序的需要。除非您以某种方式进行分析(使用分析器/使用 visualvm/添加日志),否则没有人可以知道您的应用程序大部分时间都花在了哪里。但是,正如我之前所说,只要您的数据库服务器有足够的资源,最多 100 个并不少见。这里的一项优化是,如果您使用大量连接,如果空闲时间很长,您可以删除它们并获得一个新的。
    • 我知道这并不少见,我在生产中运行的 web 应用程序有 500 个池,因为你无法真正预测线程的数量。但是在这种情况下,只有 17 个线程连接到数据库,所以我不太明白为什么您会认为 poolsize 取决于应用程序的需要?我进行了分析,它显示了 98% 的线程利用率,因此几乎没有等待连接。你提到空闲时间,我还不确定它在哪里起作用?顺便说一句,我非常感谢你的回答:)
    【解决方案2】:

    我切换到 c3p0 而不是 DBCP。在 c3p0 中,您可以指定多个辅助线程。我注意到,如果我将该数字设置为与我正在使用的线程数一样高,则连接数保持非常低(使用方便的 c3p0 的 jmx bean 来检查活动连接)。此外,我有几个依赖关系,每个都有自己的实体管理器。显然,每个实体管理器都需要一个新连接,所以我有大约 4 个实体管理器/线程,这可以解释大量连接。我认为我的任务都非常短暂,以至于 DBCP 无法跟随关闭/释放连接,因为 c3p0 的工作方式更加异步,并且您可以指定辅助线程的数量,它能够及时释放我的连接。

    编辑:但是批处理在部署到测试环境时一直挂起,释放连接时所有线程都阻塞,锁在池上。和 DBPC 一样:(

    编辑:当我切换到 BoneCP 后,我所有的问题都消失了,我也获得了巨大的性能提升

    【讨论】:

      猜你喜欢
      • 2018-12-04
      • 2014-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多