如何使用分布式 Ehcache 运行具有相同数据库模式的多个 Hibernate SessionFactories
我们有一个包含 n 个客户端(目前为 55 个)的系统,其中每个客户端都有自己的数据库,所有数据库都具有完全相同的架构。我们正在运行由分布式 ehcache 支持的 hibernate 3.6.1。这是通过 SessionFactoryService 每个数据库一个 SessionFactory 来实现的,SessionFactoryService 在运行时“懒惰”地为每个 jvm 每个客户端创建一个 SessionFactory(存储在 HashMap 中),因此我们正在运行一组应用程序管理的 SessionFactory。有一个基本的休眠配置文件,其余设置在创建时以编程方式完成。我们的存储库(或者更常见的 DAO)可以通过 SessionFactoryService 访问 SessionFactory。我们充分利用了由分布式 SingltonEhcacheRegionFactory 支持的 Hibernate 二级缓存。因为我们每个 jvm 运行 n 个 SessionFactories,所以我们不想要一个 NON SingltonEhacheRegionFactory(即每个 SessionFactory 有一个 CacheManager),因为在尝试保持跨缓存同步时,SessionFactories 之间会有太多的 jvm 间通信。因此,我们想要的只是服务器之间的通信,而不是服务器内的通信,这已经通过 SingltonEhcacheRegionFactory 实现了。
现在,乐趣开始了。通过上述设置,将会出现缓存冲突,因为无法保证数据库模式中的唯一键,因此支持它们的实体对象在 SessionFactories 中是相同的。为了使它们唯一,我们通过上面的编程配置步骤将字段 hibernate.cache.region_pre-fix 设置为每个 SessionFactory 的唯一值。这满足了 Hibernate 对二级缓存的看法,但底层的单例 ehcache 现在有一个问题。它无法找到正确的配置,因为 ehache.xml 配置文件中指定的配置在缓存名称上没有缓存前缀(也不能,因为每个前缀的每个缓存配置都必须有一个重复条目)其中有 n 个)。这会导致以下错误:
10:37:38,389 WARN AbstractEhcacheRegionFactory:201 - 在 Hibernate 配置中找不到 TransactionManagerLookup,XA 缓存将参与两阶段提交! 10:37:39,675 警告 AbstractEhcacheRegionFactory:143 - 找不到名为 [some_prefix.adc] 的缓存的特定 ehcache 配置;使用默认值。 10:37:40,328 警告 AbstractEhcacheRegionFactory:143 - 找不到名为 [some_prefix.org.hibernate.cache.UpdateTimestampsCache] 的缓存的特定 ehcache 配置;使用默认值。 10:37:40,331 警告 AbstractEhcacheRegionFactory:143 - 找不到名为 [some_prefix.org.hibernate.cache.StandardQueryCache] 的缓存的特定 ehcache 配置;使用默认值。
那么问题是,我们如何才能在每个 jvm 环境中实现具有分布式单例 ehcache 的多个 SessionFactory 呢?有没有办法将 ehcache 配置为区域前缀感知?我们实施的解决方案充其量只是hacky。我们已经实现了自己的 hibernate.cache.region.factory_class ,它扩展了 SingltonEhcacheRegionFactory (并删除了 hibernate 缓存区域前缀配置)。我们的实现所做的就是拦截对底层 Ehcache 的方法调用,并将前缀附加到用于缓存操作的所有键,从而防止缓存冲突。我们想要一个更加“开箱即用”的解决方案,出于显而易见的原因,我们所实施的方案虽然有效,但并不理想。我已阅读了有关此事的所有内容,但尚未找到使用分布式二级缓存以相同架构(最重要的是)处理多个 SessionFactories 的解决方案。任何想法、解决方案或建议将不胜感激。如果有人有很好的方法来满足要求,我什至愿意接受完全不同的设计。提前致谢!
We have a system with n number of clients (55 at this time) where each client gets their own database all of which have the exact same schema. We are running hibernate 3.6.1 backed by a distributed ehcache. This has been implemented with a SessionFactory per database via a SessionFactoryService that at run time "lazily" creates one SessionFactory per client per jvm (stored in a HashMap), so we are running an Application managed set of SessionFactories. There is one basic hibernate configuration file with the remainder of the settings done programmatically at creation time. Our repositories (or DAOs as they are more commonly referred to) are given access to the SessionFactory via the SessionFactoryService. We are taking full advantage of the hibernate second level cache backed by a SingltonEhcacheRegionFactory which is distributed. Because we are running n number of SessionFactories per jvm, we do not want a NON SingltonEhacheRegionFactory (i.e. having a CacheManager per SessionFactory) as there will be too much inter jvm communication between SessionFactories while trying to maintain synchronization across caches. So what we want is only communication across servers NOT communication within a server and this has been achieved via the SingltonEhcacheRegionFactory.
Now, here is where the fun starts. With the above setup, there will be cache collisions as there is no way to guarantee unique keys as the database schemas and hence the entity objects backing them are the same across SessionFactories. In order to make them unique, we have set the field hibernate.cache.region_pre-fix to a unique value per SessionFactory via the programmatic configuration step above. This satisfies Hibernate's view of the second level cache BUT the underlying singleton ehcache now has an issue. It cannot find the correct configuration as the configurations specified in the ehache.xml config file don't have the cache prefix on the cache name (nor could they as there would have to be a duplicate entry for each cache configuration for each prefix, of which there are n number). This causes the below error:
10:37:38,389 WARN AbstractEhcacheRegionFactory:201 - No TransactionManagerLookup found in Hibernate config, XA Caches will be participating in the two-phase commit!
10:37:39,675 WARN AbstractEhcacheRegionFactory:143 - Couldn't find a specific ehcache configuration for cache named [some_prefix.adc]; using defaults.
10:37:40,328 WARN AbstractEhcacheRegionFactory:143 - Couldn't find a specific ehcache configuration for cache named [some_prefix.org.hibernate.cache.UpdateTimestampsCache]; using defaults.
10:37:40,331 WARN AbstractEhcacheRegionFactory:143 - Couldn't find a specific ehcache configuration for cache named [some_prefix.org.hibernate.cache.StandardQueryCache]; using defaults.
So the question is, how can we accomplish a multiple SessionFactory with a distributed singlton ehcache per jvm environment? Is there a way to configure ehcache to be region pre-fix aware? The solution we have implemented is hacky at best. We have implemented our own hibernate.cache.region.factory_class which extends SingltonEhcacheRegionFactory (and removed the hibernate cache region prefix config). All our implementation does is intercept method calls to the underlying Ehcache and appends a pre-fix to all keys used for cache operations, thereby preventing cache collisions. We would like a more "out of the box" solution and for obvious reasons what we have implemented though it works, is not ideal. I have read everything I can possibly find on the matter and haven't found a solution that address multiple SessionFactories with the SAME SCHEMA (and most importantly) using a distributed second level cache. Any ideas, solutions, or advice would be much appreciated. I am even open to an entirely different design if someone has a good way to address the requirements. Thanks in advance!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
。您是什么意思?如果您对所有客户端使用相同的架构,那么肯定有一种方法可以保证唯一的密钥。有很多技术可以实现这一点,包括使用 UUID 或使用 Hibernate 的 hilo 算法。
。不确定我是否理解。您的意思是为了能够获得唯一的密钥,您需要不同的缓存区域?如果是这样,那就不是真的:-) 缓存区域应该是实体(Car、Person、Account)的“命名空间”,而不是条目(Car#1、Car#2)的“命名空间”。
多个会话工厂不是问题。不确定 ehcache,但我会考虑使用“缓存服务器”,例如 Infinispan。您可以在它自己的 JVM 中启动它,所有客户端在想要访问缓存时都会与它对话。同样,不确定我是否正确理解了您的环境,但是在使用缓存时,您应该使用确保 Client#1 看到的数据与 Client#2 相同的设置。
因此,我将设置一个具有专用缓存服务器的环境,配置所有会话工厂以使用它。另外,您在描述中遗漏的一点是事务管理器。在处理分布式环境时,事务管理非常重要,以确保缓存(和数据库)中的数据不陈旧且一致。
您可以在此处阅读有关 Infinispan 与 Hibernate 的更多信息:http://community.jboss.org/wiki/usinginfinispanasjpahibernatesecondlevelcacheprovider
What do you mean? If you are using the same schema for all clients, there is certainly a way to guarantee unique keys. There are a lot of techniques for this, including using UUID or using Hibernate's hilo algorithm.
Not sure I understood. You mean that to be able to get unique keys you need different cache regions? If so, that's not true :-) Cache regions are supposed to be a "namespace" for entities (Car, Person, Account), not for entries (Car#1, Car#2).
Multiple session factories are not a problem. Not sure about ehcache, but I would consider using a "Cache server", like Infinispan. You can start it in its own JVM, and all clients would talk to it whenever they want to access the cache. Again, not sure I understood your environment correctly, but when using a cache, you should use a setup which ensures that the data that Client#1 sees is the same as Client#2.
So, I would setup an environment with a dedicated cache server, configuring all session factories to use it. Also, one bit that you missed in your description is the transaction manager. When dealing with distributed environments, transaction management is really important, to ensure that the data in the cache (and database) are not stale and are consistent.
You can read more about Infinispan with Hibernate here: http://community.jboss.org/wiki/usinginfinispanasjpahibernatesecondlevelcacheprovider