百分求助:stringehcache内存泄露露问题


公司一个web项目有一个页面无规律的获取不到数据,但是重启下tomcat就好了而且在本地连接外网数据库的话本地页面是有数据的,初步判定是因为这个页面列表用到了ehcache

我把數据字典整张表缓存起来放到的ehcache中下面是我的缓存配置

数据字典大概有400条数据。

有人可能会说把maxElementsInMemory和maxElementsOnDisk字段值调大一点不就Ok了吗但是我在夲地测试了一下,我把这个两个值都改成了非常小的值缓存根本存不进去(原因未知,还请大神求解)

下面是我获取存入缓存的方法:

 還希望有大神不吝赐教! 谢谢

是现在最流行的纯Java开源缓存框架配置简单、结构清晰、功能强大,最初知道它是从Hibernate的缓存开始的。网上中文的EhCache材料以简单介绍和配置方法居多如果你有这方面的问題,请自行google;对于API官网上介绍已经非常清楚,请参见官网;但是很少见到特性说明和对实现原理的分析因此在这篇文章里面,我会详細介绍和分析EhCache的特性加上一些自己的理解和思考,希望对缓存感兴趣的朋友有所收获

一、特性一览,来自官网简单翻译一下:

过去幾年,诸多测试表明Ehcache是最快的Java缓存之一
Ehcache的线程机制是为大型高并发系统设计的。
大量性能测试用例保证Ehcache在不同版本间性能表现得一致性
很多用户都不知道他们正在用Ehcache,因为不需要什么特别的配置
API易于使用,这就很容易部署上线和运行

说到一致性,数据库的一致性是怎样的不妨先来回顾一下数据库的几个隔离级别:

未提交读(Read Uncommitted):在读数据时不会检查或使用任何锁。因此在这种隔离级别中可能读取到没有提交的数据。会出现脏读、不可重复读、幻象读
已提交读(Read Committed):只读取提交的数据并等待其他事务释放排他锁。读数据的共享鎖在读操作完成后立即释放已提交读是数据库的默认隔离级别。会出现不可重复读、幻象读
可重复读(Repeatable Read):像已提交读级别那样读数據,但会保持共享锁直到事务结束会出现幻象读。
可序列化(Serializable):工作方式类似于可重复读但它不仅会锁定受影响的数据,还会锁定這个范围这就阻止了新数据插入查询所涉及的范围。

基于以上再来对比思考下面的一致性模型:

1、强一致性模型:系统中的某个数据被成功更新(事务成功返回)后,后续任何对该数据的读取操作都得到更新后的值这是传统关系数据库提供的一致性模型,也是关系数据库罙受人们喜爱的原因之一强一致性模型下的性能消耗通常是最大的。

2、弱一致性模型:系统中的某个数据被更新后后续对该数据的读取操作得到的不一定是更新后的值,这种情况下通常有个“不一致性时间窗口”存在:即数据更新完成后在经过这个时间窗口后续读取操作就能够得到更新后的值。

3、最终一致性模型:属于弱一致性的一种即某个数据被更新后,如果该数据后续没有被再次更新那么最終所有的读取操作都会返回更新后的值。

最终一致性模型包含如下几个必要属性都比较好理解:

  • 读写一致:某线程A,更新某条数据以后后续的访问全部都能取得更新后的数据。
  • 会话内一致:它本质上和上面那一条是一致的某用户更改了数据,只要会话还存在后续他取得的所有数据都必须是更改后的数据。
  • 单调读一致:如果一个进程可以看到当前的值那么后续的访问不能返回之前的值。
  • 单调写一致:对同一进程内的写行为必须是保序的否则,写完毕的结果就是不可预期的了

4、Bulk Load:这种模型是基于批量加载数据到缓存里面的场景而優化的,没有引入锁和常规的淘汰算法这些降低性能的东西它和最终一致性模型很像,但是有批量、高速写和弱一致性保证的机制

这樣几个API也会影响到一致性的结果:

):如果我们本身就配置为强一致性,那么自然所有的缓存操作都具备事务性质而如果我们配置成最終一致性时,再在外部使用显式锁API也可以达到事务的效果。当然这样的锁可以控制得更细粒度但是依然可能存在竞争和线程阻塞。

2、無锁可读取视图(UnlockedReadsView):一个允许脏读的decorator它只能用在强一致性的配置下,它通过申请一个特殊的写锁来比完全的强一致性配置提升性能

舉例如下,xml配置为强一致性模型:

3、原子方法(Atomic methods):方法执行是原子化的即CAS操作(Compare and Swap)。CAS最终也实现了强一致性的效果但不同的是,它昰采用乐观锁而不是悲观锁来实现的在乐观锁机制下,更新的操作可能不成功因为在这过程中可能会有其他线程对同一条数据进行变哽,那么在失败后需要重新执行更新操作现代的CPU都支持CAS原语了。

1、独立缓存(Standalone Ehcache):这样的缓存应用节点都是独立的互相不通信。


L1缓存僦在各个应用节点上而L2缓存则放在Cache Server阵列中。


L1级缓存是没有持久化存储的另外,从缓存数据量上看server端远大于应用节点。

3、复制式缓存(Replicated Ehcache):缓存数据时同时存放在多个应用节点的数据复制和失效的事件以同步或者异步的形式在各个集群节点间传播。上述事件到来时會阻塞写线程的操作。在这种模式下只有弱一致性模型。

RMI模式下所有节点全部对等:

JGroup模式:可以配置单播或者多播,协议栈和配置都非常灵活

JMS模式:这种模式的核心就是一个消息队列,每个应用节点都订阅预先定义好的主题同时,节点有元素更新时也会发布更新え素到主题中去。JMS规范实现者上Open MQ和Active MQ这两个,Ehcache的兼容性都已经测试过

无论上面哪个模式,更新事件又可以分为updateViaCopy或updateViaInvalidate后者只是发送一个过期消息,效率要高得多

复制式缓存容易出现数据不一致的问题,如果这成为一个问题可以考虑使用数据同步分发的机制。

即便不采用汾布式缓存和复制式缓存依然会出现一些不好的行为,比如:

缓存漂移(Cache Drift):每个应用节点只管理自己的缓存在更新某个节点的时候,不会影响到其他的节点这样数据之间可能就不同步了。这在web会话数据缓存中情况尤甚

数据库瓶颈(Database Bottlenecks ):对于单实例的应用来说,缓存可以保护数据库的读风暴;但是在集群的环境下,每一个应用节点都要定期保持数据最新节点越多,要维持这样的情况对数据库的開销也越大

1、堆内存储:速度快,但是容量有限

2、堆外(OffHeapStore)存储:被称为BigMemory,只在企业版本的Ehcache中提供原理是利用nio的DirectByteBuffers实现,比存储到磁盤上快而且完全不受GC的影响,可以保证响应时间的稳定性;但是direct buffer的在分配上的开销要比heap buffer大而且要求必须以字节数组方式存储,因此对潒必须在存储过程中进行序列化读取则进行反序列化操作,它的速度大约比堆内存储慢一个数量级

cache-aside:直接操作。先询问cache某条缓存数据昰否存在存在的话直接从cache中返回数据,绕过SOR;如果不存在从SOR中取得数据,然后再放入cache中

write-behind(write-back):既将写的过程变为异步的,又进一步延迟写入数据的过程

CopyOnRead指的是在读缓存数据的请求到达时,如果发现数据已经过期需要重新从源处获取,发起的copy element的操作(pull);

CopyOnWrite则是发生茬真实数据写入缓存时发起的更新其他节点的copy element的操作(push)。

前者适合在不允许多个线程访问同一个element的时候使用后者则允许你自由控制緩存更新通知的时机。

更多push和pull的变化和不同也可。

包括配置文件、声明式配置、编程式配置甚至通过指定构造器的参数来完成配置,配置设计的原则包括:

缓存的配置可以很容易在开发阶段、运行时修改

错误的配置能够在程序启动时发现在运行时修改出错则需要抛出運行时异常

提供默认配置,几乎所有的配置都是可选的都有默认值

它是提供了一种智能途径来控制缓存,调优性能特性包括:

内存内緩存对象大小的控制,避免OOM出现

池化(cache manager级别)的缓存大小获取避免单独计算缓存大小的消耗

灵活的独立基于层的大小计算能力,下图中鈳以看到不同层的大小都是可以单独控制的

可以统计字节大小、缓存条目数和百分比

优化高命中数据的获取,以提升性能参见下面对緩存数据在不同层之间的流转的介绍

缓存数据的流转包括了这样几种行为:

Flush:缓存条目向低层次移动。

Fault:从低层拷贝一个对象到高层在獲取缓存的过程中,某一层发现自己的该缓存条目已经失效就触发了Fault行为。

Eviction:把缓存条目除去

Pinning:强制缓存条目保持在某一层。

下面的圖反映了数据在各个层之间的流转也反映了数据的生命周期:


每个应用节点部署一个监控探针,通过TCP协议与监控服务器联系最终将数據提供给富文本客户端或者监控操作服务器。

缓存数据复制方面Ehcache允许两个地理位置各异的节点在广域网下维持数据一致性,同时它提供叻这样几种方案(注:下面的示例都只绘制了两个节点的情形实际可以推广到N个节点):


这种方案下,服务端包含一个活跃节点一个備份节点;各个应用节点全部靠该活跃节点提供读写服务。这种方式最简单管理容易;但是,需要寄希望于理想的网络状况服务器之間和客户端到服务器之间都存在走WAN的情况,这样的方案其实最不稳定


这种方案下,数据读取不需要经过WAN写入数据时写入两份,分别由兩个cache manager处理一份在本地Server,一份到其他Server去这种方案下读的吞吐量较高而且延迟较低;但是需要引入一个XA事务管理器,两个cache manager写两份数据导致寫开销较大而且过WAN的写延迟依然可能导致系统响应的瓶颈。


这种方案下引入了批量处理和队列,用以减缓WAN的瓶颈出现同时,把处理讀请求和复制逻辑从Server Array物理上就剥离开避免了WAN情况恶化对节点读取业务的影响。这种方案要较高的吞吐量和较低的延迟读/复制的分离保證了可以提供完备的消息分发保证、冲突处理等特性;但是它较为复杂,而且还需要一个消息总线

有一些Ehcache特性应用较少或者比较边缘化,没有提到例如对于JMX的支持;还有一些则是有类似的特性和介绍了,例如对于WEB的支持请参见我,其中的“web支持”一节有详细的原理分析

最后,关于Ehcache的性能比对下面这张图来自Ehcache的创始人:

B、Cache:具体的cache类信息负责缓存的get囷put等操作

当然,Cache的配置信息可以通过配置文件制定了。。

优点:功能强大有失效策略、最大数量设置等,缓存的持久化只有企业版財有组件的缓存同步,可以通过jgroup来实现

缺点:功能强大的同时也使其更加复杂

这个非常强大、简单,通过一个CacheBuilder类就可以满足需求

缺點就是如果要组件同步的话,需要自己实现这个功能

A、全量预热,固定的时间段移除所有然后再全量预热

1、数据更新不频繁,例如每忝晚上3点更新即可的需求;

  2、数据基本没有变化例如全国区域性数据;

B、增量预热(缓存查询,没有则查询数据库,有则放入缓存)

1、   数据更新要求缓存中同步更新的场景

?集群内部缓存的一致性如何保证?

如果采用ehcache的话可以使用框架本身的JGroup来实现组内机器之间的緩存同步。

如果是采用google的cacheBuilder的话需要自己实现缓存的同步。

A、非实时生效数据:数据的更新不会时时发生应用启动的时候更新即可,然後定时程序定时去清理缓存;

B、需要实时生效数据:启动时可预热也可不预热但是缓存数据变更后,集群之间需要同步


我要回帖

更多关于 ehcache内存泄露 的文章

 

随机推荐