我有一个Java批处理,它使用一个大的结果集进行选择(我使用Spring callbackhandler处理元素)。 callbackhandler将一个任务放在一个固定的线程池中来处理该行。 我的poolize固定在16个线程上。 结果集包含大约100k个元素。 所有数据库访问代码都通过JdbcTemplate或Hibernate / Spring处理,不存在手动连接管理。 我尝试使用Atomikos和Commons DBCP作为连接池。
现在,我认为我的连接池中的17个最大连接数足以让这个批次完成。一个用于选择,另一个用于连接池中的线程,用于更新某些行。然而,这似乎太天真,因为我必须指定一个更大的最大池大小(没有尝试过一个确切的值),首先我尝试50在我的本地Windows机器上工作,但似乎不是足够的Unix测试环境。在那里我必须指定128才能使它工作(再次,我甚至没有尝试50到128之间的值,我直接去了128)。
这是正常的吗?连接池中是否存在一些我缺失的基本机制?我发现很难调试这个,因为我不知道如何查看打开的连接会发生什么。我尝试了各种log4j设置,但没有得到任何满意的结果。
编辑,附加信息:当连接池大小似乎太低时,批处理似乎挂起。如果我在进程上执行jstat,我可以看到所有线程都在等待新连接。起初我没有在dbcp连接池上指定maxWait属性,这会导致线程在新连接上无限期地等待,我注意到批处理一直挂起。所以没有发布连接。然而,这只发生在处理+ -70k行之后,这解雇了我最初的连接泄漏预感。
edit2:我忘了提到我已经在我的任务中重写了更新部分。我在ConcurrentLinkedQueue中查询我的更新,我在1000个元素上清空它。所以我实际上只做了大约100次更新。
edit3:我正在使用Oracle而我正在使用并发工具。所以我有一个配置了16个固定池大小的执行器。我在这个执行器上提交我的任务。我不在我的任务中手动使用连接,我使用线程安全的jdbctemplate并询问它来自连接池的连接。我想Spring / DBCP处理连接/线程问题。
答案 0 :(得分:1)
如果您使用的是Linux,只要您使用的是MySQL,就可以尝试使用MySql管理员以图形方式监控您的连接状态。
无论如何,即使100个连接对于大型企业应用程序来说并不罕见,每分钟处理几千个请求。
但是如果请求很少或者每个请求都不需要唯一的事务,那么我建议你调整线程内的操作。
也就是说,你如何将100k元素分配给16个线程? 如果每次从共享位置(或缓冲区)读取一行时尝试获取连接,则需要花费时间。
看看这是否有帮助。
您可以使用java.util.concurrent collections
同步缓冲区不要为每个元素使用一个Runnable / Callable。这会降低性能。 另外你是如何创建线程的?使用Executors来运行runnable / callable。还要记住,不希望跨线程共享数据库连接。因此,一次在1个线程中使用1个连接。
例如。创建一个Executor并提交16个runnalbles,每个runnalbles都有自己的连接。
答案 1 :(得分:0)
我切换到c3p0而不是DBCP。在c3p0中,您可以指定多个辅助线程。我注意到如果我把这个数字和我正在使用的线程数一样高,连接数就会保持很低(使用c3p0的方便的jmx bean来检查活动连接)。此外,我对每个自己的实体管理器都有几个依赖项。显然每个实体管理器都需要一个新的连接,所以我有大约4个实体管理器/线程,这可以解释大量的连接。我认为我的任务都是如此短暂,以至于DBCP无法跟上关闭/释放连接,因为c3p0工作更加异步,你可以指定helperthreads的数量,它能够及时释放我的连接。
编辑:但批处理在部署到测试环境时保持挂起,所有线程在释放连接时都会阻塞,锁在池上。与DBPC一样:(
编辑:当我切换到BoneCP时,我的所有问题都消失了,而且作为奖励我的性能也有了很大提升