java – 具有Hibernate二级缓存的CPU优势何时超过初始命中

将对象添加到Hibernate二级对象缓存的CPU优势何时超过初始命中.

我目前正在使用没有二级缓存的Hibernate.这适用于处理音乐文件(www.jthink.net/songkong)的应用程序,它使用Hibernate,因此它可以扩展更多数据,即它可以处理100,000首歌曲,内存少于1000首歌曲.一旦处理完歌曲,那些歌曲就没兴趣了(除非用户运行撤销)

据我所知,如果我启用二级缓存(对于我的歌曲类),那么首先将歌曲写入缓存将使用更多的cpu然后如果只是写入数据库,并且对歌曲对象的其他修改也将需要更多的cpu资源.但是随后从Ehcache中检索歌曲将需要更少的资源,然后从数据库中检索它.

我的歌曲按文件夹逐个处理并经过多个阶段(在不同的执行程序上),当它们在下一个Executor上排队时我们只是将歌曲ID作为参数传递,否则它将使用大量堆内存来存储Song对象他们自己.因此,当特定任务实际上在Executor上运行时,它所做的第一件事就是检索那些id的歌曲.

因此,没有特定的歌曲ID被检索1000次,但每首歌曲通常被写入1至4次并检索10次.因此,如果我们有一个非常小的缓存(因为我想保持堆内存受到严密控制)我会期望处理前几个文件夹将其歌曲添加到缓存中,然后当他们从新文件夹中完成歌曲时将采取他们的放在缓存中.

但我的问题是,它值得吗?

根据经验,10次检索与1-4次写入有意义使用二级缓存,或仅在比率更像100:1时才有用?

最佳答案
真正的答案是:只需对它进行基准测试.

写入堆缓存并不是那么昂贵.所以是的,即使从缓存中检索一次也会更快,然后回到数据库.

然后,缓存主要在HashMap之上执行两项操作.它驱逐并过期.

驱逐意味着您将一些最大大小设置为缓存.达到此值后,缓存将逐出“最旧”条目以添加新条目.最老的有多种定义. Ehcache对一组条目进行抽样,并踢出样本中访问时间最长的条目.

到期意味着某个特定条目在某些时候将被视为陈旧.例如,您希望在使用数据库中最新的条目刷新条目前1小时保留一个条目.当您收到条目时,Ehcache会首先查看条目是否已过期.如果是,则返回null并从缓存中删除该条目.这意味着过期的条目将保留在缓存中,直到您尝试访问它.

在您的情况下,您将需要加载一次条目.然后把它放在缓存中.使用它,最后删除它以节省内存.如果您有最后一步,您知道不再需要该条目,请将其删除.

如果你不这样做,你将不得不依赖驱逐.因为驱逐算法会先删除过期的条目(为什么删除一个完全有效的条目,如果你可以删除过期的条目?).

您应该计算一个条目应该保留在缓存中以通过所有执行程序的时间.这将是您的到期时间(TTL).然后,您或多或少地将缓存大小调整为NB_EXECUTORS * NB_STEPS.然后它将是当前使用的歌曲的大小.添加新歌曲时,缓存需要逐出旧条目.在大多数情况下,此条目将过期,因此不会造成任何伤害.

为了防止驱逐(在找不到过期条目时成本很高),您可以编写获取条目的后台例程.它会触发到期.但同样,在确定使用基准测试之前,不要这样做,它实际上更快.

最后,您可能希望直接缓存歌曲而不是使用Hibernate级别2.因为它需要较少的操作才能获得歌曲.此外,当编写二级缓存中的条目时,Hibernate倾向于从缓存中逐出.确保将其配置为不这样做.

关于修改的说明.默认情况下,Ehcache堆栈缓存(仅限堆上缓存)是每个引用.因此,如果从缓存中检索Song对象然后对其进行修改,则缓存中的条目也会被修改,因为它实际上是唯一的实例.

但是,这不是Hibernate二级缓存的工作原理.他们会在缓存中保留某种数据库行.这将转换为歌曲并返回给您.

当您将歌曲保存到数据库时,Hibernate会像我上面所说的那样将其从缓存中逐出(但您可能会要求在配置中更新缓存,我不确定).

这就是为什么我认为你应该直接缓存而不是使用二级缓存.但请注意,因为你得到了一个由Hibernate加载的对象.在将其放入缓存之前,您需要将其从Hibernate中分离出来.然后将其附加到新执行程序中.否则,如果你有集合,可能会发生奇怪的事情.

现在,假设您希望每次都更新缓存和数据库.你有两种方法可以做到这一点.

使用Cache-aside,您将更新数据库,然后更新缓存.

使用Cache-through,您将更新缓存,这将更新数据库(雾).由于您需要提供CacheLoaderWriter实现,因此Cache-through更加复杂.但它确保缓存和数据库始终保持同步.

转载注明原文:java – 具有Hibernate二级缓存的CPU优势何时超过初始命中 - 代码日志