使用EHCache提升网站性能
本文为转载!!
这是一篇很早以前写得文章,整理了一下贴上来,希望对不熟悉EHcache的同学有用。
在开发高并发量,高性能的网站应用系统时,缓存Cache起到了非常重要的作用。本文主要介绍EHCache的使用,以及使用EHCache
的实践经验。
笔者使用过多种基于Java的开源Cache组件,其中包括OSCache、JBossCache、EHCache。OSCache功能强
大,使用灵活,可用于对象缓存、Filter缓存以及在JSP中直接使用cache标签。笔者在最近的使用过程中发现,在并发量较高时,OSCache会
出现线程阻塞和数据错误,通过分析源代码发现是其内部实现的缺陷。JBossCache最大的优点是支持基于对象属性的集群同步,不过
JBossCache的配置使用都较复杂,在并发量较高的情况下,对象属性数据在集群中同步也会加大系统的开销。以上两种Cache本文仅作简单介绍,不
做深入探讨。
EHCache是来自sourceforge(http://ehcache.sourceforge.net/)的开源项目,也是纯
Java实现的简单、快速的Cache组件。EHCache支持内存和磁盘的缓存,支持LRU、LFU和FIFO多种淘汰算法,支持分布式的Cache,
可以作为Hibernate的缓存插件。同时它也能提供基于Filter的Cache,该Filter可以缓存响应的内容并采用Gzip压缩提高响应速
度。
EHCache API的基本用法
首先介绍CacheManager类。它主要负责读取配置文件,默认读取CLASSPATH下的ehcache.xml,根据配置文件创建并
管理Cache对象。
//
使用默认配置文件创建CacheManager
CacheManager manager =
CacheManager.create();
//
通过manager可以生成指定名称的Cache对象
Cache
cache = cache = manager.getCache("demoCache");
//
使用manager移除指定名称的Cache对象
manager.removeCache("demoCache");
可以通过调用manager.removalAll()来移除所有的Cache。通过调用manager的shutdown()方法可以关闭
CacheManager。
有了Cache对象之后就可以进行一些基本的Cache操作,例如:
//往cache中添加元素
Element element = new Element("key", "value");
cache.put(element);
//从cache中取回元素
Element element = cache.get("key");
element.getValue();
//从Cache中移除一个元素
cache.remove("key");
可以直接使用上面的API进行数据对象的缓存,这里需要注意的是对于缓存的对象都是必须可序列化的。在下面的篇幅中笔者还会介绍EHCache和
Spring、Hibernate的整合使用。
配置文件
配置文件ehcache.xml中命名为demoCache的缓存配置:
<cache
name="demoCache"
maxElementsInMemory="10000"
eternal="false"
overflowToDisk="true"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
/>
各配置参数的含义:
maxElementsInMemory:缓存中允许创建的最大对象数
eternal:缓存中对象是否为永久的,如果是,超时设置将被忽略,对象从不过期。
timeToIdleSeconds:缓存数据的钝化时间,也就是在一个元素消亡之前,两次访问时间的最大时间间隔值,
这只能在元素不是永久驻留时有效,如果该值是 0 就意味着元素可以停顿无穷长的时间。
timeToLiveSeconds:缓存数据的生存时间,也就是一个元素从构建到消亡的最大时间间隔值,这只能在元素不是永久驻留时有效,如果该值是0
就意味着元素可以停顿无穷长的时间。
overflowToDisk:内存不足时,是否启用磁盘缓存。
memoryStoreEvictionPolicy:缓存满了之后的淘汰算法。LRU和FIFO算法这里就不做介绍。LFU算法直接淘汰使用
比较少的对象,在内存保留的都是一些经常访问的对象。对于大部分网站项目,该算法比较适用。
如果应用需要配置多个不同命名并采用不同参数的Cache,可以相应修改配置文件,增加需要的Cache配置即可。
利用Spring
APO整合EHCache
首先,在CLASSPATH下面放置ehcache.xml配置文件。在Spring的配置文件中先添加如下cacheManager配置:
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
</bean>
配置demoCache:
<bean id="demoCache"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager"
ref="cacheManager" />
<property
name="cacheName">
<value>demoCache</value>
</property>
</bean>
接下来,写一个实现org.aopalliance.intercept.MethodInterceptor接口的拦截器类。有了拦截器就可以有选择性
的配置想要缓存的
bean 方法。如果被调用的方法配置为可缓存,拦截器将为该方法生成 cache key
并检查该方法返回的结果是否已缓存。如果已缓存,就返回缓存的结果,否则再次执行被拦截的方法,并缓存结果供下次调用。具体代码如下:
public class MethodCacheInterceptor implements
MethodInterceptor,
InitializingBean {
private
Cache cache;
public
void setCache(Cache cache) {
this.cache = cache;
}
public
void afterPropertiesSet() throws Exception {
Assert.notNull(cache,
"A cache is
required. Use setCache(Cache) to provide one.");
}
public
Object invoke(MethodInvocation invocation) throws Throwable {
String targetName =
invocation.getThis().getClass().getName();
String methodName =
invocation.getMethod().getName();
Object[] arguments =
invocation.getArguments();
Object result;
String cacheKey =
getCacheKey(targetName, methodName, arguments);
Element element = null;
synchronized (this){
element = cache.get(cacheKey);
if (element == null) {
//调用实际的方法
result =
invocation.proceed();
element =
new Element(cacheKey, (Serializable) result);
cache.put(element);
}
}
return
element.getValue();
}
private
String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer sb = new
StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null)
&& (arguments.length != 0)) {
for (int i = 0; i <
arguments.length; i++) {
sb.append(".").append(arguments[i]);
}
}
return sb.toString();
}
}
synchronized
(this)这段代码实现了同步功能。为什么一定要同步?Cache对象本身的get和put操作是同步的。如果我们缓存的数据来自数据库查询,在没有这
段同步代码时,当key不存在或者key对应的对象已经过期时,在多线程并发访问的情况下,许多线程都会重新执行该方法,由于对数据库进行重新查询代价是
比较昂贵的,而在瞬间大量的并发查询,会对数据库服务器造成非常大的压力。所以这里的同步代码是很重要的。
接下来,继续完成拦截器和Bean的配置:
<bean id="methodCacheInterceptor"
class="com.xiebing.utils.interceptor.MethodCacheInterceptor">
<property
name="cache">
<ref
local="demoCache" />
来源:(http://blog.sina.com.cn/s/blog_40c7872a0100h7s1.html?retcode=0
)
- 使用EHCache提升网站性能_编程浪子_新浪博客
</property>
</bean>
<bean id="methodCachePointCut"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property
name="advice">
<ref
local="methodCacheInterceptor" />
</property>
<property
name="patterns">
<list>
<value>.*myMethod</value>
</list>
</property>
</bean>
<bean id="myServiceBean"
class="com.xiebing.ehcache.spring.MyServiceBean">
</bean>
<bean id="myService"
class="org.springframework.aop.framework.ProxyFactoryBean">
<property
name="target">
<ref
local="myServiceBean" />
</property>
<property
name="interceptorNames">
<list>
<value>methodCachePointCut</value>
</list>
</property>
</bean>
其中myServiceBean是实现了业务逻辑的Bean,里面的方法myMethod()的返回结果需要被缓存。这样每次对
myServiceBean的myMethod()方法进行调用,都会首先从缓存中查找,其次才会查询数据库。使用AOP的方式极大地提高了系统的灵活
性,通过修改配置文件就可以实现对方法结果的缓存,所有的对Cache的操作都封装在了拦截器的实现中。
CachingFilter功能
使用Spring的AOP进行整合,可以灵活的对方法的的返回结果对象进行缓存。CachingFilter功能可以对HTTP响应的内容进行缓存。这种
方式缓存数据的粒度比较粗,例如缓存整张页面。它的优点是使用简单、效率高,缺点是不够灵活,可重用程度不高。
EHCache使用SimplePageCachingFilter类实现Filter缓存。该类继承自CachingFilter,有默认
产生cache
key的calculateKey()方法,该方法使用HTTP请求的URI和查询条件来组成key。也可以自己实现一个Filter,同样继承
CachingFilter类,然后覆写calculateKey()方法,生成自定义的key。
在笔者参与的项目中很多页面都使用AJAX,为保证JS请求的数据不被浏览器缓存,每次请求都会带有一个随机数参数i。如果使用
SimplePageCachingFilter,那么每次生成的key都不一样,缓存就没有意义了。这种情况下,我们就会覆写
calculateKey()方法。
要使用SimplePageCachingFilter,首先在配置文件ehcache.xml中,增加下面的配置:
<cache name="SimplePageCachingFilter"
maxElementsInMemory="10000" eternal="false"
overflowToDisk="false"
timeToIdleSeconds="300" timeToLiveSeconds="600"
memoryStoreEvictionPolicy="LFU"
/>
其中name属性必须为SimplePageCachingFilter,修改web.xml文件,增加一个Filter的配置:
<filter>
<filter-name>SimplePageCachingFilter</filter-name>
<filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SimplePageCachingFilter</filter-name>
<url-pattern>/test.jsp</url-pattern>
</filter-mapping>
下面我们写一个简单的test.jsp文件进行测试,缓存后的页面每次刷新,在600秒内显示的时间都不会发生变化的。代码如下:
<%
out.println(new Date());
%>
CachingFilter输出的数据会根据浏览器发送的Accept-Encoding头信息进行Gzip压缩。经过笔者测试,Gzip压缩后的数据量
是原来的1/4,速度是原来的4-5倍,所以缓存加上压缩,效果非常明显。
在使用Gzip压缩时,需注意两个问题:
1.
Filter在进行Gzip压缩时,采用系统默认编码,对于使用GBK编码的中文网页来说,需要将操作系统的语言设置
为:zh_CN.GBK,否则会出现乱码的问题。
2.
默认情况下CachingFilter会根据浏览器发送的请求头部所包含的Accept-Encoding参数值来判断是否进行Gzip压
缩。虽然IE6/7浏览器是支持Gzip压缩的,但是在发送请求的时候却不带该参数。为了对IE6/7也能进行Gzip压缩,可以通过继承
CachingFilter,实现自己的Filter,然后在具体的实现中覆写方法acceptsGzipEncoding。
具体实现参考:
protected boolean acceptsGzipEncoding(HttpServletRequest
request) {
final
boolean ie6 = headerContains(request, "User-Agent", "MSIE
6.0");
final
boolean ie7 = headerContains(request, "User-Agent", "MSIE
7.0");
return
acceptsEncoding(request, "gzip") || ie6 || ie7;
}
EHCache在Hibernate中的使用
EHCache可以作为Hibernate的二级缓存使用。在hibernate.cfg.xml中需增加如下设置:
<prop
key="hibernate.cache.provider_class">
org.hibernate.cache.EhCacheProvider
</prop>
然后在Hibernate映射文件的每个需要Cache的Domain中,加入类似如下格式信息:
<cache
usage="read-write|nonstrict-read-write|read-only"
/>
比如:
<cache usage="read-write"
/>
最后在配置文件ehcache.xml中增加一段cache的配置,其中name为该domain的类名。
<cache name="domain.class.name"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="300"
timeToLiveSeconds="600"
overflowToDisk="false"
/>
EHCache的监控
对于Cache的使用,除了功能,在实际的系统运营过程中,我们会比较关注每个Cache对象占用的内存大小和Cache的命中率。有了这些
数据,我们就可以对Cache的配置参数和系统的配置参数进行优化,使系统的性能达到最优。EHCache提供了方便的API供我们调用以获取监控数据,
其中主要的方法有:
//得到缓存中的对象数
cache.getSize();
//得到缓存对象占用内存的大小
cache.getMemoryStoreSize();
//得到缓存读取的命中次数
cache.getStatistics().getCacheHits()
//得到缓存读取的错失次数
cache.getStatistics().getCacheMisses()
分布式缓存
EHCache从1.2版本开始支持分布式缓存。分布式缓存主要解决集群环境中不同的服务器间的数据的同步问题。具体的配置如下:
在配置文件ehcache.xml中加入
<cacheManagerPeerProviderFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerProviderFactory"
properties="peerDiscovery=automatic,
multicastGroupAddress=230.0.0.1,
multicastGroupPort=4446"/>
<cacheManagerPeerListenerFactory
class="net.sf.ehcache.distribution.RMICacheManagerPeerListenerFactory"/>
另外,需要在每个cache属性中加入
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
例如:
<cache name="demoCache"
maxElementsInMemory="10000"
eternal="true"
overflowToDisk="true">
<cacheEventListenerFactory
class="net.sf.ehcache.distribution.RMICacheReplicatorFactory"/>
</cache>
总结
EHCache是一个非常优秀的基于Java的Cache实现。它简单、易用,而且功能齐全,并且非常容易与Spring、
Hibernate等流行的开源框架进行整合。通过使用EHCache可以减少网站项目中数据库服务器的访问压力,提高网站的访问速度,改善用户的体验。
分享到:
相关推荐
为了提高MyBatis的性能,有时候我们需要加入缓存支持,目前用的比较多的缓存莫过于ehcache缓存了,ehcache性能强大,而且位各种应用都提供了解决方案,在此我们主要是做查询缓存,提高查询的效率.
Ehcache 是一种基于标准的开源缓存,可提高性能,卸载数据库并简化可伸缩性
缓存可以提高查询数据性能, 对同一批数据进行多次查询时, 第一次查询走数据库, 查询数据后,将数据保存在内存中,第二次以后查询 可以直接从内存获取数据,而不需要 和数据库进行交互。
本人在做项目时用到了Hibernate的二级缓存,使用的是EhCache,结合本人自己的理解总结了如何在java web项目中配合Hibernate使用二级缓存,以提高程序的性能,附带需要的文件,参考的文件,和测试类以及说明。
提高性能)、Lucene 4.10.4和Quartz 2.2.1(定时生成索引)、JUnit 4.12(单元测试)、Google Guava Collections 18.0(性能更好的集合工具类库)、Log4j(记录日志)等等。 前端主要技术: Bootstrap 3.3.4、HTML5、jQuery ...
EhCache 的优点是可以减少数据库查询次数,提高系统性能。 EhCache 的缺点是需要正确配置和实现,否则可能会导致缓存问题。 EhCache 是一种流行的 Java 缓存工具,可以用于各种 Java 应用程序中,以提高系统性能和...
无论您是想学习新的技能,还是想提高现有应用程序的性能,这个项目都将是您的宝贵资源。 内容概览 项目设置和初始化 控制器设计和实现 数据持久化与数据库集成 安全性和身份验证 性能优化和监控 部署和生产环境...
缓存系统可以减少数据库的访问次数,提高系统的响应速度和性能。今天,我们将探索五款最好的免费Linux缓存系统,这些系统都具有高性能、可扩展性和灵活性等特点。 1. Memcached:Memcached是一个分布式的高速缓存...
为了提高论坛性能,技术选型 Spring 5.0 + SpringMVC + JPA + Ehcache(可选Memcached) + Lucene 使用平台: JDK 1.8及以上 + Tomcat 8.0及以上 + MySQL 5.5.3及以上 源码运行教程: 1.将源代码导入到Eclipse中...
为了提高论坛性能,技术选型 Spring 5.0 + SpringMVC + JPA + Ehcache(可选Memcached) + Lucene 使用平台: JDK 1.8及以上 + Tomcat 8.0及以上 + MySQL 5.5.3及以上 源码运行教程: 1.将源代码导入到Eclipse中...
为了提高论坛性能,部分功能使用数据库分表设计,默认分为4个表,表中有数据后不建议再调整分表数量。程序带有图形安装界面,第一次使用需执行安装操作。前台所有页面均支持返回HTML和JSON格式数据,API接口文档可在...
Java高并发高性能分布式框架从...高并发- 多级缓存(分布式缓存)高并发- 池化在应用系统开发过程中,我们经常会用到池化技术,如对象池、连接池、线程池等 ,通过池化来减少一些消耗,以提升性能。 对象池通过复用对象
+ Ehcache 2.9.0(作为二级缓存,提高性能) + Lucene 4.10.4(全文检索引擎工具包) + Quartz 2.2.1(定时生成索引) + JUnit 4.12(单元测试) + Google Guava Collections 18.0(性能更好的集合工具类库) + Log4j(记录日志...
Hibernate中使用了一级缓存和二级缓存的机制来提高程序的性能. 一 为什么要使用缓存? 缓存是一块存储区域,可能是一块内存,也可能是一块硬盘.缓存能起到缓冲的作用,把程序经常使用...
JAVA SSF项目框架源码 后台管理系统源码 注意:不带技术支持,有帮助文件,虚拟商品,发货不退,看好再拍。...Ehcache (作为二级缓存,提高性能)、Lucene 和Quartz (定时生成索引)、Log4j(记录日志)等等。
对于Java开发者来说,有很多常用的缓存解决方案,例如EhCache和Memcached等。这些解决方案的核心目标是提高系统吞吐量,减轻数据库等持久层的压力。 根据其部署和应用范围,缓存可以分为本地缓存和分布式缓存两种...
缓存是提高系统性能的重要手段之一。实现缓存依赖就是要在被依赖对象与缓存对象之间建立一个有效关联,使数据得到合理的刷新。通过对EhCache、Map、Annotation以及AOP等相关技术的研究,提出了SSH架构中方法级依赖缓存...
Spring @Cacheable 非常有用,可以提高性能但不能防止底层服务中的异常。 如果您只是将它放在缓存中并且服务抛出异常,那么很自然地返回缓存的最后状态......或者可能不会。 我们运行的服务经常需要读取一些文本...
1、采用Spring MVC的静态加载缓存功能,在首页将Javascript文件、CSS文件和图片等静态资源文件加载进来放进内存,极大提高ExtJS的加载速度。 2、三种皮肤主题:经典、灰色和海王星,支持多浏览器和多分辨率。 3、...
1、采用Spring MVC的静态加载缓存功能,在首页将Javascript文件、CSS文件和图片等静态资源文件加载进来放进内存,极大提高ExtJS的加载速度。 2、三种皮肤主题:经典、灰色和海王星,支持多浏览器和多分辨率。 3、...