避免同一缓存区域的多次重新填充(由于并发) [英] Avoiding multiple repopulations of the same cache region (due to concurrency)

查看:189
本文介绍了避免同一缓存区域的多次重新填充(由于并发)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个高流量的网站,我使用hibernate。我还使用ehcache来缓存生成页面所需的一些实体和查询。



问题是并行缓存未命中,并且长解释是当应用程序引导和高速缓存区域是冷的每个高速缓存区域由不同的线程填充多次(而不是仅一次),因为该站点同时被许多用户命中。此外,当一些高速缓存区域无效时,由于相同的原因它被重新填充多次。
如何避免这种情况?



我设法通过向hibernate.cache.provider_class提供我自己的实现将1个实体和1个查询缓存转换为BlockingCache ,但BlockingCache的语义似乎不工作。甚至最糟糕的是,BlockingCache死锁(块)和应用程序完全挂起。线程转储显示处理被阻塞在BlockingCache的互斥上获取操作。



所以,问题是,Hibernate是否支持这种使用?



如果不是,您如何在生产中解决这个问题?

em> hibernate.cache.provider_class 指向我的自定义缓存提供程序,它是从 SingletonEhCacheProvider ,在start()方法结束时(第136行之后)我执行:

  Ehcache cache = manager.getEhcache(foo); 
if(!(cache instanceof BlockingCache)){
manager.replaceCacheWithDecoratedCache(cache,new BlockingCache(cache));
}

这样,在初始化之后, ,我用BlockingCache装饰它。 foo是一个查询缓存,bar(相同的代码,但省略)是pojo的实体缓存。



似乎不工作意味着初始问题仍然存在。由于并发性,缓存foo仍然被相同的数据重新填充多次。我验证这通过强调与JMeter的网站有10个线程。我希望9个线程阻塞,直到第一个请求数据从foo完成它的工作(执行查询,存储数据在缓存),然后直接从缓存获取数据。



修改3 :此问题的另一个解释可以在 https://forum.hibernate.org/viewtopic.php?f=1&t=964391&start=0 但没有明确的答案。 / p>

解决方案

这个问题最大的改进是ehcache现在(从2.1开始)支持事务休眠缓存策略。这大大减轻了这个问题中描述的问题。



为了进一步(在访问同一个查询缓存区域时锁定线程),需要实现< a href =http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/hql/QueryTranslatorFactory.html =nofollow> QueryTranslatorFactory 返回自定义(扩展)< a href =http://docs.jboss.org/hibernate/core/3.5/api/org/hibernate/hql/ast/QueryTranslatorImpl.html =nofollow> QueryTranslatorImpl 实例,它将检查查询并在列表方法中根据需要使用参数和块。这当然要考虑查询缓存的具体使用情况,使用hql获取很多实体。


I have a high traffic website and I use hibernate. I also use ehcache to cache some entities and queries which are required to generate the pages.

The problem is "parallel cache misses" and the long explanation is that when the application boots and the cache regions are cold each cache region is being populated many times (instead of only once) by different threads because the site is being hit by many users at the same time. In addition, when some cache region invalidates it's being repopulated many times because of the same reason. How can I avoid this?

I managed to convert 1 entity and 1 query cache to a BlockingCache by providing my own implementation to hibernate.cache.provider_class but the semantics of BlockingCache do not seem to work. Even worst sometimes the BlockingCache deadlocks (blocks) and the application hangs completely. Thread dump shows that processing is blocked on the mutex of BlockingCache on a get operation.

So, the question is, does Hibernate support this kind of use?

And if not, how do you solve this problem on production?

Edit: The hibernate.cache.provider_class points to my custom cache provider which is a copy paste from SingletonEhCacheProvider and at the end of the start() method (after line 136) I do:

Ehcache cache = manager.getEhcache("foo");
if (!(cache instanceof BlockingCache)) {
    manager.replaceCacheWithDecoratedCache(cache, new BlockingCache(cache));
}

That way upon initialization, and before anyone else touches the cache named "foo", I decorate it with BlockingCache. "foo" is a query cache and "bar" (same code but omitted) is an entity cache for a pojo.

Edit 2: "Doesn't seem to work" means that the initial problem still exists. Cache "foo" is still being re-populated many times with the same data, because of the concurrency. I validate this by stressing the site with JMeter with 10 threads. I'd expect the 9 threads to block until the first one which requested data from "foo" to finish it's job (execute queries, store data in cache), and then get the data directly from the cache.

Edit 3: Another explanation for this problem can be seen at https://forum.hibernate.org/viewtopic.php?f=1&t=964391&start=0 but with no definite answer.

解决方案

The biggest improvement on this issue is that ehcache now (since 2.1) supports the transactional hibernate cache policy. This vastly mitigates the problems described in this issue.

In order to go a step further (lock threads while accessing the same query cache region) one would need to implement a QueryTranslatorFactory to return custom (extended) QueryTranslatorImpl instances which would inspect query and parameters and block as necessary in the list method. This of course regards the specific use case of query cache using hql which fetch many entities.

这篇关于避免同一缓存区域的多次重新填充(由于并发)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆