我的网站流量很高,并且使用hibernate模式。我还使用ehcache缓存生成页面所需的一些实体和查询。
问题是“并行高速缓存未命中”,长原因是当应用程序启动且高速缓存区域变冷时,每个高速缓存区域将由不同线程填充多次(而不是仅一次),因为该站点受到许多用户的攻击与此同时。另外,由于相同的原因,当某些缓存区域无效时,它会被多次填充。如何避免这种情况?
我通过向hibernate.cache.provider_class提供自己的实现,设法将1个实体和1个查询缓存转换为BlockingCache,但是BlockingCache的语义似乎不起作用。甚至最糟糕的是,有时BlockingCache死锁(块)并且应用程序完全挂起。线程转储显示在get操作上BlockingCache互斥锁上的处理被阻止。
那么,问题是,Hibernate是否支持这种使用?
如果没有,您如何在生产中解决此问题?
编辑 : hibernate.cache.provider_class 指向我的自定义缓存提供程序,它是从SingletonEhCacheProvider复制粘贴,并且在start()方法的结尾(在第136行之后),我这样做:
Ehcache cache = manager.getEhcache("foo"); if (!(cache instanceof BlockingCache)) { manager.replaceCacheWithDecoratedCache(cache, new BlockingCache(cache)); }
这样,在初始化时,以及在其他任何人触摸名为“ foo”的缓存之前,我都会使用BlockingCache装饰它。“ foo”是查询缓存,“ bar”(相同的代码,但省略了)是pojo的实体缓存。
编辑2 :“似乎不起作用”表示最初的问题仍然存在。由于并发性,高速缓存“ foo”仍多次用相同的数据填充。我通过使用具有10个线程的JMeter对该站点进行强调来验证这一点。我希望9个线程能够阻塞,直到第一个线程从“ foo”请求数据以完成其工作(执行查询,将数据存储在缓存中),然后直接从缓存中获取数据。
编辑3 :有关此问题的另一种解释,请参见https://forum.hibernate.org/viewtopic.php?f=1&t=964391&start=0,但没有明确的答案。
这个问题的最大改进是ehcache现在(从2.1开始)支持transactionalhibernate cache policy。这极大地缓解了此问题中描述的问题。
transactional
为了更进一步(在访问同一查询缓存区域时锁定线程),需要实现QueryTranslatorFactory以返回自定义(扩展)的QueryTranslatorImpl实例,该实例将检查查询和参数,并根据需要在list方法中进行阻塞。当然,这与使用获取许多实体的hql的查询缓存的特定用例有关。