- 浏览: 360096 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (292)
- jbpm3.2 (4)
- hibernate (1)
- struts (2)
- spring (7)
- oracle (20)
- TCP/UDP (3)
- SpringSide (4)
- maven (4)
- eclipse插件 (11)
- 模板引擎 (2)
- javascript (4)
- 设计模式 (2)
- 工作中遇到异常及解决 (3)
- java文件编译问题 (1)
- ehcache应用 (1)
- java反射 (1)
- jbpm4 (1)
- Google-Gson (1)
- Jquery (6)
- XML (5)
- 工作记事 (2)
- flash builder 4 (1)
- Lucene (8)
- struts2 (1)
- AspectJ (1)
- spring proxool连接池配置 (1)
- StringUtils (1)
- spring security (5)
- JAVA点滴 (9)
- jbpm4.3 (1)
- ACL (0)
- 线程 (7)
- Java线程:新特征-线程池 (1)
- MemCache (5)
- compass (0)
- NIO (2)
- zookeeper (4)
- 并发 (2)
- redis (9)
- Nginx (5)
- jvm (1)
- 互联网 (24)
- shell (3)
- CAS (1)
- storm (4)
- 数据结构 (3)
- MYSQL (3)
- fsdfsdfsd (0)
- hadoop (19)
- hive (3)
- IntelliJ (3)
- python (3)
- 23423 (0)
- spark (7)
- netty (9)
- nmon (1)
- hbase (8)
- cassandra (28)
- kafka (2)
- haproxy (3)
- nodejs (3)
- ftp (1)
最新评论
-
记忆无泪:
遇到这个问题我用的sed -i 's/\r$//' /mnt/ ...
CentOS6 Shell脚本/bin/bash^M: bad interpreter错误解决方法 -
alenstudent:
Windows 下Nexus搭建Maven私服 -
dandongsoft:
lucene3+IK分词器 改造 lucene2.x+paoding -
duanyanrui:
学习了,支持
Google-Gson -
yscyfy:
这是你直接翻译过来的???
Google-Gson
OSCache 缓存重建在 Race Condition 下的 NRE 问题
一,现象:
高并发情况下,使用 OSCache 作为本地缓存中间件的前端服务,日志文件中会出现大量如下错误信息:
异常堆栈: |
java.lang.IllegalStateException: Cannot complete cache update - current state (2) is not UPDATE_IN_PROGRESS at com.opensymphony.oscache.base.EntryUpdateState.completeUpdate(EntryUpdateState.java:105) at com.opensymphony.oscache.base.Cache. completeUpdate (Cache.java:762) at com.opensymphony.oscache.base.Cache. putInCache (Cache.java:619) at com.opensymphony.oscache.base.Cache.putInCache(Cache.java:580) at com.opensymphony.oscache.general.GeneralCacheAdministrator.putInCache(GeneralCacheAdministrator.java:249) at com.opensymphony.oscache.general.GeneralCacheAdministrator.putInCache(GeneralCacheAdministrator.java:259) |
二,NRE 背景:
无论你使用哪一种本地缓存中间件,如果你缓存数据片段时设置了过期时间,都需要考虑缓存失效后的缓存重建(repopulate the cache )场景。
进一步必须考虑 Race Condition (同进程下多线程,或不同进程)下如何重建。
也就是说,某个线程在重建缓存过程中,其他线程发现缓存不存在或已过期,该如何处置?
从2005 年OSCache 的版本到现在,它一直这么声称:
* @throws NeedsRefreshException Thrown when the object either
* doesn't exist, or exists but is stale. When this exception occurs,
* the CacheEntry corresponding to the supplied key will be locked
* and other threads requesting this entry will potentially be blocked
* until the caller repopulates the cache . If the caller choses not
* to repopulate the cache, they <em>must</em> instead call
* {@link #cancelUpdate(String)}.
即,
当 key 不存在,或者存在但数据过期(stale )时,
调用 getFromCache 函数时会抛出 NRE 异常;
当异常发生时,
对应于这个 key 的 CacheEntry 将被锁住,
而请求这个 entry 的其他线程将可能(注意,仅仅是可能) 被阻塞,直到调用者重建缓存。
如果调用者没有选择重建缓存,必须 调用 cancelUpdate 函数来“Cancels any pending update for this cache entry ”。
三,缓存重建的 OSCache 官方推荐做法:
读取缓存遇到 NRE 异常时,OSCache 官方推荐的做法是:
1 String myKey = "myKey";
2 String myValue;
3 int myRefreshPeriod = 1000;
4 try {
5 // Get from the cache
6 myValue = (String) admin. getFromCache (myKey, myRefreshPeriod);
7 } catch ( NeedsRefreshException nre) {
8 try {
9 // Get the value (probably from the database)
10 myValue = "This is the content retrieved.";
11 // Store in the cache
12 admin. putInCache (myKey, myValue);
13 } catch (Exception ex) {
14 // We have the current content if we want fail-over.
15 myValue = (String) nre.getCacheContent();
16 // It is essential that cancelUpdate is called if the
17 // cached content is not rebuilt
18 admin. cancelUpdate (myKey);
19 }
20 }
即,本线程先试图重建缓存,如果再次发生异常,则本线程(不管三七二十一)直接调用 cancelUpdate 函数。
现在的一些 OSCache Manager 工具类, get 方法也就实现为一旦捕获 NRE 异常就直接 canelUpdate :
1 public OSCache get(String key, int myRefreshPeriod){
2 try {
3 return (OSCache) this .admin. getFromCache (key,myRefreshPeriod);
4 } catch ( NeedsRefreshException ex){
5 this .admin. cancelUpdate (key);
6 return null ;
7 }
8 }
四,OSCache 在 Race Condition 下缓存重建的特殊场景
简单地说,就是:
线程1 正在重建缓存;
线程2 读取缓存时得到 NRE 异常,主动 cancel update ;
线程1 重建缓存完毕,却发现状态被改为了 UPDATE_CANCELLED ,与期望不符,于是抛出异常 java.lang.IllegalStateException 。
具体过程如下:
(0 )缓存过期;
(1 )线程 T1 获得 update lock ,并开始调用 putInCache 函数 ;
(2 ) 线程 T2 在 T1 没有结束 update 之前,也开始 getCacheEntry 了;
(3 )T2 调用的 getCacheEntry 函数捕获 NeedsRefreshException 异常;
(4 )T2 调用 cancelUpdate 函数来“取消所有试图更新本 cache entry 的操作”, 于是 EntryUpdateState 变为 UPDATE_CANCELLED ,它是一个正整数 2 ;
(5 )T1 其实已经重建了缓存 ;
(6 )T1 随后调用 completeUpdate (EntryUpdateState.java,93 行) 来通知那些等着本次更新操作的线程; 但 completeUpdate 函数却发现当前 EntryUpdateState 居然不等于 UPDATE_IN_PROGRESS (对应0 ),而是 UPDATE_CANCELLED (对应2 ),于是抛出异常 。即下面代码抛出的 IllegalStateException 异常,文字通常为:“ Cannot complete cache update - current state ( 2 ) is not UPDATE_IN_PROGRESS ”,其中的 2 就是指 UPDATE_CANCELLED :
1. /**
2. * Updates the state to <code>UPDATE_COMPLETE</code>. This should <em>only</em>
3. * be called by the thread that managed to get the update lock.
4. * @return the counter value after the operation completed
5. */
6. public int completeUpdate() {
7. if (state != UPDATE_IN_PROGRESS) {
8. throw new IllegalStateException( "Cannot complete cache update - current state (" + state + ") is not UPDATE_IN_PROGRESS" );
9. }
10.
11. state = UPDATE_COMPLETE;
12. return decrementUsageCounter();
13. }
总之,按目前 OSCacheManager 的做法,在高并发环境下,一旦一个 OSCache 缓存失效,而缓存的数据片段很大,那么很有可能让其他线程在 getFromCache 时有机会捕获 NRE 异常,最终导致做缓存重建的线程抛出 IllegalStateException 异常,虽然此时缓存已经重建完毕。
发表评论
-
无备案小站的最好的广告收益来源
2020-08-09 10:52 207现在无备案的无名小站运营维持真的很难,广告难接,各大广告联盟 ... -
老番茄访问IP突破1W
2019-11-13 10:19 5感谢大家,老番(www.laofanqie.com) 用户访问 ... -
Nmon工具的使用以及通过nmon_analyse生成分析报表
2016-09-07 11:44 357Nmon工具的使用以及通过nmon_a ... -
用“逐步排除”的方法定位Java服务线上“系统性”故障
2015-08-27 19:12 703一、摘要 由于硬件问题、系统资源紧缺或者程序本身的BUG, ... -
simple-spring-memcached简介
2015-07-09 15:06 389memcached是一款非常优秀的分布式缓存工具,有效提升了 ... -
Tomcat 7 的新JDBC连接池的使用说明
2015-06-28 22:55 1277Tomcat 7 的JDBC连接池实 ... -
CentOS安装JDK1.6
2015-04-01 11:56 10011、获得程序包 jdk-6u16-dlj-linux- ... -
abtest
2014-12-01 11:51 1000Apache服务自带了应该用于压力测试的工具ab(Apach ... -
mysql优化
2014-08-29 11:36 57719195.cn 手游网站mysql 优化一: v ... -
怎么快速搭建游戏网站,手游网站,手机应用网站??
2014-07-28 13:14 1551大家好,作为19195手游 ... -
mysql备份还原
2014-06-13 11:31 2备份数据库 -
centos6利用yum安装php mysql
2014-05-18 13:47 865一、安装mysql #yum -y install my ... -
Centos如何挂载硬盘
2014-05-15 13:03 732远程SSH登录上Centos服务器后,进行如下操作提醒:挂 ... -
远程监控JVM--VisualVM
2013-01-09 18:26 1123对于使用命令行远程监控jvm太麻烦?那可以试试sun ... -
聊聊并发(五)原子操作的实现原理
2013-01-07 17:50 01 引言 原子(atom)本意是“不能被进一步分 ... -
聊聊并发(四)深入分析ConcurrentHashMap
2013-01-07 17:48 0术语定义 术语 英文 解释 哈希算法 ... -
聊聊并发(三)Java线程池的分析和使用
2013-01-07 17:45 8041. 引言 合理利用线程池能够带来三个好处。第一 ... -
聊聊并发(二)Java SE1.6中的Synchronized
2013-01-07 17:42 8811 引言 在多线程并发编程中Synchronized一 ... -
聊聊并发(一)深入分析Volatile的实现原理
2013-01-07 17:41 777作者http://ifeve.com 引言 在 ... -
虚拟机stack全解析
2013-01-07 14:40 1277转载 通过jps -lv 获取到本地的一个JVM实例进 ...
相关推荐
oscache缓存技术,压缩包中有详细代码及步骤
这里结合 天气预报的webservice 展示了OsCache框架的具体使用方法 项目可直接运行 ,代码简洁清晰
oscache缓存技术入门实例
Hibernate OSCache缓存 Hibernate OSCache缓存
oscache缓存使用总结
OSCache缓存框架的简单用法,希望对大家有所帮助!!!
一个OSCache缓存技术的关键zip包
OSCache标记库由OpenSymphony设计,它是一种开创性的缓存方案,它提供了在现有JSP页面之内实现内存缓存的功能。OSCache是个一个被广泛采用的高性能的J2EE缓存框架,OSCache还能应用于任何Java应用程序的普通的缓存...
描述了oscahce在JAVA开发中的应用和配置说明
1、OSCache是什么? 2、OSCache的特点 3、有关“用OSCache进行缓存对象”的研究
oscache,java,缓存机制的使用
OSCache标记库由OpenSymphony设计,它是一种开创性的缓存方案,它提供了在现有JSP页面之内实现内存缓存的功能。OSCache是个一个被广泛采用的高性能的J2EE缓存框架,OSCache还能应用于任何Java应用程序的普通的缓存...
二级缓存插件OScache配置,很好的学习资料
NULL 博文链接:https://davidxiaozhi.iteye.com/blog/1045223
oscache-java缓存框架插件和安装教程,使用教程一步到位
NULL 博文链接:https://baobeituping.iteye.com/blog/748346
NULL 博文链接:https://hihitiger.iteye.com/blog/966649
NULL 博文链接:https://yanxiansheng.iteye.com/blog/1636690
具体使用请参考:https://blog.csdn.net/w13240362354/article/details/51934056/
看就知道......................