为什么 spring/hibernate 只读数据库事务的运行速度比读写慢?
<tldr>问题#1的简短答案是,休眠从会话开始,以同步JDBC调用结束。执行读写调用时不会发送这些调用,这就是只读调用速度较慢的原因。请参阅下面的补救措施。</tldr>@Transaction(readOnly = true)
set session.transaction.read.only
set session.transaction.read.write
好吧,这是一个有趣的旅程。很多东西让我学习和分享。以下一些应该是显而易见的,但希望我的无知和我学到的东西会对其他人有所帮助。
对问题 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 输出(获胜)时,我注意到有很多不必要的自动提交和只读/读写 JDBC 调用。升级到我们使用的令人敬畏的HikariCP连接池库的较新版本有助于解决这个问题。在2.4.1版本中,他们添加了一些智能,减少了其中一些调用。只读事务开销低至 120 毫秒。读写仍然在100ms。很好。tcpdump ... -X
-
HikariCP的作者Brett Wooldridge向我指出了可能有帮助的MySQL驱动程序设置。非常感谢伙计。将以下设置添加到我们的MySQL JDBC URL中,告诉驱动程序使用连接的软件状态,而不是向服务器询问状态。
jdbc:mysql://.../database?useLocalSessionState=true&useLocalTransactionState=true
这些设置导致删除了更多的同步 JDBC 命令。只读事务开销降至 60 毫秒,现在与读写相同。呜呼。
编辑/警告:在发现驱动程序未发送事务信息的错误后,我们实际上回滚了添加。不确定错误是在驱动程序中,休眠中还是在我们的代码中。useLocalTransactionState=true
-
但是在进一步查看 tcpdump 输出时,我仍然看到正在发送只读/读写事务设置。我的最后一个修复是编写一个自定义只读检测池,如果它看到对连接的第一次调用是 ,则从特殊池中发出连接。connection.setReadOnly(true)
使用此自定义池将只读和读写连接的事务开销降低到 20 毫秒。我认为它基本上删除了最后一个JDBC事务开销调用。这是我从主页上写的两个类的来源,写下了这一切。代码相对较脆,依赖于Hibernate做第一件事,但它似乎运行良好,我仔细地将其记录在XML和代码中。connection.setReadOnly(true)
因此,在几天的工作中,基本开销从480ms增加到20ms。对方法的 100 次“现实生活”休眠调用从 55 秒开始,到 4.5 秒结束。漂亮的踢屁股。希望获得10倍的速度提升总是如此容易。@Transaction
dao.find(...)
希望我的经验能帮助别人。