Pau*_*lor 5 java hibernate ehcache
将对象添加到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 level 2。因为它需要更少的操作来获取歌曲。此外,当写入二级缓存中的条目时,Hibernate 倾向于从缓存中逐出。确保将其配置为不这样做。
关于修改的注释。默认情况下,Ehcache 堆上缓存(并且仅堆上缓存)是按引用进行的。因此,如果您从缓存中检索 Song 对象然后修改它,则缓存中的条目也会被修改,因为它实际上是唯一的实例。
然而,Hibernate 二级缓存并不是这样工作的。他们将在缓存中保存某种数据库行。这将被转换为歌曲并返回给您。
当您将歌曲保存到数据库时,Hibernate 会将其从缓存中逐出,正如我上面所说的那样(但您可能会要求在配置中进行缓存更新,我对此不确定)。
这就是为什么我认为你应该直接缓存而不是使用二级缓存。但是,请小心,因为您会得到一个由 Hibernate 加载的对象。在将其放入缓存之前,您需要将其与 Hibernate 分离。然后将其附加到新的执行器中。否则,例如,如果您有收藏,可能会发生奇怪的事情。
现在,假设您希望每次都更新缓存和数据库。您有两种方法可以做到这一点。
使用 Cache-aside,您将更新数据库,然后更新缓存。
通过缓存直通,您将更新缓存,缓存将负责(原子地)更新数据库。CacheLoaderWriter由于您需要提供一个实现,因此缓存通过会涉及更多一些。但它确保缓存和数据库始终同步。
| 归档时间: |
|
| 查看次数: |
162 次 |
| 最近记录: |