我怎样才能阻止 h2 如此多地阻止我的休眠查询

Posted

技术标签:

【中文标题】我怎样才能阻止 h2 如此多地阻止我的休眠查询【英文标题】:How can I stop h2 being in blocking my hibernate querys so much 【发布时间】:2013-09-13 09:03:06 【问题描述】:

我已经通过 hibernate 将 h2 (1.3.172) 用于我的应用程序有一段时间了,在解决了一些非 h2 性能问题后,我的性能瓶颈是 h2。我的数据库非常简单,有 10 个表,每个表的卷少于 100,000 条记录,在 h2 功能范围内也是如此,但我认为问题在于多线程。

我实际上是在使用 hibernate/h2 来控制我的应用程序中的内存消耗。我的应用程序使用管道方法处理文件,可以处理的文件数量没有限制,所以如果我将数据存储在内存中,我会很快点击 OutOfMemory。每个文件通常要经过十个处理阶段,每个阶段都有自己的执行器服务,当文件从一个阶段移动到另一个阶段时,它会作为作业添加到相关的执行器服务上。很少有数据存储在内存中,而是在执行器上启动作业时从数据库中检索有关文件的数据,并在作业完成时将数据写回数据库。我们有 10 个执行器,每个执行器都有机器核心大小的线程池,所以在 4 个机器核心上,理论上我们可以随时向数据库发出 40 个请求,但更常见的是少于 10 个。所以我们有很多事务在进行同时主要涉及少量行。

我的应用程序是多线程的,如果我对它运行分析器,我会发现我的线程大部分时间都处于阻塞状态,等待 executeQuery() 或 executeUpdate()。我读到 h2 是单线程的,所以我认为问题是由 h2 同步请求引起的,而不是锁定,但我可能误解了这一点。我已经设置了 MVCC=TRUE 以便 h2 执行行而不是表锁定,但我仍然会偶尔超时 - 是否可以设置一些东西来检查正在使用的锁。

我读到有一个 MULTI_THREADING 选项,但它不能与 MVCC 一起使用,这很遗憾,因为如果我删除 MVCC=TRUE,我觉得我需要这两个选项,这意味着每次我执行插入或操作时 h2 都会锁定表更新,而且因为我只有几张表,所以它们几乎总是被锁定。

所以,我觉得阻塞可能会大大减少,但我不清楚根本问题是什么以及如何进行

测试 这是我的起点,测试用例需要 3 分 14 秒

3:14,FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE

我尝试了各种组合,例如

3:02,FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE;LOG=0;CACHE_SIZE=65536;LOCK_MODE=0;
2:56,FILE_LOCK=SOCKET;MVCC=TRUE;DB_CLOSE_ON_EXIT=FALSE;LOG=0;;CACHE_TYPE=SOFT_LRU;LOCK_MODE=0;
1:05,FILE_LOCK=SOCKET;DB_CLOSE_ON_EXIT=FALSE;LOCK_TIMEOUT=10000

我发现唯一有很大不同的是删除了 MVCC=TRUE 选项,但不幸的是,我的锁定超时次数从几乎为零增加到加载,所以不幸的是,一些所需的处理没有发生,这可能是总时间更快的原因 因为应用程序中的某些阶段没有完成,或者使用 MVCC 会减慢速度。

我尝试使用 MULTI_THREADED=TRUE 但它似乎根本不适合我

关于在多核系统中的使用

我刚刚阅读了 MULTI_THREADED 选项 https://groups.google.com/forum/#!topic/h2-database/VoE3AU7mSuM 的说明

托马斯说

默认为“非多线程”,意味着只能运行一条语句 随时(每个数据库)。周围有一个同步块 运行声明。启用多线程后, 同步语句在会话(连接)上而不是在 数据库对象。

选项是增加并发性,而不是吞吐量。默认 设置通常不是问题,除非您长时间运行 查询。

如果我理解正确,这意味着当禁用时,虽然 h2 可以接受多个连接,但它一次只会处理一个查询,但即使启用它,它也会在查询之间交换中途但实际上仍然只是一次处理一个查询,即它可以开始处理查询1,然后切换到查询2,然后再返回查询1,但永远不会真正使用cpu并行处理查询1和查询2。

因此,在任何一种情况下,尽管在 cpu 之间切换,它在任何时候都只会使用一个 cpu。因此,如果您有一台功能强大的机器,例如 16 个核心,而瓶颈是数据库,那么添加更多核心根本无济于事因为 h2 一次只能使用一个核心

这似乎是一个真正的限制,我想知道它与 Derby 或任何其他嵌入式 Java 数据库相比如何。

【问题讨论】:

【参考方案1】:

有线程被阻塞,这可能是,是的,但我会首先专注于那些阻塞的线程,这意味着正在消耗 CPU时间或磁盘 I/O。那些是什么陈述?他们是不使用索引的查询吗?你有索引吗?或者您是否不必要地插入/删除行?另请参阅how to analyze performance problems 上的文档。

【讨论】:

我确实有索引,即使我从一个空数据库开始也会出现问题(因此行扫描可能比使用索引更快),我认为我的陈述是明智的,尽管因为我使用休眠它不是很容易看到发生了什么。我会按照建议调查 sql,但如果您在问题的多核部分提供意见,我将不胜感激。 请在问题中查看我的多核总结【参考方案2】:

虽然我喜欢 H2,但我认为这不是您的最佳选择。您应该尝试 Derby,它更加成熟且可用于生产 (it's a descendant of the IBM product Cloudspace)。

下一步是减少事务隔离。如果您看到 this document 了解每个隔离级别使用的锁类型。

由于您使用 Hibernate,因此切换数据库不会花费太长时间(只需更改 JDBC 配置并将现有数据加载到新数据库中即可)。

就像 H2 一样,您可以嵌入 Derby。

【讨论】:

我确实将 Derby 用于另一个应用程序,我的观点是 h2 在功能和性能方面已经超过了 derby i,但这主要基于 h2 自己的基准,我现在看到的是单连接基准 H2 在单线程环境中启动和处理数据要快得多。一旦线程进入画面,H2 就更加保守且优化程度较低。总体而言,Derby 速度较慢但更可靠。这就是为什么我使用 H2 进行测试,使用 Derby 进行实际生产(这也有助于从代码中剔除特定于 DB 的代码)。 所以根据文档,它可以进行类似于 h2 的 MVCC 模式的行级锁定 - 我假设它自己会智能地做到这一点? ,我希望如此,因为尝试在没有这种模式的情况下使用 h2 意味着我一直走得太远,可能由于表锁而导致锁超时。 你为什么要问?性能不是可以扣除的东西。您将不得不尝试它是否真的适用于您的情况。 我之所以问,是因为在 h2 中使用表级锁定而不是行级锁定真的很烂,如果 derby 没有这个功能,我也不想花太多精力去使用它。

以上是关于我怎样才能阻止 h2 如此多地阻止我的休眠查询的主要内容,如果未能解决你的问题,请参考以下文章

运行PowerShell进程时如何阻止Windows 10机器休眠/休眠?

C#阻止系统休眠

阻止 iphone 休眠但允许屏幕锁定

win10 阻止休眠工具

如何在设备休眠时保持 GPS 处于全功率状态

我的 Internet 浏览器每次都会自动打开和关闭 HTML 侧边栏。我怎样才能阻止它,发生了啥?