为什么spring / hibernate只读数据库事务比读写运行慢?

问题描述 投票:26回答:1

我一直在研究只读与读写数据库事务的性能。 MySQL服务器在慢速VPN链接上是远程的,因此我很容易看到事务类型之间的差异。这是连接池,我知道它基于比较第一次和第二次JDBC调用。

当我将Spring AOP配置为在我的DAO调用上使用只读事务时,与读写相比,调用速度慢30-40%:

<!-- slower -->
<tx:method name="find*" read-only="true" propagation="REQUIRED" />
...
// slower
@Transaction(readOnly = true)

与:

<!-- faster -->
<tx:method name="find*" read-only="false" propagation="REQUIRED" />
...
// faster
@Transaction

看看tcpdump,似乎只读事务在与MySQL交谈时做得更多。这是read-only dumpread-write

  1. 任何人都可以解释为什么只读通话需要更长的时间。这是预期的吗?
  2. 除了改善网络之外,还有什么我做错了或能做些什么来提高速度?刚刚发现了一些good performance recommendations这个很棒的帖子。还有其他意见吗?

非常感谢。

java spring hibernate database-performance spring-transactions
1个回答
29
投票

为什么spring / hibernate只读数据库事务比读写运行慢?

好的,这是一个有趣的旅程。很多我可以学习和分享。下面的一些应该是显而易见的,但希望我的无知和我所学到的将有助于其他人。

<tldr>对问题#1的简短回答是,hibernate使用@Transaction(readOnly = true)同步JDBC调用从set session.transaction.read.only会话开始,并以set session.transaction.read.write调用结束。执行读写调用时不会发送这些调用,这就是为什么只读调用较慢的原因。

对问题#2的更长答案涉及我尝试降低远程数据库性能的步骤的以下详细信息:

  1. 我们做的第一件事就是在读完这个OpenVPN optimization page之后将数据库VPN从TCP切换到UDP。叹。我应该知道这一点。我还将以下设置添加到OpenVPN客户端和服务器配置中。只读事务开销从480ms降至141ms,但仍然超过读写的100ms。大赢。 ; Got these from: https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux proto udp tun-mtu 6000 fragment 0 mssfix 0
  2. 仔细观察tcpdump输出(获胜的tcpdump ... -X),我注意到有很多不必要的自动提交和只读/读写JDBC调用。升级到我们使用的更好版本的真棒HikariCP connection pool库有助于此。在版本2.4.1中,他们添加了一些智能,减少了一些这些调用。只读事务开销低至120ms。读写仍然是100ms。尼斯。
  3. HikariCP的作者Brett Wooldridge向我指出了可能有用的MySQL驱动程序设置。非常感谢老兄。将以下设置添加到我们的MySQL JDBC URL会告诉驱动程序使用连接的软件状态而不是询问服务器的状态。 jdbc:mysql://.../database?useLocalSessionState=true&useLocalTransactionState=true 这些设置导致删除了更多的同步JDBC命令。只读事务开销降至60ms,现在与读写相同。呜呜。 编辑/警告:在发现驱动程序未发送交易信息的错误后,我们实际上回滚添加useLocalTransactionState=true
  4. 但是在更多地关注tcpdump输出时,我仍然看到了正在发送的只读/读写事务设置。我的最后一个修复是编写一个自定义只读检测池,如果它看到第一次连接调用是connection.setReadOnly(true),它会从特殊池中发出连接。 使用此自定义池将只读和读写连接的事务开销降低到20ms。我认为它基本上删除了最后一个JDBC事务开销调用。以下是我主页上two classes that I wrote的来源。代码相对脆弱,依赖于Hibernate做connection.setReadOnly(true)的第一件事,但它似乎运行良好,我在XML和代码中仔细记录它。

因此,在几天的工作中,基本的@Transaction开销从480毫秒增加到20毫秒。对于dao.find(...)方法的100“真实生活”休眠调用在55秒开始并以4.5秒结束。漂亮踢屁股。希望速度提高10倍总是很容易。

希望我的经验可以帮助他人

© www.soinside.com 2019 - 2024. All rights reserved.