前几天把网站部署到服务器上后发现访问速度和龟速差不多,内心感到非常焦虑——之前并未做过这方面的尝试,要解决问题实在有些头大。
但幸好之前做过一个项目,本地访问速度感觉奇慢,但正式环境下访问速度反倒快得飞起。虽然我期初并不知晓原因,但这毕竟是解决问题的线索。
追本溯源的找,情况倒也不难办。
ehcache
org.apache.catalina.filters.ExpiresFilter
ehcache是我找到的一个关键信息。虽然之前我们素未谋面,但cache的中文意思是缓存,这一点英语能力我还是有的。另外,我之前写过一篇文章《为组件添加Expires头,最大化利用浏览器缓存》,虽然文章现在看来很糟糕,但至少提供了信息给我——org.apache.catalina.filters.ExpiresFilter。
利用这两点,至少暂时解决了问题,尽管ehcache我很不熟,就算是看了很多文档和博客,依然懵懵懂懂。但本着解决问题的原则,我发现我至少会用它们俩。
首先来说ehcache。
EhCache 是一个纯Java的进程内缓存框架,具有快速、精干等特点,是Hibernate中默认CacheProvider。Ehcache是一种广泛使用的开源Java分布式缓存。主要面向通用缓存,Java EE和轻量级容器。它具有内存和磁盘存储,缓存加载器,缓存扩展,缓存异常处理程序,一个gzip缓存servlet过滤器,支持REST和SOAP api等特点。
经过大量的调查和尝试后,找到了——SimplePageCachingFilter:
它是ehcache-web模块下页面缓存Filter的一个简单实现,适用于可以压缩的Http响应(response),如HTML、XML、JSON等。
页面缓存主要用Filter过滤器对请求的url进行过滤,如果该url在缓存中出现。那么页面数据就从缓存对象中获取,并以gzip压缩后返回。其速度是没有压缩缓存时速度的3-5倍,效率相当之高!其中页面缓存的过滤器有CachingFilter,一般要扩展filter或是自定义Filter都继承该CachingFilter。
第一步,在pom.xml文件中添加ehcache的依赖:
<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache-core --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.6.11</version> </dependency> <!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache-web --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-web</artifactId> <version>2.0.4</version> </dependency>
第二步,在classpath下新建ehcache.xml:
<?xml version="1.0" encoding="UTF-8"?> <ehcache> <cache name="SimplePageCachingFilter" maxEntriesLocalHeap="1000" eternal="false" overflowToDisk="true" timeToIdleSeconds="120" timeToLiveSeconds="120" memoryStoreEvictionPolicy="LFU" /> </ehcache>
名字必须为SimplePageCachingFilter;
maxEntriesLocalHeap=”1000” : 堆内存中最大缓存对象数,0没有限制(必须设置);
eternal=”false” : 对象是否永久有效,一但设置了,timeout将不起作用。 (必须设置)
overflowToDisk=”false” : 当缓存达到maxElementsInMemory值时,是否允许溢出到磁盘(必须设置)(内存不足时,是否启用磁盘缓存。)
timeToIdleSeconds=”120” : 导致元素过期的访问间隔(秒为单位),即当缓存闲置n秒后销毁。 当eternal为false时,这个属性才有效,0表示可以永远空闲,默认为0
timeToLiveSeconds=”120” : 元素在缓存里存在的时间(秒为单位),即当缓存存活n秒后销毁. 0 表示永远存在不过期
memoryStoreEvictionPolicy=”LFU” : 当达到maxElementsInMemory时,如何强制进行驱逐,默认使用”最近使用(LRU)”策略,其它还有先入先出FIFO,最少使用LFU,较少使用LRU
第三步,在web.xml中配置ehcache 页面缓存过滤器:
<!--ehcache 页面缓存过滤器 --> <filter> <filter-name>PageCachingFilter</filter-name> <filter-class>net.sf.ehcache.constructs.web.filter.SimplePageCachingFilter</filter-class> </filter> <filter-mapping> <filter-name>PageCachingFilter</filter-name> <url-pattern>/mec/good</url-pattern> </filter-mapping>
这里我只添加了访问比较频繁的首页路径。
完成之后,启动tomcat,发现如下日志:
DEBUG 2018-05-08 10:37:02,920 net.sf.ehcache.constructs.web.filter.Filter: Request Headers: host -> localhost:8880: connection -> keep-alive: cache-control -> max-age=0: upgrade-insecure-requests -> 1: user-agent -> Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36: accept -> text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8: referer -> http://localhost:8880/zmeng/initLogin?backToUrl=http%3A%2F%2Flocalhost%3A8880%2Fzmeng%2Fmec%2Fgood: accept-encoding -> gzip, deflate, br: accept-language -> zh-CN,zh;q=0.9: cookie -> JSESSIONID=6BFDADE7284DF880D35D4866632C3FAE; Hm_lvt_82116c626a8d504a5c0675073362ef6f=1521712436,1524018865,1524206145; COOKIE_MEMBER_HEADIMAGE="http://wx.qlogo.cn/mmopen/oiazmgRzbajknOWTxtDgxibicdQcnhicNbNRiap0gOTyPWWDKwibTtlaUHDm22ibWiaAJ7ibVsjjFQibZ6j3Mcwic2g5qicUyMsC2YVFjhFM/0"; COOKIE_MEMBER=3l+5WJRuO2mF/7lj0JsJ0FSTYJEg5xaV
DEBUG 2018-05-08 10:37:02,920 net.sf.ehcache.constructs.web.filter.CachingFilter: Thread http-bio-8880-exec-13 has been marked as visited.
DEBUG 2018-05-08 10:37:02,921 net.sf.ehcache.constructs.web.filter.Filter: Request Headers: host -> localhost:8880: connection -> keep-alive: cache-control -> max-age=0: upgrade-insecure-requests -> 1: user-agent -> Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36: accept -> text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8: referer -> http://localhost:8880/zmeng/initLogin?backToUrl=http%3A%2F%2Flocalhost%3A8880%2Fzmeng%2Fmec%2Fgood: accept-encoding -> gzip, deflate, br: accept-language -> zh-CN,zh;q=0.9: cookie -> JSESSIONID=6BFDADE7284DF880D35D4866632C3FAE; Hm_lvt_82116c626a8d504a5c0675073362ef6f=1521712436,1524018865,1524206145; COOKIE_MEMBER_HEADIMAGE="http://wx.qlogo.cn/mmopen/oiazmgRzbajknOWTxtDgxibicdQcnhicNbNRiap0gOTyPWWDKwibTtlaUHDm22ibWiaAJ7ibVsjjFQibZ6j3Mcwic2g5qicUyMsC2YVFjhFM/0"; COOKIE_MEMBER=3l+5WJRuO2mF/7lj0JsJ0FSTYJEg5xaV
DEBUG 2018-05-08 10:37:02,921 net.sf.ehcache.constructs.web.filter.Filter: Request Headers: host -> localhost:8880: connection -> keep-alive: cache-control -> max-age=0: upgrade-insecure-requests -> 1: user-agent -> Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Mobile Safari/537.36: accept -> text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8: referer -> http://localhost:8880/zmeng/initLogin?backToUrl=http%3A%2F%2Flocalhost%3A8880%2Fzmeng%2Fmec%2Fgood: accept-encoding -> gzip, deflate, br: accept-language -> zh-CN,zh;q=0.9: cookie -> JSESSIONID=6BFDADE7284DF880D35D4866632C3FAE; Hm_lvt_82116c626a8d504a5c0675073362ef6f=1521712436,1524018865,1524206145; COOKIE_MEMBER_HEADIMAGE="http://wx.qlogo.cn/mmopen/oiazmgRzbajknOWTxtDgxibicdQcnhicNbNRiap0gOTyPWWDKwibTtlaUHDm22ibWiaAJ7ibVsjjFQibZ6j3Mcwic2g5qicUyMsC2YVFjhFM/0"; COOKIE_MEMBER=3l+5WJRuO2mF/7lj0JsJ0FSTYJEg5xaV
并且在120s之内页面上的时间并未发生改变:
120s之后再去访问的时候就发现时间已经发生了变化,并且页面被重新缓存。
尽管对ehcache非常皮毛,但总算是hello world了一次。以后我会再做新的研究并且把心得整理出来。
再来说ExpiresFilter。
ExpiresFilter是Java servlet API 当中的一部分,它负责控制设置response当中的响应头(Expires) 和 ( Cache-Control的max-age),过期时间可以设置为相对于源文件的最后修改时间,或者浏览器的访问时间。
这些响应头指示浏览器控制文档的缓存,如果使用了缓存,那么浏览器在下一次获取文档(HTML)的时候就会从本地缓存中获取,而不是访问实际的资源服务器,除非超过失效时间。关于HTTP头控制客户端缓存的更多介绍请参见我的另外一篇文章,http://www.cnblogs.com/daxin/p/3981553.html或者可以直接查阅HTTP协议(see RFC 2616 section 14.9)。
使用ExpiresFilter就简单得多了,虽然SimplePageCachingFilter也不麻烦。
在web.xml文件中添加ExpiresFilter,内容如下:
<filter> <filter-name>ExpiresFilter</filter-name> <filter-class>org.apache.catalina.filters.ExpiresFilter</filter-class> <init-param> <param-name>ExpiresByType image</param-name> <param-value>access plus 10 days</param-value> </init-param> <init-param> <param-name>ExpiresByType text/css</param-name> <param-value>access plus 10 days</param-value> </init-param> <init-param> <param-name>ExpiresByType application/javascript</param-name> <param-value>access plus 10 days</param-value> </init-param> </filter> <filter-mapping> <filter-name>ExpiresFilter</filter-name> <url-pattern>/*</url-pattern> <dispatcher>REQUEST</dispatcher> </filter-mapping>
其作用就是对image、css、JavaScript添加Expires头。
完成之后就可以看到css文件已经被缓存起来了。