Sapphire是一個高併發、高緩存吞吐性、高性能的Java分佈式內存對象緩存系統,其具備簡單易學、方便實用等特色。它可以用來存儲各類格式的數據,包括圖像、視頻、文件以及數據庫檢索的結果等。簡單的說就是將數據源中的數據臨時存儲於內存中,而後從內存中讀取,從而大大提升讀取速度。java
Sapphire目前最新版本爲1.1.7-beta,主要特性包含: 數據庫
1.敏捷快速;數組
2.體系結構中立、跨平臺支持; 緩存
3.多種緩存管理容器實現; 安全
4.多種緩存策略(LRU、LUF、RDM); 服務器
5.支持緩存註解服務驅動(Annotation方式直接緩存方法); 網絡
6.支持緩存持久化及加載虛擬機運行期數據; 架構
7.單個緩存最大緩存容量爲1gByte; 併發
8.支持緩存容量單位設置(byte、kByte、mByte、gByte) app
9.支持TCP單播集羣、P2P多播、組播集羣、RMI多播集羣;
Cache提供的經常使用方法以下:
put(Object key, Object value):Object 添加緩存數據
get(Object key):Object 獲取緩存數據
remove(Object key):Object 清除指定緩存數據
clear():void 清除全部緩存數據
getElementsInSize():long 獲取當前緩存已用元素數量
getSurplusElementsInSize(): long 獲取當前緩存剩餘元素數量
getMaxElementsInSize(): long 獲取當前緩存最大元素數量
getCacheInMemory(): long 獲取當前緩存已用緩存容量
getMaxCacheInMemory(): long 獲取當前緩存最大緩存容量
getSurplusCacheInMemory():long 獲取當前緩存剩餘緩存容量
cacheUseRecords(Object key): void 計算緩存使用記錄
getCacheUseRecords():HashMap 獲取緩存使用記錄
getMaxCacheInMemoryForByte(long maxCacheInMemory,
String capacityUnit): long 計算當前緩存的最大字節緩存容量
5.使用Sapphire緩存缺省數據類型
缺省狀況下Sapphire能夠爲您緩存的數據類型爲以下3類:
基本數據類型;
數組類型;
String類型;
使用Sapphire緩存缺省數據類型實現:
/* 緩存基本數據類型 */
cache.put("byte", 1);
cache.put("short", 10);
cache.put("int", 100);
cache.put("long", 1000L);
cache.put("float", 1.5);
cache.put("double", 10.5D);
cache.put("char", 'A');
cache.put("boolean", true);
/* 緩存數組數據類型 */
cache.put("byte[]", new byte[100]);
/* 緩存String數據類型 */
cache.put("String", "Sapphire Cache");
6.使用Sapphire緩存複合數據類型
缺省狀況下Sapphire並無提供對複合數據類型的支持,但您能夠將您須要緩存的複合對象實現Sapphire爲您提供的CacheSerializable接口(該接口爲標記接口,無需任何實現)。一旦您的複合對象實現了該接口,Sapphire便會容許緩存您所指定的複合對象,除了能夠實現CacheSerializable接口,Sapphire仍然容許您實現JDK原生的Serializable接口。
至於複合數據類型爲何須要實現CacheSerializable接口或者實現Serializable接口Sapphire才容許將其緩存呢?其實Sapphire在對您的數據進行緩存以前須要將全部數據進行序列化處理,以便計算當前所需緩存的數據所佔緩存容量的內存大小。
使用Sapphire緩存複合數據類型實現:
class SaveObject implements CacheSerializable
{
//...
}
/* 初始化Sapphire容器方式 */
CacheManager cacheManager = new SapphireCacheManager();
/* 獲取緩存實例 */
Cache cache = cacheManager.getCache("defaultCache");
/* 緩存複合數據類型 */
cache.put("object", new SaveObject());
System.out.println(cache.get("object") instanceof CacheSerializable);
注意:
若是您在使用Sapphire爲您緩存複合對象時並無將所需緩存的數據實現CacheSerializable接口或者Serializable接口,Sapphire將會拋出java.io.NotSerializableException異常信息。
7.啓動緩存註解服務驅動
經過Sapphire的配置文件咱們能夠觀察到<service:annotation-driven>標籤。該標籤主要用做於開啓緩存註解服務驅動,其中包含有一個auto屬性,該屬性所容許的參數範圍爲「true」與「false」。若是您將auto屬性設置爲「true」,則意味着您將成功開啓Sapphire的緩存註解服務驅動服務,不然意味着該服務的狀態爲關閉狀態。
至於開啓Sapphire的緩存註解服務驅動有何用處,想必這是您最爲關心的問題。其實不難發如今不少複雜應用的狀況下,咱們常常須要緩存具體的方法返回結果(好比服務層與持久層),面對這種狀況雖然咱們可使用Cache對象的put方法進行數據緩存,但這並不靈活。因此Sapphire將爲您提供了一個基於註解方式的方法返回值緩存技術,這即是剛纔咱們所提到的緩存註解服務。
位於org.sapphire.cache.annotation包下的@CacheService類型正是咱們即將使用到的方法返回值緩存技術的實現。
緩存註解服務驅動實例:
此處省略導包過程…
public class SapphireCacheTest extends TestCase
{
/**
* @param args
*/
public static void main(String[] args) throws Exception
{
/* 初始化Sapphire容器方式 */
CacheManager cacheManager = new SapphireCacheManager();
/* 獲取緩存實例 */
Cache cache = cacheManager.getCache("defaultCache");
Element element1 = new Element(SaveObject.class.getName(),
"testService1", cache);
element1.put(26);
System.out.println("age: " + cache.get("age"));
Element element2 = new Element(SaveObject.class.getName(),
"testService2", cache);
element2.put(1, "JohnGao");
System.out.println("UserBean: " + cache.get("info"));
}
}
此處省略導包過程…
public class SaveObject implements CacheSerializable
{
@CacheService(cacheElementKey = "age")
public int testService1(int age)
{
return age;
}
@CacheService(cacheElementKey = "info")
public Object testService2(int userId, String userName)
{
class InfoBean implements CacheSerializable
{
int userId;
String userName;
}
InfoBean info = new InfoBean();
info.userId = userId;
info.userName = userName;
return info;
}
}
在您使用Sapphire爲您提供的緩存註解服務器時,您務必先找到Sapphire的配置文件中的<service:annotation-driven>標籤,並將該標籤的auto屬性設置爲「true」則意味着註解服務成功開啓。接着您即可以經過@CacheService(cacheElementKey = "age")的註解方式對所需緩存的方法進行標註。這裏須要提醒一下@CacheService中須要設置一個cacheElementKey的屬性,該屬性所表明的是緩存Key。
當您成功的在方法前添加@CacheService標註後,仍然還須要使用到一個類型,那即是Element類型。該類型做爲Sapphire的緩存元素類型,在使用緩存註解服務的時候您必須使用它纔可以對您的方法返回值進行動態緩存。
Element提供的經常使用方法以下:
Element(String serviceClass, String serviceMethod,
Cache cache) 構造函數(緩存類型名稱、緩存方法名稱、Cache實例)
put(Object... params):void 添加服務參數
cacheParam(Object... params):void 緩存服務參數
注意:
若是您並無開啓Sapphire的緩存註解服務便使用時,Sapphire將會拋出org.sapphire.cache.
exception.CacheServiceException異常。
8.設置緩存所能存儲的最大元素數量
Sapphire在緩存管理上爲您提供了更爲靈活的緩存管理方式,但首先您應該先了解Sapphire究竟是如何對緩存進行管理的。
經過Sapphire的配置文件咱們能夠在<cache/>標籤中找到一個名爲maxElementsInSize的屬性,該屬性用於定義單個緩存所容許存放的最大緩存元素數,假設您將maxElementsInSize屬性設置爲10,那麼您的緩存實例將只容許緩存10個數據元素。
一旦您所定義的maxElementsInSize溢出,Sapphire將會拋org.sapphire.cache.exception.
CacheElementsException異常。
9.設置緩存所能存儲的最大緩存容量
Sapphire做爲一個高效的緩存Framework,單個緩存容許您存儲高達1Gbyte的緩存數據。固然Sapphire的緩存容量與實際的物理內存與VM內存精密相關,也就是說若是您但願將Sapphire的單個緩存容量設置爲1GByte,那麼你須要觀察您的實際物理內存及VM內存是否容許,不然Sapphire將會拋出java.lang.OutOfMemoryError異常。
經過Sapphire的配置文件咱們能夠在<cache/>標籤中找到2個名爲maxCacheInMemory和capacityUnit的屬性,其中maxCacheInMemory屬性用於設置您所定義的緩存容量大小,而maxCacheInMemory則用於定義您的緩存容量單位,假設maxCacheInMemory定義爲「10」,capacityUnit定義爲「mByte」,那麼也就是說您則定義了一個緩存容量爲10mByte的單個緩存實例。一旦您所定義的maxCacheInMemory溢出,Sapphire將會拋出org.sapphire.cache.exception.
OutOfCacheError異常。
在程序中您能夠經過Cache類型提供的一些緩存容量及元素檢測方法來觀測您具體的緩存容量開銷。
觀測緩存容量開銷實例:
/* 初始化Sapphire緩存管理容器 */
CacheManager cacheManager = new SapphireCacheManager();
/* 獲取緩存實例 */
Cache cache = cacheManager.getCache("defaultCache");
/* 添加緩存元素 */
cache.put("key", new byte[100]);
System.out.println("最大緩存元素長度:" + cache.getMaxElementsInSize());
System.out.println("當前緩存元素長度:" + cache.getElementsInSize());
System.out.println("剩餘緩存元素長度:" + cache.getSurplusElementsInSize());
System.out.println("最大緩存容量:" + cache.getMaxCacheInMemory());
System.out.println("當前緩存容量:" + cache.getCacheInMemory());
System.out.println("剩餘緩存容量:" + cache.getSurplusCacheInMemory());
注意:
若是最大緩存元素長度<=當前緩存元素長度時,剩餘緩存元素長度則爲「-1」。若是當前緩存容量>最大緩存容量時,剩餘緩存容量則爲「-1」。
10.緩存持久化
在您使用Sapphire緩存數據時,極有可能會出現maxElementsInSize溢出及maxCacheInMemory溢出。但這些溢出的數據可能偏偏是較爲重要且不但願丟失的數據,這個時候該怎麼辦呢?值得慶幸的是Sapphire爲您帶來了高效的緩存持久化技術,也就是說您能夠經過Sapphire的配置文件找到<cache/>標籤的overflowToDisk屬性,並設置爲「true」時,那麼一旦maxElementsInSize或者maxCacheInMemory溢出時,其溢出的數據並不會直接丟失,Sapphire則將會爲您將這一部分溢出的數據持久化於本地進行存儲,以便於您繼續使用。
若是您但願使用Sapphire爲您提供的緩存持久化技術,那麼您不只僅須要將Sapphire配置文件中得overflowToDisk屬性設置爲「true」,您還須要設置<diskStore>標籤中得path、diskEternal、timeToRemoveSeconds等3個屬性。path屬性缺省爲「java.io.tmpdir」,也就是說一旦出現maxElementsInSize或者maxCacheInMemory溢出時,Sapphire會將溢出數據緩存於操做系統的臨時目錄(不一樣的操做系統臨時目錄不一樣)中進行存儲,存儲格式爲SAPPHIRE_CACHE.data。
除了path屬性外,<diskStore>標籤中的另外2個屬性diskEternal和timeToRemoveSeconds則將知足您更多的需求。若是您但願您所持久化的緩存數據是永遠有效的,則須要將diskEternal屬性設置爲「true」,這樣一來持久化於本地的緩存將永不失效。若是您將其設置爲「false」時,則意味着timeToRemoveSeconds屬性所定義的內容將影響到持久化緩存的失效週期,假設您將timeToRemoveSeconds屬性定義爲「10」,當10秒之後,Sapphire的回收器將會對持久化緩存進行回收。
11.加載虛擬機重啓期數據
當您成功將緩存進行持久化後,Sapphire爲您提供了一種持久化讀取機制來加載虛擬機重啓期數據。固然您須要將Sapphire配置文件中的diskPersistent屬性設置爲「true」
這裏有一點您須要稍加註意,若是您在Sapphire的配置文件中設置的maxElementsInSize或者maxCacheInMemory屬性再也不重啓期數據的範圍內,也就是說Sapphire仍然會將其認爲溢出,致使重複緩存持久化。
12.緩存回收策略
Sapphire爲您提供有3種緩存回收策略,分別爲:LRU、LFU、RMD。
LRU(最少使用, Least Recently Used)將會根據您對緩存元素的實際使用來動態收回緩存元素,使用次數最少的緩存元素則優先被Sapphire回收器進行回收,固然您須要經過Sapphire的配置文件找到<cache>標籤並設置timeToLiveSeconds屬性,該屬性主要用於設置緩存的失效週期,單位爲秒。假設您將timeToLiveSeconds屬性設置爲「10」,則意味着10秒之後Sapphire回收器將會按照cacheCleanupPolicy屬性所定義的回收策略對緩存進行動態回收。LFU和RMD等回收策略也是常常較爲適用的,但通常來講咱們推薦您使用LRU緩存回收策略。
注意:
若是您在<cache>標籤中將eternal屬性設置爲「true」時,則意味着您的緩存爲永不失效,一樣cacheCleanupPolicy則也就意味着失效。
13.分佈式緩存——TCP集羣配置模式 Sapphire爲您提供了3種類型的分佈式緩存機制,但Sapphire推薦您使用TCP集羣爲首選。由於該分佈式緩存的實現方式爲TCP單播機制,不管是安全性、正確性、穩定性,哪怕是效率上都是較爲優秀的。 若是您但願使用TCP集羣配置模式的方式來實現緩存共享,那麼首先您須要在Sapphire的配置文件中添加TCP集羣配置。 您可使用Sapphire爲您提供的<distributedCacheManagerFactory>標籤,該標籤中一共包含了3個屬性,分別是:class、serverHost以及serverPort。其中class用於指定集羣類型,serverHost屬性用於指定集羣地址,serverPort屬性用於指定集羣端口。 假設您已經成功配置TCP集羣后,您還需在<cache>標籤中添加<distributedCacheListener>子標籤,該標籤用於啓動緩存複製監聽,幷包含一個名爲replicateCache的屬性,若是您將其設置爲「true」則意味着您容許緩存實例實現緩存共享,不然將意味着拒絕緩存共享。 TCP集羣配置示例: <!-- 緩存註解服務驅動 --> <service:annotation-driven auto="true" /> <!-- 緩存持久化全局配置 --> <diskStore path="java.io.tmpdir" diskEternal="false" timeToRemoveSeconds="60" /> <!-- TCP集羣配置模式 --> <distributedCacheManagerFactory class="org.sapphire.cache.distributed.tcp.TcpDistributedCacheManagerFactory" serverHost="127.0.0.1" serverPort="30051" /> <!-- 缺省緩存配置 --> <cache name="defaultCache" eternal="false" maxElementsInSize="100" maxCacheInMemory="1" capacityUnit="mByte" overflowToDisk="true" diskPersistent="false" timeToLiveSeconds="60" cacheCleanupPolicy="LRU"> <!-- 啓動緩存複製監聽 --> <distributedCacheListener replicateCache="true" /> </cache> 經過上述示例,您能夠發現< distributedCacheManagerFactory >標籤中的class屬性其值爲一個TcpDistributedCacheManagerFactory類型(位於org.sapphire.cache.distributed.tcp包下)。該類型做用於搭建一個穩定且高性能的TCP分佈式緩存服務器。 使用Sapphire來爲您實現分佈式緩存是一件及其簡單的事情,只要您在Sapphire的配置文件中啓用了TCP集羣配置模式,併成功開啓了緩存複製監聽,那麼就無需您在作任何操做,即可實現分佈式緩存共享。接下來您能夠經過一段簡單的測試代碼來實現Sapphire爲您提供的基於TCP集羣配置模式的分佈式緩存。 分佈式緩存示例: /* 初始化Sapphire緩存管理容器 */ CacheManager cacheManager = new SapphireCacheManager(); /* 獲取緩存實例 */ Cache cache = cacheManager.getCache("defaultCache"); while(true) { cache.put("cacheKey", "cacheValue"); System.out.println(cache.get("key")); Thread.sleep(1000); } 上述程序一旦運行後,Sapphire便會成功開啓TCP緩存服務器,啓動緩存服務,併成功的實現緩存共享。但這個時候您可能會以爲奇怪,由於您並無使用客戶端對TCP緩存服務器進行鏈接,爲何您卻能夠獲取共享後的緩存?其實這是由於在缺省環境下Sapphire的TCP緩存服務器既是服務端又是客戶端,可以自身實現緩存共享。 若是您的網絡中有其他的節點須要共享緩存信息,那麼您即可以將< distributedCacheManagerFactory >標籤中的class屬性的值更改成org.sapphire.cache.distributed.tcp. TcpDistributedCacheConnection便可,該類型爲TCP集羣鏈接類型。 注意: 若是程序中,您並無成功啓動TCP集羣配置模式,而直接爲class屬性去配置TcpDistributedCacheConnection類型,這個時候Sapphire則會拋出org.sapphire.cache.exception. TcpCacheDistributedException異常。 還有一點您須要注意,假設您程序中有多個緩存實例都須要實現緩存共享時,您能夠在Sapphire配置文件中爲須要實現緩存共享的緩存類型開啓緩存複製監聽便可。