Hibernate二级缓存速度慢

6
我正在使用内存中的ehcache进行Hibernate二级缓存,但速度较慢。我的意思是,与SQL相比并不慢,但在快速数据库上使用SSD也没有真正的加速。实际速度提高不到2倍,有时甚至无法察觉。
看起来其他人也有同样的问题,但没有得到答案: http://forum.spring.io/forum/spring-projects/data/44353-hibernate-second-level-caching-slow-no-really-slow https://forum.hibernate.org/viewtopic.php?t=985913 经过一些分析,似乎Hibernate总是对缓存元素进行反序列化和序列化,而不是直接存储它们,这导致了这种糟糕的性能(与直接使用ehcache相比,性能下降了100倍以上)。
所以,我的问题是:
- Hibernate是否可以直接存储和恢复缓存对象? - 是否有其他方法可以加速二级缓存? - 是否有一个相对简单的替代机制来更快地缓存Hibernate?

因为您提出了三个问题,而不是一个,所以您立即将此问题放入“过于广泛”的领域。 Stackoverflow 是关于一次只问一个问题的,考虑将其拆分或缩小到您真正想知道的内容。这可能是要聚焦于 Hibernate 缓存性能问题。首先要更具体地说明您正在使用哪个版本的 Hibernate。 - Gimby
好的,问题的要点是“我想要更快的缓存”。如果这三个选项中有任何一个可行,我都会满意。 - P.Péter
我认为这是一个关键点:“小于2的因子”。如果不知道您的应用程序在做什么,任何人都如何解决这个问题?您能否组合一个类似于您的应用程序的访问模式的示例或基准测试? - cruftex
1
我也注意到了这一点。在SSD上直接查询数据库与使用L2C的速度差不多(在我的示例中为28毫秒与33毫秒)。但是,L2C的第一次查询要慢得多!我原本期望L2C至少比直接查询快2-3倍,但现状就是这样。 - Andreas Gelever
4个回答

2

hibernate能否直接存储和恢复缓存对象?

不行,因为这意味着并发会话将使用相同的对象实例,从而互相干扰。

有没有其他方法来加速二级缓存?

可能有成千上万种加速方式,大多数取决于您应用程序的具体要求。

是否有比较简单的替代机制来更快地进行Hibernate缓存?

目前至少还没有。


1
这是一个旧问题,但其他人似乎在使用Hibernate + Ehcache时遇到了性能问题。我花了一些时间来找出问题,因此我在这里添加了我找到的内容,希望这会对某人有所帮助。
JCache / JSR-107规范指出,默认情况下缓存必须“按值存储”,而Ehcache默认为“按引用存储”。在使用Ehcache 3时,Hibernate使用jcache接口,因此Ehcache通过使用序列化复制程序强制执行规范:在存储任何键或值之前,它们都会被序列化到字节缓冲区中。每个缓存get()和每个put()操作都需要相当多的CPU周期。
Ehcache在默认使用IdentityCopier拷贝器时切换到按引用存储(即将对象直接放入缓存),请参见CompleteConfiguration的源代码。因此,为避免序列化/反序列化,我在我的ehcache.xml中添加了一个default-copiers元素。
<?xml version="1.0" encoding="UTF-8"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ehcache.org/v3" xmlns:jsr107="http://www.ehcache.org/v3/jsr107">

    <service>
        <jsr107:defaults enable-management="false" enable-statistics="false" default-template="default" />
    </service>

    <default-copiers>
        <copier type="java.lang.Object">org.ehcache.impl.copy.IdentityCopier</copier>
    </default-copiers>
    
    <cache>...</cache>
    <cache-template name="default">...</cache-template>
</config>

0
你解决了Hibernate二级缓存性能问题吗?在某些应用程序中,diskPersistence和overFlowToDisk被启用,并且在TRACE日志中注意到了克隆/序列化/反序列化。不明白为什么Hibernate/Ehcache需要再次克隆/反序列化本地JVM对象。

我还没有想出如何使用快速的二级缓存。在关键的地方,我使用一个带有分离对象的内存 ehcache。它确实有缺点,因为你必须小心不要尝试合并从该缓存获取的对象。 - P.Péter
我只想说我有完全相同的问题。使用简单的HashMap替换ehcache 3.8进行测试,速度提高了约200倍。反序列化真的是这么慢吗? - MTilsted
@kisna 看看我的回答,我通过设置<default-copiers>并使用IdentityCopier来提高缓存性能。但是如果你正在进行磁盘操作(那么显然需要序列化),这可能不起作用。 - Guillaume

0
我们也遇到了这个问题。如果您从第二级缓存中存储和检索许多对象,则必须考虑水合和脱水的时间。
这不是便宜的。但是需要,因为您不能将真实实体放入第二级缓存中。首先,对象绑定到会话并可能具有某些代理和其他 hibernate 魔法内容。其次,对象将在多个会话/事务之间共享。因此,hibernate 进行水合和脱水。
为了在某些情况下拥有更快的解决方案,我们所做的是构建一个“第三级缓存”,使用 Spring @Cacheable,在其中放置 DTO 对象(我们称之为 DataTransferObject),这些对象是只读的。因此,如果我们有一个 Member 实体,则有一个 MemberDTO,它是第三级缓存的对象。它基本上是真实实体的副本,仅用于缓存目的。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接