JCS是Jakarta的项目Turbine的子项目,它是复合式的缓冲工具,具有配置灵活的特点。JCS提供内存、硬盘、分布式架构、构建缓存 服务器四种方式来实现对象缓存;能够很方便的实现缓存的差异化定制。有缓冲对象时间过期设定。对于一些需要频繁访问而每访问一次都非常消耗资源的对象,可以临时存放在缓冲区中,这样可以提高服务的性能。而JCS正是一个很好的缓冲工具。缓冲工具对于读操作远远多于写操作的应用性能提高非常显著。
JCS现在支持两种内存缓冲算法LRU和MRU。通常都是使用LRU算法。org.apache.stratum.jcs.engine.memory.lru.LRUMemoryCache。使用内存缓冲区需要定义缓冲区大小,当超过缓冲区限制时,会将缓冲内容抛弃掉。如果有配硬盘缓冲,则将挤出来的缓冲内容写入硬盘缓冲区。
JCS对于缓冲的对象,可以设定缓冲过期时间,一个对象在缓冲区中停留的时间超过这个时间,就会被认为是“不新鲜”而被放弃。
一方面,为了避免缓冲区过大,撑爆虚拟机的内存,另一方面又希望能够缓冲更多的对象,JCS可以将超出缓冲区大小的对象缓存到硬盘上。配置上也比较方便,只需要指定缓冲临时文件的存放目录位置。硬盘缓冲将缓冲对象的内容写到文件上,但是将访问索引保存在内存中,因此也能够达到尽可能高的访问效率。
通常,将对象缓冲在内存中,一方面提高了应用的性能,而另一方面却使得应用不可以分布式发布。因为假设一个应用配置在两台服务器上并行运行,而两台服务器单 独缓冲,则很容易导致两个缓冲区内容出现版本上的不一致而出错。一个机器上修改了数据,这个动作会影响到本地内存缓冲区和数据库服务器,但是却不会通知到另一台服务器,导致另一台上缓冲的数据实际上已经无效了。并行式的分布缓冲就是解决这个问题。可以通过配置,将几台服务器配成一个缓冲组,组内每台服务器上有数据更新,会横向将更新的内容通过TCP/IP协议传输到其他服务器的缓冲层,这样就可以保证不会出现上述情况。这个的缺点是如果组内的并行的服务器数量增大后,组内的数据传输量将会迅速上升。这种方案适合并行服务器的数量比较少的情况。
客户/服务端式的缓冲集群。这种方式支持一个主服务器和最高达到256个客户端。客户端的缓冲层会尝试连接主服务器,如果连接成功,就会在主服务器上注册。每个客户端有数据更新,就会通知到主服务器,主服务器会将更新通知到除消息来源的客户端以外的所有的客户端。每个客户端可 以配置超过一个服务器,第一个服务器是主服务器,如果与第一个服务器连接失败,客户端会尝试与备用的服务器连接,如果连接成功,就会通过备用服务器与其他客户端对话,同时会定期继续尝试与主服务器取得连接。如果备用服务器也连接失败,就会按照配置顺序尝试与下一个备用服务器连接。这种方式下,更新通知是一种轻量级的,一个机器上的数据更新,不会把整个数据传输出去,而只是通知一个ID,当远程的其他机器收到更新通知后,就会把对应ID的缓冲对象从本地的内存缓冲区中移除,以保证不会在缓冲区内出现错误数据。这种构造需要分别配置客户端和服务器,配置比较麻烦。
首先理解下缓冲区(region)的概念:缓冲区可以理解为内存中临时存放缓冲对象的一个区域,使用缓冲区可以改善某些应用的性能。每个应用根据自身需要,可以定义多个缓冲区,各个缓冲区具有不同的属性,比如缓冲区大小、缓冲过期时间、缓冲区构架等等。不同类型的对象放在不同的缓冲区中以满足不同的需要。缓冲区在JCS中以一个String对象来标示,以方便配置和编程。虽然可以使用中文来作为缓冲区的名称,不过还是推荐使用英文字符,而且不要有空格或者特殊字符。
JCS整体框架主要分为三个大的部分。访问接口(access)、缓冲引擎(engine)以及辅助缓冲(auxiliary)。
访问接口
Java.lang.Object
|
+--org.apache.jcs.access.CacheAccess
|
+--org.apache.jcs.access.GroupCacheAccess
|
+--org.apache.jcs.JCS
JCS是CacheAccess和GroupCacheAccess的子类,实现接口有
org.apache.jcs.access.behavior.IcacheAccess
org.apache.jcs.access.behavior.IGroupCacheAccess
这些接口定义了JCS的行为,主要是以关键字为检索条件的缓冲,还有以关键字为条件的分组缓冲。
缓冲引擎
JCS缓冲体系的缓冲引擎的结构很完善,并且具有良好的可扩展性。主体结构是一个组合式缓冲器(CompositeCache),其中有一个内存缓冲器(MemoryCache)和若干个辅助缓冲器(AuxiliaryCache)。构建缓冲器时,首先向组合式缓冲管理器(CompositeCacheManager)申请,组合式缓冲管理器会构建一个缓冲配置器 (CompositeCacheConfigurator)来从配置文件读取缓冲的配置,然后根据配置来构建组合式缓冲器 (CompositeCache)。配置好的组合式缓冲器会单独工作,管理读写自己缓冲区。
辅助缓冲
目前提供的辅助缓冲器有以下三种,硬盘缓冲,并行式的分布缓冲,星状的客户/服务式的缓冲。
jcs-1.3.jar
commons-lang-2.3.jar
commons-collections-2.1.1.jar
concurrent-1.3.4.jar
同一个应用,只需要修改配置,就可以改变缓冲构架,不需要修改应用的源代码。配置方法也比较简单,就是修改配置文件cache.ccf。Jcs源代码采用Class.getResourceAsStream(/cache.ccf)的方式来加载配置文件,所以项目的cache.ccf要放在字节码文件所在的根目录下面,在web项目中,则要放在classes文件夹下。
一个简单的配置:
1: #WEB-INF/classes/cache.ccf(以下内容不要换行)
2: jcs.default=jcs.default.cacheattributes=org.apache.jcs.engine.CompositeCacheAttributes
3: jcs.default.cacheattributes.MaxObjects=1000
4: jcs.default.cacheattributes.MemoryCacheName=org.apache.jcs.engine.memory.lru.LRUMemoryCache
上面配置了默认缓冲属性。一个应用中,由于对象类型的不同,可能会使用多个缓冲区,每个缓冲区都会有一个名字,如果在配置文件中没有指明特定的缓冲区的属性,所有的缓冲区都会根据默认属性来构建。上面的内容,指明缓冲区的大小为存放1000个对象,内存缓冲器使用 LRUMemoryCache对象。可选的还有MRUMemoryCache,应该可以自定义新的内存缓冲区。1000个缓冲对象这个容量,是指每个缓冲区都缓冲1000个,而不是指所有缓冲区总容量。以上配置,就可以让应用运行起来。
Client.java
1: package com.zero.jcs;
2: import java.io.Serializable;
3: public class Client implements Serializable{
4: private String name;
5: private int age;
6: public Client() {
7: }
8: public Client(String name, int age) {
9: this.age = age;
10: this.name = name;
11: }
12: public String getName() {
13: return name;
14: }
15:
16: public void setName(String name) {
17: this.name = name;
18: }
19: public int getAge() {
20: return age;
21: }
22: public void setAge(int age) {
23: this.age = age;
24: }
25: }
JCSCache.java
1: package com.zero.jcs;
2: import org.apache.jcs.JCS;
3: import org.apache.jcs.access.exception.CacheException;
4: public class JCSCache {
5: private static final String cacheRegionName = "client";
6: private static JCSCache instance;
7: private static JCS cache;
8: private JCSCache() {
9: try {
10: cache = JCS.getInstance(cacheRegionName);
11: } catch (CacheException e) {
12: e.printStackTrace();
13: }
14: }
15: public static JCSCache getInstance() {
16: synchronized (JCSCache.class) {
17: if (instance == null) {
18: instance = new JCSCache();
19: }
20: }
21: return instance;
22: }
23: public void putObject(Object key, Object obj) {
24: try {
25: cache.put(key, obj);
26: } catch (Exception e) {
27: e.printStackTrace();
28: }
29: }
30:
31: public Object getObject(Object key) {
32: Object obj = null;
33: obj = (Object) cache.get(key);
34: return obj;
35: }
36: public void clearObject(Object key) {
37: try {
38: cache.remove(key);
39: } catch (Exception e) {
40: e.printStackTrace();
41: }
42: }
43: public void clear() {
44: try {
45: cache.clear();
46: } catch (Exception e) {
47: e.printStackTrace();
48: }
49: }
50: }
Test.java
1: package com.zero.jcs;
2: import com.zero.jcs.JCSCache;
3: public class Test {
4: public static void main(String[] args) {
5: JCSCache jcsCache = JCSCache.getInstance();
6: jcsCache.putObject("a", "111");
7: jcsCache.putObject("b", new Client("zero", 23));
8: System.out.println("a " + jcsCache.getObject("a"));
9: System.out.println("b " + jcsCache.getObject("b"));
10: }
11: }