深入剖析SapphireFramework—本地缓存基本使用

 深入剖析SapphireFramework—本地缓存基本使用_第1张图片

 

前言

本篇博文将重点讲解关于Sapphire的各个方面,其中内容涉及到其Framework的底层实现细节及设计思想,所以建议大家仔细的阅读本篇博文。如果有不清楚或者不理解的地方,笔者希望大家能够通过邮件或者留言的方式告知笔者,笔者将耐心并负责的对其进行回复。

 

当然在正式开始之前,你首先需要明白的是Sapphire究竟是出于领域模型中的哪一层?以及Sapphire的目的什么?其实Sapphire作用于缓存层,其目的为分布式内存对象缓存系统。这时你可能会问笔者为什么要选用Sapphire作为你的缓存框架?市面上不是有诸多优秀的第三方开源缓存框架吗?Sapphire具备何种优势?其实谈到第三方缓存框架笔者首推EhCache,因为不论是在本地缓存领域还是在分布式缓存领域,吞吐性或者并发性方面,EhCache都是无可挑剔的,但Ehcache与生俱来的缺陷同样也不可避免。首先EhCache并不支持对缓存元素的内存管理,这一点在企业级的项目中其实是至关重要的。并且EhCache仅仅只是指针对缓存元素的数量做了管理,这只是一个“伪内存”管理。Sapphire提供真正意义上内存管理的实现,这便是你选用Sapphire的条件之1,其2,EhCache的分布式缓存不论在配置上还是使用上都显得不方便,至少对于笔者来说,更倾向简洁的配置风格,这便是你选用Sapphire的理由之2。其3,Ehcache原生并不支持Annotation,Sapphire原生则支持,这便是你选用Sapphire的理由之3。最后Sapphire提供有更加丰富和灵活的缓存回收策略缓存内存单位设置也将是你选用Sapphire的重要理由。

 

Sapphire的优点如下:

1、敏捷快速;

2、体系结构中立,跨平台支持;

3、多种缓存管理容器实现;

4、多种缓存回收策略(LRU、LFU、FIFO、RDM);

5、支持缓存注解服务驱动(Annotation方式直接缓存方法);

6、支持缓存持久化及加载虚拟机运行期数据;

7、单个缓存最大缓存容量为1gByte;

8、支持缓存容量单位设置(byte、kByte、mByte、gByte);

9、支持TCP单播集群(BIO/NIO)、P2P广播、组播集群、RMI组播集群;

10、支持与Spring的无缝集成,及事物集成;

 

一、Sapphire的下载与安装

Sapphire目前的最新版本为2.0.3.RC1,笔者本章博文所有的程序示例都将选用此版本作为其实现。好了,废话不多说,首先你可以访问Sapphire的官方地址:http://code.google.com/p/sapphire-cache/downloads/list进行对应版本的下载。

 

下载页面:

深入剖析SapphireFramework—本地缓存基本使用_第2张图片

 

当你成功下载好后,你可以对于压缩包进行解压,该压缩包中包含了咱们需要使用到的依赖库、API、使用范例等资源。

至于Sapphire的安装也是极其简单的。如果你是使用Maven来管理你的项目,你可能需要先将构件下载至本地,然后上传至你的Nexus私服中,最后配置构件下载即可。当然如果是非Maven的项目则可以将构件直接导入进工程即可使用。

 

二、Sapphire的本地缓存使用

Sapphire的本地缓存使用相对于EhCache来说,则显得更加简单方便。不过可能会有诸多开发人更关心缓存性能,三句话离不开性能。既然这样,咱们就先来看看Sapphire与EhCache在本地缓存方面的缓存吞吐性测试对比

下述为Sapphire开启内存管理时与EhCache的本地缓存吞吐性操作对比:

深入剖析SapphireFramework—本地缓存基本使用_第3张图片

 

通过上图我们可以发现,本地缓存的10W次吞吐性,Sapphire所花周期为1125ms,EhCache也仅仅只花了惊人的110ms。这是什么原因导致差距如此明显呢?还记得笔者在开始之前曾经给大家提到过Sapphire的缓存内存管理将是一大亮点,正式由于缓存内存的管理需要牺牲掉Sapphire的一部分性能,因为Sapphire在添加缓存元素使,底层实现需要不停的跟踪对象内存开销,以及计算对象内存开销

注意看Sapphire的Cache.java实现:

/* 序列化当前缓存对象 */
ByteArrayOutputStream byteArray = new ByteArrayOutputStream();
new ObjectOutputStream(byteArray).writeObject(value);

/* 获取当前缓存对象容量 */
long objectInMemory = byteArray.toByteArray().length;

/* 存储当前缓存对象容量 */
cacheInMemoryList.put(key, objectInMemory);

/* 计算当前缓存已用缓存容量 */
cacheInMemory += objectInMemory;
surplusCacheInMemory = cacheInMemory < maxCacheInMemory ? maxCacheInMemory
- cacheInMemory: -1L;

  

假设笔者将上述代码实现进行注释后,咱们再来看看重新执行本地缓存的10W次吞吐性测试,看看会不会有什么改变?

下述为Sapphire关闭内存管理时与EhCache的本地缓存吞吐性操作对比:

深入剖析SapphireFramework—本地缓存基本使用_第4张图片

 

值得庆幸的是,当咱们关闭Sapphire的内存管理后,Sapphire的本地缓存性能提升了不少好,峰值达到了203ms,距离EhCache仅仅只差一倍左右,当然既然目前存在一定的差距,笔者希望Sapphire在今后的道路上更够优化的更好。

 

说了这么多,来点实在的吧。打开你的IDE工具,咱们来编写第一个基于Sapphire的程序。在开始编写程序之前,咱们首先需要将Sapphire的配置文件导入进项目,配置文件存放于src下即可。

配置文件内容:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE sapphire PUBLIC 
	"-//Sapphire Cache//DTD Sapphire Configuration 2.0//CN"
	"http://sapphire-cache.googlecode.com/files/sapphire-cache-2.0.3.dtd">
<sapphire>
	<!-- 缓存注解服务驱动 -->
	<service:annotation-driven auto="true" />

	<!-- 缓存持久化全局配置 -->
	<diskStore path="java.io.tmpdir" diskEternal="false"
		timeToRemoveSeconds="60" />

	<!-- 缺省缓存配置 -->
	<cache eternal="false" maxElementsInSize="100" maxCacheInMemory="1"
		capacityUnit="mByte" overflowToDisk="true" diskPersistent="false"
		timeToLiveSeconds="60" cacheCleanupPolicy="FIFO" />
</sapphire> 

 

 上述配置文件中<service:annotation-driven/>标签定义了Sapphire的注解驱动,如果你在项目中需要使用到缓存服务,那么你需要将该服务进行开启

<diskStore/>标签定义了缓存的持久化全局配置,也就是说缓存的固化配置。其中“path”属性定义了缓存固化的具体位置,“java.io.tmpdir”代表的是操作系统的临时目录,不同的操作系统其临时目录则不为相同。“diskEternal”属性定义了缓存固化是否永久有效,如果缓存固化永久有效将不执行缓存固化回收,否则执行“timeToRemoveSeconds”属性。

<cache>属性则定义了缓存的基本参数信息,其中“eternal”属性定义了缓存是否永久有效,“maxElementsInSize”属性定义了缓存的最大元素个数,“maxCacheInMemory”属性定义了缓存的最大内存资源,“capacityUnit”属性定义了内存资源单位,“overflowToDisk”属性定义了缓存是否允许持久化,“diskPersistent”属性定义了是否允许加载虚拟机重期数据,“timeToLiveSeconds”属性定义了缓存对象的回收周期,“cacheCleanupPolicy”属性定义了缓存的内存回收策略

当然如果你将“eternal”属性定义为“true”后,缓存的内存回收将失效,并且如果缓存内存溢出,这里提出的缓存溢出可能包含2个方面,第一个为缓存元素溢出,另一个为缓存内存溢出时,如果“overflowToDisk”属性设置为“false”时将Sapphire将会抛出内存溢出异常

Sapphire的缺省缓存为“defaultCache”,在配置文件中你也可以定义自定义缓存,但Sapphire不允许定义在配置文件中的缓存名称重复,否则Sapphire在初始化缓存容器时会抛出:org.sapphireframework.cache.exception.CacheNameException: Cache name not allowed to repeat异常。

 

编写第一个基于Sapphire的程序:

/* 初始化缓存管理容器 */
cacheManager = new SapphireCacheManager();
		
/* 获取缓存实例 */
Cache cache = cacheManager.getCache("defaultCache");
		
/* 缓存操作 */
cache.put("key1", "value");
cache.put("key2", 10);
cache.put("key3", 1.1D);
cache.put("key4", true);
cache.put("key5", 'A');
cache.put("key6", new CacheTest.Test_());
System.out.println(cache.get("key1"));

 

在您的程序中使用Sapphire来帮助您搭建缓存架构是一件极其简单且轻松的事情。首先我们只需初始化Sapphire缓存管理容器(上述程序示例中使用到的Sapphire管理容器为SapphireCacheManager),该容器会负责初始化一系列的缓存前期准备工作。紧接着我们需要通过SapphireCacheManager的getCache(String cacheName)方法取得缓存实例并得到一个具体的Cache对象,最后通过Cache对象的put(Object key, Object value)方法添加您所需缓存的数据即可。

至于其他的缓存CRUD操作将与ConcurrentHashMap保持一致,换句话说Sapphire就是对ConcurrentHashMap进行了轻量级封装 

SapphireCache的缺省缓存为“defaultCache”,当然你也可以在配置文件中添加你自己的自定义缓存,不过如果getCache()找不到你所定义的缓存名称时将会抛出:org.sapphireframework.cache.exception.CacheException: Unable to find the cache instances: defausltCache异常。

 

CacheManager为Sapphire的顶层缓存管理容器,其派生类有:

深入剖析SapphireFramework—本地缓存基本使用_第5张图片

 

通过上图我们可以发现CacheManager的缓存容器实现为SapphireCacheManager与CacheManagerForSafety。其中SapphireCacheManager为非线程安全,而CacheManagerForSafety则基于线程安全模型就性能比较而言SapphireCacheManager显得更为高效,CacheManagerForSafety则更为安全,当然您可以根据您的具体需求选择合适您的缓存管理实现。

CacheManager提供的常用方法如下:

/**
 *	获取缓存实例
 *
* 	@author JohnGao
 * 
* 	@param String: 缓存实例名称
* 
* 	@throws Exception
* 
* 	@return Cache: 指定缓存实例
*/
public Cache getCache(String cacheName) throws Exception;
	
/**
*	获取所有缓存已用缓存内存容量
*
* 	@author JohnGao
* 
* 	@param String: 缓存实例名称
* 
* 	@throws Exception
* 
* 	@return long:所有缓存容量大小
*/
public long getCacheInMemoryAll() throws Exception;

 

当然不管您是使用任何一种缓存管理容器,Sapphire都为您提供有2种构造实现。假设您在项目中使用SapphireCacheManager作为缓存管理实现,您可以根据您具体的配置需求来达到满足您具体的实现。通常情况下,我们建议您使用缺省构造,因为这样不仅仅可以为您减少一定的代码量,且显得更为直观,但使用带参构造则会使您的应用更为灵活和高效。

使用SapphireCacheManager作为管理容器2种实现:

/* 第一种初始化Sapphire容器方式 */ 
CacheManager cacheManager = new SapphireCacheManager(); 
 或者: 
 /* 第二种初始化Sapphire容器方式 */ 
CacheManager cacheManager = new SapphireCacheManager("sapphire-cache.xml");

 

 使用CacheManagerForSafety作为管理容器2种实现:

/* 第一种初始化Sapphire容器方式 */ 
CacheManager cacheManager = new CacheManagerForSafety();  
或者: 
 /* 第二种初始化Sapphire容器方式 */ 
CacheManager cacheManager = new CacheManagerForSafety("sapphire-cache.xml");

 

注意:

如果使用第一种缓存构造实现,Sapphire的缓存管理容器会自动在根目录查找名为sapphire-cache.xml的缓存配置文件。

 

你可能感兴趣的:(cache,sapphire)