对于JCS的研究还是要回到从前使用redis的场景。主要是redis作为分布式缓存,可以集中在内存中缓存大量数据。但是,进程与redis的通信终归是进程间的通信,所有的数据都需要序列化与反序列化。这中间的开销,在高频访问场景下其实还是很大的。最简单的就是我在顶呱呱时参与的性能测试,当时单压登录的时候,就显示瓶颈就是与redis的通信,更确切的就是反序列化的过程。
抛开压测的方法是否合理,这一瓶颈在很多场景下其实是不可忽略的,比如会话验证。每个接口无论是否需要进行会话验证,其实都需要在相关的逻辑走一道。如果逻辑中使用的某些配置值(比如不需要验证的uri有哪些)在redis中,那这个开销其实还是蛮大的,平常不显,压力大了就显出来了。当时我是用一个HashMap来临时做了个缓存。结果有两个问题:
其实是当时不知道还有进程内的缓存框架。这也是前段时间刚好碰到的。最近忙过了一段时间再回来,发现还没有整理,于是就先用起来进行整理了。
当时选型还是选了很久,现在时间过得有些久了,细节记不清了。总之最后选择了JCS。当时仔细对比过Spring的cache机制,发现它并不是一个缓存,而是方便我们进行缓存操作的一组类,在spring的和核心里。这里我们暂时就先不管它了,先说JCS怎么用吧。
我对JCS的定位是进程内缓存,基本的目标是将它纳入我以后搭建项目的工具集中。这里需要使用它实现的几个基本功能,也就是本次研究的目标是:
官网的Getting Started中,使用jar包的形式引入jcs3,这并不符合我常规使用的项目依赖管理方式。maven的引入方式如下:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-jcs3-jcache</artifactId>
<version>3.0</version>
</dependency>
在使用jcs之前,我们还是首先要了解一些它的核心概念,否则后面很多配置和操作都是无从谈起的。而
元素,是jcs中的最小管理单元,也就是一个缓存数据对象。我们可以每个元素进行独立的设置。
jcs中使用区域来对元素分区管理。这样我们就可以对一部分元素采用这种配置,而一部分元素采用另一种配置。
针对于核心功能之外的扩展功能,比如使用jdbc对缓存进行持久化,多进程之间的同步等等,具体可以参考官网的相关章节。
在官网的介绍中,我们需要配置的根目录也就是resource目录下创建一个cache.ccf文件来对这个缓存进行配置。这个文件即使什么都没有,缓存也就都可以用了。但是,我可在使用缓存时可以对其记性需要的控制,我们还是要了解它是怎么配置的。
总体上来说,缓存包括三种配置:
下面简单举例说明下各部分的配置结构,具体配置内容在后面再详细整理。
在使用JCS时,任何未指定配置的区域,都将使用default区域的配置。以下是对default区域的一点样例配置。
jcs.default=DC,RFailover
jcs.default.cacheattributes=org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.default.cacheattributes.MaxObjects=1000
其中最重要的是jcs.default=DC,RFailover
。这会告诉我们使用了哪些辅助缓存。但是,这些辅助缓存将会在后面独立进行定义。我们可以根据需要添加任意数量的辅助缓存,将他们用英文逗号分隔就好了。远程和横向辅助缓存的行为可能会发生冲突,需要注意。
以下是一段区域配置的样例
jcs.region.testCache=DC,RFailover
jcs.region.testCache.cacheattributes= org.apache.commons.jcs3.engine.CompositeCacheAttributes
jcs.region.testCache.cacheattributes.MaxObjects=1000
我们注意到,默认配置是以jcs.default开头的,而上面的配置是以jcs.region.testCache开头的。它就是testCache这个区域的配置。与default对应,jcs.region.testCache=DC,RFailover也是对它辅助缓存的配置。
以下是两个辅助缓存配置的样例
jcs.auxiliary.DC=org.apache.commons.jcs3.auxiliary.disk.DiskCacheFactory
jcs.auxiliary.DC.attributes=org.apache.commons.jcs3.auxiliary.disk.DiskCacheAttributes
jcs.auxiliary.DC.attributes.DiskPath=c:/dev/cache/raf
jcs.auxiliary.RFailover=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheFactory
jcs.auxiliary.RFailover.attributes=org.apache.commons.jcs3.auxiliary.remote.RemoteCacheAttributes
jcs.auxiliary.RFailover.attributes.RemoteTypeName=LOCAL
jcs.auxiliary.RFailover.attributes.FailoverServers=localhost:1102,localhost:1101
上面就定义了我们前面在元素和区域配置中用到的两个辅助缓存。我们可以看到它们的配置的开头分别是jcs.auxiliary.DC
和jcs.auxiliary.RFailover
辅助缓存好像主要是用于远程同步和本地持久化的。
官方网站上只有对配置参数的举例,并没有详细的配置参数说明。但是呢,它所有的配置都是走的特定的类,所以,我们可以去类里面查看具体的配置说明,以及查看都有什么参数可以配置。
在default中的jcs.default.cacheattributes属性用的是这个类的配置。这个类定义了缓存区域的默认配置,如果完全没有在配置文件中进行配置的话,就会使用这个类里的硬编码对缓存区域进行配置。属性不是特别多,我就列举一下吧:
元素配置
首先获取cache对象
CacheAccess<String, String> cache = JCS.getInstance( "default" );
泛型里指定的就是缓存的key和value的类型。getInstance中传入的是region的名称,没有配置的名称也是可以传的,会按照默认配置返回。接下来我们就可以拿着这个对象对缓存进行操作了。
下面是一段典型的对缓存赋值的操作。
try
{
cache.put(key,value);
}
catch ( CacheException e )
{
logger.error(String.format( "Problem putting value %s in the cache, for key %s%n%s",
value, key, e.getMessage() ) );
throw e;
}
可以看到,操作异常是可以使用缓存捕捉的。
常用的操作也就put,get和remove,具体就不详细说明了,很简单。
这样日常使用也就够了。
上面的操作,作为使用缓存进行增删改查已经没有什么问题了。但是,我们有些时候可能会需要使用缓存做一些进阶的事情,就需要对其进行更加深入的控制和监听了。
在jcs3中,可以订阅缓存元素的一些事件,方便我们在元素相关的生命周期,或者发生相应的事情时获得通知,及时处理。
具体的事件处理需要实现接口:org.apache.commons.jcs3.engine.control.event.behavior.IElementEventHandler
事件处理的实例可以直接添加到元素里,也可以放到区域的默认配置里,但是好像只能通过代码进行添加。以下是官网的一些样例代码,由于我这里还没有实际的业务点使用,就没有对其进行测试了。记录在这里,以后就不用老去翻官网了。
通过元素添加
CacheAccess<String, String> jcs = JCS.getInstance( "myregion" );
. . .
MyEventHandler meh = new MyEventHandler();
// jcs.getDefaultElementAttributes returns a copy not a reference
IElementAttributes attributes = jcs.getDefaultElementAttributes();
attributes.addElementEventHandler( meh );
jcs.put( "key", "data", attributes );
通过区域的默认配置进行设置
CacheAccess<String, String> jcs = JCS.getInstance( "myregion" );
. . .
MyEventHandler meh = new MyEventHandler();
// this should add the event handler to all items as
//they are created.
// jcs.getDefaultElementAttributes returns a copy not a reference
IElementAttributes attributes = jcs.getDefaultElementAttributes();
attributes.addElementEventHandler( meh );
jcs.setDefaultElementAttributes( attributes );
在我的实际使用场景中,我希望将数据字典以及一些常用的配置放到缓存里,在使用的时候直接通过缓存加载而不是联表查询,以降低表之间的耦合,减少sql所承载的职责。但是,数据字典中数据的维护是在后台的,使用的时候大多实在业务进程,它们一般是以springboot服务的形式承载的。所以,我们就需要后台服务进程可以更新业务进程的缓存。
在jcs3中,有三种方式可以解决这个问题:
由于这部分涉及一些具体业务和两个项目,等我写好了之后以新的贴子进行更新吧。本文就到这里了。