草庐IT

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

coder 2023-05-11 原文

我一直在围绕只读与读写数据库事务的性能进行一些研究。 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 .还有其他意见吗?

非常感谢。

最佳答案

Why do spring/hibernate read-only database transactions run slower than read-write?

对问题 #1 的简短回答是 hibernate 使用 set session.transaction.read.only 启动 @Transaction(readOnly = true) session > 同步 JDBC 调用并以 set session.transaction.read.write 调用结束。在进行读写调用时不会发送这些调用,这就是只读调用较慢的原因。请参阅下面的我的补救措施。

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

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

  1. 读完这篇 OpenVPN optimization page 之后,我们做的第一件事就是将我们的数据库 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
    
  2. 在仔细查看 tcpdump 输出(tcpdump ... -X 为胜利),我注意到有很多不必要的自动提交和只读/读取-write 正在进行的 JDBC 调用。升级到新版本的真棒HikariCP connection pool我们使用的图书馆对此有所帮助。在 2.4.1 版本中,他们添加了一些智能来减少其中一些调用。只读事务开销低至 120 毫秒。读写仍为 100ms。不错。

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

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

    这些设置导致更多的同步 JDBC 命令被删除。只读事务开销降至 60 毫秒,现在与读写相同。呜呼。

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

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

使用此自定义池将只读和读写连接的事务开销降低到 20 毫秒。我认为它基本上消除了最后一个 JDBC 事务开销调用。这里是 two classes that I wrote 的来源从我的主页上写下这一切。代码相对脆弱,首先要依赖 Hibernate 执行 connection.setReadOnly(true) 但它似乎运行良好,我在 XML 和代码中仔细记录了它。

所以在几天的工作中,基本的 @Transaction 开销从 480 毫秒变为 20 毫秒。对 dao.find(...) 方法的 100 次“现实生活” hibernate 调用从 55 秒开始,到 4.5 秒结束。相当踢屁股。希望将速度提高 10 倍总是这么容易。

希望我的经验对其他人有所帮助。

关于java - 为什么spring/hibernate只读数据库事务运行比读写慢?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34797480/

有关java - 为什么spring/hibernate只读数据库事务运行比读写慢?的更多相关文章

  1. ruby - 为什么我可以在 Ruby 中使用 Object#send 访问私有(private)/ protected 方法? - 2

    类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc

  2. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  3. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  4. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  5. ruby - 为什么 4.1%2 使用 Ruby 返回 0.0999999999999996?但是 4.2%2==0.2 - 2

    为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返

  6. ruby - ruby 中的 TOPLEVEL_BINDING 是什么? - 2

    它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput

  7. ruby - 我可以使用 aws-sdk-ruby 在 AWS S3 上使用事务性文件删除/上传吗? - 2

    我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的

  8. ruby - Infinity 和 NaN 的类型是什么? - 2

    我可以得到Infinity和NaNn=9.0/0#=>Infinityn.class#=>Floatm=0/0.0#=>NaNm.class#=>Float但是当我想直接访问Infinity或NaN时:Infinity#=>uninitializedconstantInfinity(NameError)NaN#=>uninitializedconstantNaN(NameError)什么是Infinity和NaN?它们是对象、关键字还是其他东西? 最佳答案 您看到打印为Infinity和NaN的只是Float类的两个特殊实例的字符串

  9. ruby-on-rails - 如果 Object::try 被发送到一个 nil 对象,为什么它会起作用? - 2

    如果您尝试在Ruby中的nil对象上调用方法,则会出现NoMethodError异常并显示消息:"undefinedmethod‘...’fornil:NilClass"然而,有一个tryRails中的方法,如果它被发送到一个nil对象,它只返回nil:require'rubygems'require'active_support/all'nil.try(:nonexisting_method)#noNoMethodErrorexceptionanymore那么try如何在内部工作以防止该异常? 最佳答案 像Ruby中的所有其他对象

  10. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

随机推荐