提问者:小点点

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


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

当我将SpringAOP配置为在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进行更多的来回对话。这是只读转储与读写。

>

  • 有人能解释为什么只读调用耗时更长吗?这是预期的吗?

    除了改善网络之外,我有没有做错什么,或者我可以做些什么来提高他们的速度?刚刚找到了这个很棒的帖子,里面有一些很好的性能建议。还有其他评论吗?

    非常感谢。


  • 共1个答案

    匿名用户

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

    好吧,这是一次有趣的旅程。我有很多东西要学习和分享。下面的一些应该是显而易见的,但希望我的无知和我所学到的会对其他人有所帮助。

    问题#2的较长答案涉及我为尝试提高远程数据库性能而采取的步骤的以下详细信息:

    >

  • 我们做的第一件事就是在阅读了这个OpenVPN优化页面后,将数据库VPN从TCP切换到UDP。唉。我应该知道这一点。我还在OpenVPN客户端和服务器配置中添加了以下设置。只读事务开销从480毫秒下降到141毫秒,但仍然超过读写的100毫秒。大胜利。

    ; Got these from:
    ; https://community.openvpn.net/openvpn/wiki/Gigabit_Networks_Linux
    proto udp
    tun-mtu 6000
    fragment 0
    mssfix 0
    

    在仔细查看tcpdump输出(tcpdump…-Xfor the win)时,我注意到进行了许多不必要的自动提交和只读/读写JDBC调用。升级到我们使用的令人敬畏的HikariCP连接池库的较新版本对此有所帮助。在2.4.1版中,他们添加了一些智能,减少了其中一些调用。只读事务开销降至120毫秒。读写仍然在100毫秒。不错。

    Brett Wooldridge,HikariCP的作者给我指出了可能有帮助的MySQL驱动程序设置。非常感谢伙计。将以下设置添加到我们的MySQL JDBCURL告诉驱动程序使用连接的软件状态,而不是向服务器询问状态。

    jdbc:mysql://.../database?useLocalSessionState=true&useLocalTransactionState=true
    

    这些设置导致删除了更多同步JDBC命令。只读事务开销下降到60ms,现在与读写相同。呜呼。

    编辑/警告:在发现驱动程序未发送事务信息的错误后,我们实际上回滚了添加useLocalTransactionState=true。不确定错误是在驱动程序、Hibernate还是我们的代码中。

    但是在查看更多tcpdump输出时,我仍然看到只读/读写事务设置被发送。我的最后一个修复是编写一个自定义只读检测池,如果它看到对连接的第一个调用是connect. setReadOnly(true),它会从一个特殊池中给出连接。

    使用这个自定义池将只读连接和读写连接的事务开销降低到20毫秒。我认为它基本上删除了最后一个JDBC事务开销调用。这是我从主页上写的两个类的源代码。代码相对脆弱,依赖于Hibernate做连接。setReadOnly(true)第一件事,但它似乎工作得很好,我在XML和代码中仔细记录了它。

    因此,在几天的工作中,基本的@Transaction开销从480毫秒增加到20毫秒。对da. find(…)方法的100次“真实生活”Hibernate调用从55秒开始,到4.5秒结束。非常棒。希望速度提高10倍总是这么容易。

    希望我的经验能帮助到别人。