Skip to content

Commit 2efeab6

Browse files
author
邱家榆
committed
增加对JedisCluster的支持
1 parent ed35069 commit 2efeab6

File tree

12 files changed

+160
-103
lines changed

12 files changed

+160
-103
lines changed

README.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,30 @@
88
现在使用的缓存技术很多,比如*Redis**Memcache**EhCache*等,甚至还有使用*ConcurrentHashMap**HashTable* 来实现缓存。但在缓存的使用上,每个人都有自己的实现方式,大部分是直接与业务代码绑定,随着业务的变化,要更换缓存方案时,非常麻烦。接下来我们就使用**AOP + Annotation** 来解决这个问题,同时使用**自动加载机制** 来实现数据“**常驻内存**”。
99

1010

11-
###[设计思想及原理](./doc/idea.md)
11+
### [设计思想及原理](./doc/idea.md)
1212

13-
###[使用方法](./doc/use.md)
13+
### [使用方法](./doc/use.md)
1414

15-
###[注解(Annotation)说明](./doc/annotations.md)
15+
### [注解(Annotation)说明](./doc/annotations.md)
1616

17-
###[表达式的应用](./doc/script.md)
17+
### [表达式的应用](./doc/script.md)
1818

19-
###[缓存删除](./doc/deleteCache.md)
19+
### [缓存删除](./doc/deleteCache.md)
2020

21-
###[注意事项](./doc/warning.md)
21+
### [注意事项](./doc/warning.md)
2222

23-
###[缓存管理页面](./doc/admin.md)
23+
### [缓存管理页面](./doc/admin.md)
2424

25-
###[与Spring Cache的区别](./doc/SpringCache.md)
25+
### [与Spring Cache的区别](./doc/SpringCache.md)
2626

27-
###源码阅读
27+
### 源码阅读
2828

2929
已经实现基于aspectj,代码在com.jarvis.cache.aop.aspectj.AspectjAopInterceptor。想通过阅读代码了解详细细节,可以以此为入口。
3030

3131

3232
### [更新日志](./doc/changesLog.md)
3333

34-
###未来计划:
34+
### 未来计划:
3535
希望未来能更好适应高并发的环境,更方便运维,欢迎有这方面经验的人能参与进来,让更多的人受益。
3636

3737
在异步刷新缓存时,增加尝试多次去数据层加载数据,以适应解决有多个数据源,而其中部分数据源出问题情况。通过这种尝试机制,也许能获取到新的数据。

doc/ConcurrentHashMap.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
###ConcurrentHashMap配置
1+
### ConcurrentHashMap配置
22

33
<bean id="cacheManager" class="com.jarvis.cache.map.CachePointCut" init-method="start" destroy-method="destroy">
44
<constructor-arg ref="autoLoadConfig" />

doc/JRedis.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
####JRedis配置
1+
#### JRedis配置
22

33
Redis配置
44

doc/Memcache.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
###Memcache配置
1+
### Memcache配置
22

33
<bean id="memcachedClient" class="net.spy.memcached.spring.MemcachedClientFactoryBean">
44
<property name="servers" value="192.138.11.165:11211,192.138.11.166:11211" />

doc/changesLog.md

Lines changed: 37 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
##更新日志
1+
## 更新日志
22

3-
* ####4.14 修改说明
3+
* #### 4.14 修改说明
44

55
* 使用Lombok来缩减代码,Lombok能帮助我们减少写get,set,hashCode,toString等没有技术含量的工作,而且在修改增加或删除java bean中的属性时,不需要去改hashCode,toString等方法,减少因为忘记修改而造成的错误。
66
* 增加OGNL表达式引擎支持,经过测试它的性能要比SpringEL表达式还要优秀。测试代码在:com.test.script.ScriptTest
77

8-
* ####4.13 修改说明
8+
* #### 4.13 修改说明
99

1010
* com.jarvis.cache.clone.ICloner中的Object deepClone(Object obj) 改为 Object deepClone(Object obj, final Type type),在能获得Type的情况下使用,能更好保证数据准备和效率
1111

@@ -17,7 +17,7 @@
1717

1818
* 修复DataLoader中,等待第一个请求获取数据后,又再去数据层获取数据的BUG,这个BUG是在4.11版本产生的,建议使用4.11和4.12的用户升级一下。
1919

20-
* ####4.12 修改说明:
20+
* #### 4.12 修改说明:
2121

2222
* fastjson deepClone 数组中有Map或Collection时,转换失败的问题
2323
* Fastjson深度复制优化:针对深度复制Method的arguments进行优化,通过method.getGenericParameterTypes() 来方便深度复制泛型参数。
@@ -26,40 +26,40 @@
2626
* ICacheManager中的get和set方法中,增加Method method和 Object args[]两个参数,方便使用者根据情况进行扩展,比如:增加一些自定义的注解,来处理特殊业务逻辑(比如:增加本地缓存功能)
2727

2828

29-
* ####4.11 修改说明:
29+
* #### 4.11 修改说明:
3030

3131
* 增加刷新缓存数据功能,如果不使用自动加载,则在缓存即将过期时,开启线程进行异步刷新数据,可以减少用户的等待,避免因缓存失效失效造成系统压力过大;
3232
* 在刷新缓存和自动加载缓存中,如果从数据层加载数据时,发生异常,则使用旧数据进行续租(如果有旧数据的话),达到提前预防缓存失效后,系统压力过大问题;
3333
* 解决使用fastjson进行深度复制数据组时,转换错误的问题;
3434
* 增加使用cloning进行深度复制,性能要比fastjson提高50%。相关的测试代码在:com.test.fastjson.CloningTest和com.test.fastjson.DeepCloneTest两个类中;
3535
* 将数据加载功能从AbstractCacheManager中移到DataLoader中,使得代码更加清晰易懂;
3636

37-
* ####4.10 增加使用Fastjson进行序列化的支持,同时也增加了对比较大的数据进行压缩的工具。
37+
* #### 4.10 增加使用Fastjson进行序列化的支持,同时也增加了对比较大的数据进行压缩的工具。
3838

39-
* ####4.9 去除默认的serializer和scriptParser,以便于与Spring 进行强解耦。
39+
* #### 4.9 去除默认的serializer和scriptParser,以便于与Spring 进行强解耦。
4040

41-
* ####4.8 优化JavaScriptParser 中的代码,并根据JDK版本,使用javascript 还是nashorn 引擎。
41+
* #### 4.8 优化JavaScriptParser 中的代码,并根据JDK版本,使用javascript 还是nashorn 引擎。
4242

43-
* ####4.7 修改说明:
43+
* #### 4.7 修改说明:
4444

4545
* 修改缓存预警时间值,加入-10~10秒随机数,避免缓存集中失效
4646
* 实现表达式引擎的可扩展性,默认还是使用SpringEL表达式引擎(com.jarvis.cache.script.SpringELParser),但可以自己实际情况进行扩展。扩展方法:实现com.jarvis.cache.script.IScriptParser,然后通过配置把实现的实例注入到AbstractCacheManager中的scriptParser属性即可。使用不同表达式引擎时,注意表达式的语言的区别。
4747
* 增加了JavaScript 表达式引擎实现:com.jarvis.cache.script.JavaScriptParser。如果项目使用JDK1.8的,想用JavaScript的话,建议使用Nashorn 来实现,性能会比较好。
4848

4949

50-
* ####4.6 修改说明:
50+
* #### 4.6 修改说明:
5151

5252
* @Cache中增加 expireExpression,实现通过表达式来动态获取expire 值;
5353
* @Cache 中增加 alarmTime。当缓存在alarmTime 时间内即将过期的话,会自动刷新缓存内容;
5454
* 解决 hessian2 无法序列化SoftReference 的bug;
5555

56-
* ####4.5 修改说明:
56+
* #### 4.5 修改说明:
5757

5858
* 调整CacheTask 中 Thread.sleep(0); 的位置;
5959
* 增加CacheChangeListener 接口,优化代码结构;
6060
* 使用SoftReference 管理Map中的缓存数据;
6161

62-
* ####4.4 修改说明:
62+
* #### 4.4 修改说明:
6363

6464
当遍历次数达到2000时,执行Thread.sleep(0); 触发操作系统立刻重新进行一次CPU竞争, 让其它线程获得CPU控制权的权力。
6565

@@ -68,58 +68,58 @@
6868
* 增加属性:int unpersistMaxSize,允许不持久化变更数(当缓存变更数量超过此值才做持久化操作)
6969
* 增加属性: boolean copyValue;是否拷贝缓存中的值:true时,是拷贝缓存值,可以避免外界修改缓存值;false,不拷贝缓存值,缓存中的数据可能被外界修改,但效率比较高。
7070

71-
* ####4.3 对 ConcurrentHashMap 缓存增加持久化功能。重启时会从本地磁盘加载缓存数据,避免因刚启动没有缓存数据,造成压力过大。
71+
* #### 4.3 对 ConcurrentHashMap 缓存增加持久化功能。重启时会从本地磁盘加载缓存数据,避免因刚启动没有缓存数据,造成压力过大。
7272

7373

74-
* ####4.2 改用JDK1.6进行编译;将isAutoload中的cache.expire() > 120 改为 cache.expire() >= 120;
74+
* #### 4.2 改用JDK1.6进行编译;将isAutoload中的cache.expire() > 120 改为 cache.expire() >= 120;
7575

7676
AutoLoadHandler中排序线程增加sleep,以节约系统资源
7777

78-
* ####4.1 提升缓存管理页的扩展性
78+
* #### 4.1 提升缓存管理页的扩展性
7979

8080
将获取AOP配置信息功能从 AdminServlet 中抽取出来,并使用CacheManagerConfig接口来获取。
8181

82-
* ####4.0 实现AOP的可扩展
82+
* #### 4.0 实现AOP的可扩展
8383

8484
受网友Rekoe 将AutoLoadCache 和 nutz整合的启发([https://github.com/Rekoe/AutoLoadCache](https://github.com/Rekoe/AutoLoadCache)),将AutoLoadCache 中的AOP相关功能进行抽取,以达到可扩展
8585

8686
* 把AOP拦截方法从AbstractCacheManager中抽取出来,并使用CacheAopProxyChain 和 DeleteCacheAopProxyChain 两个代理类进行封装拦截到的请求。
8787
* 实现了使用Aspectj进行AOP拦截:com.jarvis.cache.aop.aspectj.AspectjAopInterceptor
8888
* 升级时一定要注意配置文件的变化,可以参考[cache-example](https://github.com/qiujiayu/cache-example) 中的配置
8989

90-
* ####3.7 细节优化:
90+
* #### 3.7 细节优化:
9191

9292
* 调整 写缓存(writeCache)代码结构。
9393
* 将ShardedCachePointCut中hashExpire默认值设置为-1;
9494
* 解析SpEL表达式时,增加判断是否有返回值,避免在不能使用#retVal的地方,使用了#retVal
9595
* 将com.jarvis.cache.map.CachePointCut.shutDown() 改成 destroy()
9696

97-
* ####3.6 对@ExCache相关代码进行调整,自动加载时也对@ExCache进行处理。对一些变量增加volatile 修饰符,以便于其它线程的读取到最新的值。
97+
* #### 3.6 对@ExCache相关代码进行调整,自动加载时也对@ExCache进行处理。对一些变量增加volatile 修饰符,以便于其它线程的读取到最新的值。
9898

99-
* ####3.5 增加如下几个功能:
99+
* #### 3.5 增加如下几个功能:
100100

101101
* 注册自定义Spring EL表达式函数
102102
* 如果ShardedCachePointCut 中的 hashExpire 小于0则使用@Cache中设置的expire值,替换hashExpire值。
103103
* 增加@ExCache,用于增强@Cache 设置缓存功能。应用场景举例:我们使用getUserByName时,返回User的对象,其实也可以设置给getUserById的缓存中的,反过也是同样的道理,通过getUserById方法返回的数据,也可以设置给getUserByName的缓存中​,这样可以减少与DAO的交互了。
104104

105105

106-
* ####3.4 使用管道来操作Redis 的哈希表,减少与Redis的交互次数。
106+
* #### 3.4 使用管道来操作Redis 的哈希表,减少与Redis的交互次数。
107107

108-
* ####3.3 增加 Spring EL 表达式(Expression)缓存。
108+
* #### 3.3 增加 Spring EL 表达式(Expression)缓存。
109109

110110

111-
* ####3.2 进一步优化“拿来主义”机制
111+
* #### 3.2 进一步优化“拿来主义”机制
112112

113113
使用当前的ProcessingTO来做同步锁,把锁粒度降到了最低,以提升并发性能;删除并发线程的计数器;如果第一个线程执行时出现异常,那等待中的线程,也直接抛出异常,因为此时去执行DAO的出错的可能性非常大,会造成服务器压力过大。
114114

115115

116-
* ####3.1 优化“拿来主义”机制
116+
* #### 3.1 优化“拿来主义”机制
117117

118118
“拿来主义”机制指的是,当有多个请求去获取同一个数据时,我们先让其中一个请求先去DAO中获取数据,并放到缓存中,其它请求则等它完成后,直接去缓存中获取数据,通过这种方式减轻DAO中的并发。
119119

120120
但经测试发现,刚往Reids中放的数据,立即去取是获取不到数据的(无法命中),测试代码已经放到[cache-example](https://github.com/qiujiayu/cache-example) 中。优化后的方案是,不从远程服务器获取,而是从本地内存中获取第一个请求返回的数据。减少并发的同时,还能减轻网络压力。
121121

122-
* ####3.0 此版本做了大调整,有些功能已经不兼容老版本
122+
* #### 3.0 此版本做了大调整,有些功能已经不兼容老版本
123123

124124
不再使用默认缓存Key,所有的缓存都必须自定义缓存Key;原来使用$hash()来调用hash函数,改为使用#hash()进行调用。
125125

@@ -129,17 +129,17 @@
129129

130130
如果需要在MyBatis Mapper中使用@Cache@CacheDelete,则需要使用com.jarvis.cache.mybatis.CachePointCutProxy 来处理。
131131

132-
* ####2.13 优化多线程并发等机制, 代码调整如下:
132+
* #### 2.13 优化多线程并发等机制, 代码调整如下:
133133

134134
![Alt 优化多线程并发等机制](wait.png "优化多线程并发等机制")
135135

136136
由于我们这里要实现的功能是,当前的线程要等待前一个正在运行线程的结果,但我们不知道前一个线程的执行到哪一步。有可能在我们要执行wait时,已经完成notifyAll了。通过调整逻辑变得更加严谨。
137137

138-
* ####2.12 解决jdk1.8之前中 java.lang.NoSuchMethodError: java.util.Map.putIfAbsent 错误。
138+
* #### 2.12 解决jdk1.8之前中 java.lang.NoSuchMethodError: java.util.Map.putIfAbsent 错误。
139139

140-
* ####2.11 @CacheDeleteKey中keyType 设置default,以实现向下兼容。
140+
* #### 2.11 @CacheDeleteKey中keyType 设置default,以实现向下兼容。
141141

142-
* ####2.10 修改记录:
142+
* #### 2.10 修改记录:
143143

144144
* 优化ConcurrentHashMap 使用,将以下代码:
145145

@@ -159,7 +159,7 @@
159159

160160
* 放弃使用 @CacheDeleteKey中keyType, 直接使用它的value值来判断是自定义缓存Key,还是默认生成的缓存Key。所以keyType 变得多余了。
161161

162-
* ####2.9 修复以下几个问题
162+
* #### 2.9 修复以下几个问题
163163

164164
* @Cache(expire=0, waitTimeOut=500),当expire=0时,将设置为永久缓存;waitTimeOut 用于设置并发等待时间(毫秒)。
165165

@@ -172,21 +172,21 @@
172172

173173
* 优化AbstractCacheManager类的loadData方法中线程同步锁。
174174

175-
* ####2.8 com.jarvis.lib.util.BeanUtil.toString()方法中增加反射缓存,提升反射效率
175+
* #### 2.8 com.jarvis.lib.util.BeanUtil.toString()方法中增加反射缓存,提升反射效率
176176

177-
* ####2.7 当参数类型为 Class,自动生成的缓存Key会出问题。(感谢zhaopeng 提供的代码)
177+
* #### 2.7 当参数类型为 Class,自动生成的缓存Key会出问题。(感谢zhaopeng 提供的代码)
178178

179-
* ####2.5 2.6 当autoload=true,缓存Key中没有加上命名空间,对1.9及以上版本有影响
179+
* #### 2.5 2.6 当autoload=true,缓存Key中没有加上命名空间,对1.9及以上版本有影响
180180

181-
* ####2.4 Jedis更新到2.8
181+
* #### 2.4 Jedis更新到2.8
182182

183-
* ####2.3 AdminServlet 增加登录用户名和密码;
183+
* #### 2.3 AdminServlet 增加登录用户名和密码;
184184

185185
* ####2.2 解决Hessian不能正确序列化BigDecimal问题
186186

187-
* ####2.1 对Kryo进行测试,发现问题问题比较多,所以删除Kryo 支持,用户可以根据自己的情况实现ISerializer接口。优化HessianSerializer,提升性能,并将HessianSerializer作为默认的序列化和反序列化工具。
187+
* #### 2.1 对Kryo进行测试,发现问题问题比较多,所以删除Kryo 支持,用户可以根据自己的情况实现ISerializer接口。优化HessianSerializer,提升性能,并将HessianSerializer作为默认的序列化和反序列化工具。
188188

189-
* ####2.0 增加了Hessian 和 Kryo 序列化支持,还是使用JDK自带的处理方法。修改方法如下:
189+
* #### 2.0 增加了Hessian 和 Kryo 序列化支持,还是使用JDK自带的处理方法。修改方法如下:
190190

191191
<bean id="jdkSerializer" class="com.jarvis.cache.serializer.JdkSerializer" />
192192
<bean id="hessianSerializer" class="com.jarvis.cache.serializer.HessianSerializer" />
@@ -199,4 +199,4 @@
199199

200200
虽然Kryo效率比较高,但使用Kryo会出现的问题比较多,所以还是慎重使用,系统经常维护的就不太适合使用,经过测试,改变属性名称,或删除中间的属性等情况都可能反序列出错误的值,所以如果遇到有减少或修改的情况要及时清里缓存。如果是增加属性则会反序列化失败,这正符合我们的要求。
201201

202-
* ####1.9 增加了命名空间,避免不同的系统之支缓存冲突
202+
* #### 1.9 增加了命名空间,避免不同的系统之支缓存冲突

doc/deleteCache.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
##缓存删除
1+
## 缓存删除
22

3-
###通过删除缓存,实现数据实时性
3+
### 通过删除缓存,实现数据实时性
44

55
下面商品评论的例子中,如果用户发表了评论,要所有涉及到的前端页面立即显示该如何来处理?
66

@@ -26,7 +26,7 @@
2626
}
2727
}
2828

29-
###批量删除缓存
29+
### 批量删除缓存
3030

3131
在一些用户交互比较多的系统中,使用程序删除缓存是非常常见的事情,当我们遇到一些查询条件比较复杂的查询时,我们没有办法通过程序,反向生成缓存key,也就无法精确定位需要删除的缓存,但我们又不希望把不相关的缓存给误删除时。这时就可以使用下面介绍的批量删除缓存功能。
3232

doc/idea.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
###设计思想及原理
1+
### 设计思想及原理
22

33
如下图所示:
44
![Alt 缓存框架](FlowChart.png "缓存框架")
@@ -24,7 +24,7 @@ AutoLoadHandler(自动加载处理器)主要做的事情:当缓存即将
2424

2525
如果将应用部署在多台服务器上,理论上可以认为自动加载队列是由这几台服务器共同完成自动加载任务。比如应用部署在A,B两台服务器上,A服务器自动加载了数据D,(因为两台服务器的自动加载队列是独立的,所以加载的顺序也是一样的),接着有用户从B服务器请求数据D,这时会把数据D的最后加载时间更新给B服务器,这样B服务器就不会重复加载数据D。
2626

27-
##为什么要使用自动加载机制?
27+
## 为什么要使用自动加载机制?
2828

2929
首先我们想一下系统的瓶颈在哪里?
3030

@@ -35,22 +35,22 @@ AutoLoadHandler(自动加载处理器)主要做的事情:当缓存即将
3535

3636
注:上面提到的两种异步刷新数据机制,如果从数据层获取数据时,发生异常,则会使用旧数据进行续租。
3737

38-
##如何减少DAO层并发
38+
## 如何减少DAO层并发
3939

4040
1. 使用缓存;
4141
2. 使用自动加载机制,因“写”数据往往比读数据性能要差,使用自动加载也能减少写缓存的并发。
4242
3. 从DAO层加载数据时,**增加等待机制**(拿来主义)
4343

4444

45-
##使用规范
45+
## 使用规范
4646

4747
1. 将调接口或数据库中取数据,**封装在DAO层**,不能什么地方都有调接口的方法。
4848
2. 自动加载缓存时,**不能**在缓存方法内**叠加(或减)**查询条件值,但允许设置值。
4949
3. DAO层内部,没使用@Cache的方法,不能调用加了@Cache的方法,避免AOP失效。
5050
4. 对于比较大的系统,要进行**模块化设计**,这样可以将自动加载,均分到各个模块中。
5151

5252

53-
##为了能让更多人使用此项目,一直在为具有更好的扩展性而努力,在以下几个方法已实现可扩展:
53+
## 为了能让更多人使用此项目,一直在为具有更好的扩展性而努力,在以下几个方法已实现可扩展:
5454

5555
1. 缓存:现在已经支持Memcache、Redis、ConcurrentHashMap三种缓存,用户也可以自己增加扩展;
5656
2. AOP:项目中已经实现了Spring AOP的拦截。在Nutz官方项目中也实现了相关的插件:https://github.com/nutzam/nutzmore/tree/master/nutz-integration-autoloadcache

0 commit comments

Comments
 (0)