1. 程式人生 > >使用ehcache快取頁面、ExpiresFilter新增Expires頭,大幅提升網站效能

使用ehcache快取頁面、ExpiresFilter新增Expires頭,大幅提升網站效能

前幾天把網站部署到伺服器上後發現訪問速度和龜速差不多,內心感到非常焦慮——之前並未做過這方面的嘗試,要解決問題實在有些頭大。

但幸好之前做過一個專案,本地訪問速度感覺奇慢,但正式環境下訪問速度反倒快得飛起。雖然我期初並不知曉原因,但這畢竟是解決問題的線索。

追本溯源的找,情況倒也不難辦。

  1. ehcache
  2. 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>
  1. 名字必須為SimplePageCachingFilter;
  2. maxEntriesLocalHeap=”1000” : 堆記憶體中最大快取物件數,0沒有限制(必須設定);
  3. eternal=”false” : 物件是否永久有效,一但設定了,timeout將不起作用。 (必須設定)
  4. overflowToDisk=”false” : 當快取達到maxElementsInMemory值時,是否允許溢位到磁碟(必須設定)(記憶體不足時,是否啟用磁碟快取。)
  5. timeToIdleSeconds=”120” : 導致元素過期的訪問間隔(秒為單位),即當快取閒置n秒後銷燬。 當eternal為false時,這個屬性才有效,0表示可以永遠空閒,預設為0
  6. timeToLiveSeconds=”120” : 元素在快取裡存在的時間(秒為單位),即當快取存活n秒後銷燬. 0 表示永遠存在不過期
  7. 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檔案已經被快取起來了。