標籤:緩衝 cache jsp 緩衝機制
Oscache
特點
緩衝任何對象,你可以不受限制的緩衝部分jsp頁面或HTTP請求,任何java對象都可以緩衝。
擁有全面的API--OSCache API給你全面的程式來控制所有的OSCache特性。
永久緩衝--緩衝能隨意的寫入硬碟,因此允許昂貴的建立(expensive-to-create)資料來保持緩衝,甚至能讓應用重啟。
支援叢集--叢集快取資料能被單個的進行參數配置,不需要修改代碼。
緩衝記錄的到期--你可以有最大限度的控制緩衝對象的到期,包括可插入式的重新整理策略(如果預設效能不需要時)。
上一篇講到如何配置oschche下面介紹如何應用:
1 建立一個**Bean的緩衝類**Cache.
2 import com.opensymphony.oscache.general.*;import com.opensymphony.oscache.base.*;
3 建立一個**DAO類以便操作資料庫(也可將上兩項的內容直接合并到這裡).
4 在**Cache類裡產生一個GeneralCacheAdministrator的執行個體admin用來管理緩衝.
GeneralCacheAdministrator admin = new GeneralCacheAdministrator();
5 **Cache中的方法 如.clear(),flush().基本調用的為OSCache的 Java API.
6 在**Cache添加getBeans()和getBean()方法 以便擷取緩衝中的執行個體對象.具體實現可參照上面的例子.
7 主要用到的GeneralCacheAdministrator的方法有
public Object getFromCache(String key) throws NeedsRefreshException; -- 從緩衝中擷取一個key標識的對象.
public Object getFromCache(String key, int refreshPeriod) throws NeedsRefreshException ; -- 從緩衝中擷取一個key標識的對象. refreshPeriod重新整理周期,標識此對象在緩衝中儲存的時間(單位:秒)
注意:
如果一個NeedsRefreshException出現 必須調用admin.putInCache或admin.cancelUpdate來避免死結情況發生.
OSCache的使用主要有4種:
1.POJO 緩衝
2.HTTP Response 緩衝
3.JSP Tag Library 緩衝
4.O/R Data Access 緩衝
1、POJO 緩衝
這種方式的緩衝直接調用OSCache的API進行,主要用於處理頁面內容會根據參數動態改變,可以將參數設定為key值來儲存資料:
首先,聲明成員變數:
// OSCache Adminitrator instance
private static GeneralCacheAdministrator cacheAdmin = null;
其次,進行初始化:
public RingArtistAction() {
cacheAdmin = new GeneralCacheAdministrator();
}
將POJO進行緩衝:
// Cache data key and refresh period
String key = sex + ":" + place;
int refreshPeriod = Constants.getIntegerValue(Constants.OSCACHE_REFRESH_PERIOD).intValue();
try {
// Get from the cache
artists = (Map) cacheAdmin.getFromCache(key, refreshPeriod);
} catch (NeedsRefreshException nre) {
try {
// Get the value (probably from the database)
int count = getArtistCount(sex, place, errors);
artists = getArtistData(sex, place, count, errors);
// Store in the cache
cacheAdmin.putInCache(key, artists);
} catch (Exception ex) {
// We have the current content if we want fail-over.
artists = (Map) nre.getCacheContent();
// It is essential that cancelUpdate is called if the
// cached content is not rebuilt
cacheAdmin.cancelUpdate(key);
ex.printStackTrace();
}
}
POJO(簡單Java對象)緩衝。一個POJO緩衝是一個系統——它擔當一個"物件導向的"分布式的緩衝。在這個系統中,一旦一個使用者把POJO依附到該緩衝上,那麼緩衝方面(例如複製和持久性)應該對使用者是透明的。一個使用者只需簡單地在該POJO上操作而不須擔心更新該緩衝內容或維持對象關係的問題。不存在顯式的API調用可用來管理該緩衝。
2、HTTP Response 緩衝
這種方式的緩衝用來處理整個頁面的內容固定,不會根據參數動態改變:
首先在web.xml中配置CacheFilter:
<filter>
<filter-name>CacheFilter</filter-name>
<filter-class>com.opensymphony.oscache.web.filter.CacheFilter</filter-class>
<init-param>
<param-name>time</param-name>
<param-value>86400</param-value>
</init-param>
<init-param>
<param-name>scope</param-name>
<param-value>application</param-value>
</init-param>
</filter>
將所有需要緩衝的頁面加入filter-mapping:
<filter-mapping>
<filter-name>Set Character Encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
注意,只有返回狀態為200(HttpServletResponse.SC_OK)的內容才會被緩衝
HTTP中緩衝的目的是為了在很多情況下減少發送請求,也即直接返回緩衝;同時在許多情況下可以不需要發送完整響應。前者減少了網路迴路的數量,挺高響應速度,HTTP利用一個“到期(expiration)”機制來為此目的。後者減少了網路應用的頻寬,HTTP用“驗證(validation)”機制來為此目的。
HTTP定義了3種緩衝機制:
l Freshness allows a response to be used without re-checking it on the origin server, and can be controlled by both the server and the client. For example, the Expires response header gives a date when the document becomes stale, and the Cache-Control: max-age directive tells the cache how many seconds the response is fresh for.
l Validation can be used to check whether a cached response is still good after it becomes stale. For example, if the response has a Last-Modified header, a cache can make a conditional request using the If-Modified-Since header to see if it has changed.
l Invalidation is usually a side effect of another request that passes through the cache. For example, if URL associated with a cached response subsequently gets a POST, PUT or DELETE request, the cached response will be invalidated.
HTTP Response緩衝如何工作
所有的緩衝都用一套規則來協助他們決定什麼時候使用緩衝中的副本提供服務(假設有副本可用的情況下);一些規則在協議中有定義(HTTP協議1.0和1.1),一些規則由緩衝的管理員設定(瀏覽器的使用者或者Proxy 伺服器的管理員);
一般說來:遵循以下基本的規則(不必擔心,你不必知道所有的細節,細節將隨後說明)
1.如果回應標頭資訊:告訴緩衝器不要保留緩衝,緩衝器就不會緩衝相應內容;
2.如果請求資訊是需要認證或者安全加密的,相應內容也不會被緩衝;
3.如果在回應中不存在校正器(ETag或者Last-Modified頭資訊),快取服務器會認為缺乏直接的更新度資訊,內容將會被認為不可緩衝。
4.一個緩衝的副本如果含有以下資訊:內容將會被認為是足夠新的 ?含有完整的到期時間和壽命控制頭資訊,並且內容仍在保鮮期內;
?瀏覽器已經使用過快取複本,並且在一個會話中已經檢查過內容的新鮮度;
?緩衝Proxy 伺服器近期內已經使用過快取複本,並且內容的最後更新時間在上次使用期之前;
?夠新的副本將直接從緩衝中送出,而不會向原始伺服器發送請求;
5.如果緩衝的副本已經太舊了,快取服務器將向原始伺服器發出請求校正請求,用於確定是否可以繼續使用當前拷貝繼續服務;
總之:新鮮度和校正是確定內容是否可用的最重要途徑:
如果副本足夠新,從緩衝中提取就立刻能用了;
而經緩衝器校正後發現副本的原件沒有變化,系統也會避免將副本內容從原始伺服器整個重新傳輸一遍。
3、JSP Tag 緩衝
JSP Tag緩衝主要用於緩衝JSP頁面的局部內容:
<cache:cache key="especialcategory" cron="* 5 * * *">
<jsp:include page="/ringcategory.do" flush="true" >
<jsp:param name="ringType" value="1"/>
</jsp:include>
</cache:cache>
頁面緩衝通常採用oscache來進行實現,oscache提供了一個jsp tag,可通過這個tag來包含需要緩衝的內容部分,當然,緩衝的這個內容部分需要有對伺服器的請求或邏輯計算等的,可想而知,去緩衝一段靜態html是沒有意義的。頁面的緩衝的使用對於系統的響應速度確實會有很大的提升,在實現頁面緩衝時最麻煩的主要是緩衝的key的定義以及緩衝更新的通知,這個自然架構是沒法解決的,不過緩衝更新的通知其實在架構中可以考慮一種通知模型的,就像事件通知那樣。在實際的項目中,可以實現一個這樣的通知模型或者就是簡單的採用單例方式來標識某個key是否需要更新。
關於jsp cache的幾條建議
1.jsp cache最好做在過濾器上,把需要緩衝的頁面集中在同一個目錄下,每次更改只須更改web.xml就可以完成緩衝設定,這樣比較方便.
2.Gzip壓縮可以將頁面壓縮得很小,平均壓縮比為1/3,jsp cache的HashMap緩衝壓縮後的頁面,肯定比沒壓縮前更節約記憶體消耗,並且效率更高.
4、O/R Data Access 緩衝
資料緩衝估計大家都很熟悉,就是對系統的資料進行緩衝的方式,典型的就是Hibernate的一級、二級資料緩衝。
資料緩衝在實現上如果是用hibernate的話更多的是直接使用hibernate的一級、二級以及查詢快取,如果要實現的話可以去參考hibernate的實現機制。
資料緩衝的key在一級、二級緩衝中採用的都是資料的標識鍵的值的方式,查詢快取採用的是查詢參數、查詢語句的方式。
資料緩衝的更新則是hibernate在進行儲存時直接更新緩衝的內容,而對於查詢快取則是採用全部直接清除的方式,這樣在下次進行查詢時自然會重新去查詢,
大家可能會想,為什麼頁面緩衝和處理緩衝不採用這樣的方式來實現緩衝的更新,稍微想想就知道了,在後台發生改變的時候其實是不知道需要移除哪些key的,
所以hibernate為了避免這個麻煩,採用的就是當資料一旦發生改變的時候就清除全部的查詢快取,而不是只去清除相關的緩衝,
其實這裡可以採用一種訂閱式的模型,當然,也增加了架構的複雜度。
ORM緩衝最強大的是它的透明化和靈活可配置,你可以使用Ehcache, 也可以選Jboss,還可以用Tangosol。
請閱讀參考資料的內容擷取詳情。
參考資料:
Taking the load off: OSCache helps databases cope:http://www.theserverside.com/articles/article.tss?l=OSCacheHelpsDatabases
具體實現:
建立緩衝管理類CacheManager
package com.jrgy.util;
public class CacheManager {
private BaseCache newsCache;
private static CacheManager instance;
private static Object lock = new Object();
private CacheManager() {
// 初始BaseCache;
newsCache = new BaseCache("CNYJWeb", 12000);
}
public static CacheManager getInstance() {
if (instance == null) {
synchronized (lock) {
if (instance == null) {
instance = new CacheManager();
}
}
}
return instance;
}
//刪除?所有緩衝對象
public void removeAllCache() {
newsCache.removeAll();
}
//刪除被緩衝的對象
public void delCacheByKey(String key){
newsCache.remove(key);
}
//添加被緩衝的對象
public void add(String key, Object value) {
newsCache.put(key, value);
}
// 擷取被緩衝的對象
public Object get(String key){
try {
return newsCache.get(key);
} catch (Exception e) {
return null;
}
}
}
建立個工具類BaseController GeneralCacheAdministrator主要對實現持久化對象的儲存以及取出的相關的操作。
package com.jrgy.util;
import java.util.Date;
import com.opensymphony.oscache.base.NeedsRefreshException;
import com.opensymphony.oscache.general.GeneralCacheAdministrator;
public class BaseCache extends GeneralCacheAdministrator {
private static final long serialVersionUID = -4397192926052141162L;
private int refreshPeriod; // 到期時間(單位為秒);
private String keyPrefix; // 關鍵字前??字元;
public BaseCache(String keyPrefix, int refreshPeriod) {
super();
this.keyPrefix = keyPrefix;
this.refreshPeriod = refreshPeriod;
}
// 添加被緩衝的對象;
public void put(String key, Object value) {
this.putInCache(this.keyPrefix + "_" + key, value);
}
// 刪除被緩衝的對象;
public void remove(String key) {
this.flushEntry(this.keyPrefix + "_" + key);
}
// 根據日期刪除?被緩衝的對對象;
public void removeAll(Date date) {
this.flushAll(date);
}
//刪除?所有的緩衝對象?;
public void removeAll() {
this.flushAll();
}
// 擷取被緩衝的對象;
public Object get(String key) throws Exception {
try {
return this.getFromCache(this.keyPrefix + "_" + key,
this.refreshPeriod);
} catch (NeedsRefreshException e) {
this.cancelUpdate(this.keyPrefix + "_" + key);
throw e;
}
}
}
使用oschache
package com.jrgy.web.controller;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import net.sf.json.JSONArray;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.jrgy.main.service.impl.LoadStartDataManagerImpl;
import com.jrgy.pojo.domain.DocInfo;
import com.jrgy.pojo.domain.FriendlyLink;
import com.jrgy.pojo.domain.ItemInfo;
import com.jrgy.pojo.domain.Periodical;
import com.jrgy.util.Constants;
import com.jrgy.util.ItemCodeConstants;
import com.jrgy.util.PageObject;
import com.jrgy.util.PageView;
import com.jrgy.web.service.IWebIndexManager;
@Controller
public class WebIndexController extends BaseController {
private static final long serialVersionUID = 6316819588600885728L;
@Autowired
IWebIndexManager webIndexManager;
@Autowired
LoadStartDataManagerImpl loadStartData;
@SuppressWarnings("unchecked")
@RequestMapping("/index.do")
public ModelAndView saveDept(HttpServletRequest request,
HttpServletResponse response) {
PageObject pageObject = new PageObject();
List<ItemInfo> itemList = new ArrayList<ItemInfo>();// 擷取欄目
if ((itemList = (List<ItemInfo>) getCache(itemList, ItemCodeConstants.CACHE_JRGY_ITEM)).size() == 0) {
itemList = webIndexManager.addItemList(itmeCode);
addCache(ItemCodeConstants.CACHE_JRGY_ITEM, itemList);
}
}
}
因為配置在D:\CNYJWeb\cache\application產生緩衝的檔案夾:
結論:
1.緩衝的清空與更新,要盡量精確的去操作受到更新影響的對象,而不是全部搞掉。
在Hibernate當中,也提供了sessionFactory.evict(class, id)這樣細粒度的清空緩衝對象的方法。
sessionFactory.evice(class)的操作,要看這樣的操作是否頻繁,如果頻繁,對於緩衝的作用就會大大的折扣。
2.如果緩衝對象過多,對於失效的演算法與處理,要與業務對象的特性緊密的聯合起來,通過事件來驅動對象的失效。
3.對於商業對象的緩衝,必須要深刻分析對象的生命週期,業務特性。
4.對於資料不一致的風險,要有足夠的認識與預防手段。
5.合理的估計對象的大小,分配足夠的記憶體
6.如果只使用中心緩衝,只能減小資料庫的壓力,對於網路頻寬的壓力,還是有的,速度上也遠遠遜於本機快取的效果,所以要結合本機快取+中心緩衝的策略方案,即提高速度,避免群集複製時的瓶頸。