金氧

JPA 缓存与应用集群

摘要

本文主要介绍了 JPA 缓存体系结构以及在集群环境下 JPA 二级缓存的问题及应对策略。

JPA 缓存

JPA 缓存分为一级缓存(L1)与二级缓存(L2)。

其中,一级缓存即实体管理器(EntityManager),主要负责实体状态管理。
二级缓存即 EntityManagerFactory 缓存,主要负责缓存实体或数据行(例如 EclipseLink 缓存实体,Hibernate 缓存实体 Id 与数据行)。

查询时,二级缓存可以有效缓解数据库压力,并有助于集合实体的初始化。

JPA Cache

JPA 与应用集群

当应用运行在一个 JVM 里时,JPA 缓存是没有问题的。但如果进行应用集群,那么 L2 的更新机制将出现一致性问题。

JPA Cache in Cluster

下面提供两个通用策略以及一个产品相关策略来解决这个问题。

策略 1:禁用 L2 缓存

如果禁用二级缓存的话,

所有节点的数据视图总是可以保证一致
数据总是一致的
每一次事务查询时都将从数据库获取数据构造实体
不存在节点间消息
应用占用内存上升,因为每次事务都要构造实体
每次事务需要效率变低,因为需要构造实体
性能瓶颈——数据库

策略 2:L2 缓存同步

JPA Cache Coordination in Cluster

如果进行 L2 缓存同步,

所有节点的数据视图总是可以保证一致
数据总是一致的
事务查询尽量使用 L2 缓存的实体
创建/更新/删除 实体时需要同步所有其他节点
同步代价为 O(n2)——网络通讯与同步处理开销可能会超过缓存带来的好处
Cache Cooradination(Orz)

L2 缓存大小受限于单个节点 JVM 内存堆大小
主流 JPA 实现一般会提供 JMS、RMI、JGroups 来进行缓存同步。

策略3:一致性数据层

这里所谓的“一致性数据层”就是指使用一个能够保证分布式时数据一致性的服务,用于替换 L2。

例如组合使用 Oracle Coherence 与 TopLink Grid。

结语

对于一个基于 JPA 的 Web 应用,我们必须注意 JPA 二级缓存在集群时的问题,这是可伸缩的基本点之一。

为了解决 JPA 二级缓存不一致的问题,我们必须牺牲一定的应用性能,或是使用商业产品。

反思

ORM 固然方便,但我认为它带来的问题远比解决的问题多,基于关系型数据库的应用还是 JDBC 直接。

框架是为了简化代码,统一管理。但同时带来的限制也不容忽视。

个人还是偏向于自造轮子,宁肯多写一些代码,也不愿被框架束缚。

参考

  • Shaun Smith, TopLink Grid: Scaling JPA Application with Coherence, 2010
  • Tom Pfaeffle, Oracle Fusion Middleware Integration Guide for Oracle TopLink with Coherence Grid, 11g Release 1 (11.1.1) E16596-02, 2011-02
  • Doug Clarke, Persistence Strategies for Java EE and WebLogic
  • EclipseLink
  • Sandesh, Toplink Cache and Weblogic Cluster