您当前的位置: 首页 » asp.net编程学习 » oschina 上的一种双缓存思路

oschina 上的一种双缓存思路

举个例子:oschina 的首页,访问量很高,这个页面必须得缓存,oschina 使用的是 ehcache。

一般我们的缓存伪码如此:

List<T> objs = (List<T>)CacheManager.get(cache_region, key);
if(objs == null){
    objs = database_query(beanClass, sql, params);
    CacheManager.set(cache_region, key, (Serializable)objs);
}
return objs;

问题是一旦缓存失效需要从数据库重新加载数据的时候,大量的并发数据库访问会导致响应超级慢,也就是所谓的雪崩。

目前我们对这个问题的处理方法,我简单的说一下思路,具体的代码等有空再整理出来

假设我们前面举的例子中所使用的缓存region(region1),设置了自动失效时间为5分钟,相当于说每5分钟就会有一次发现访问首页很卡。因此引入了第二个缓存 region (region2) ,这个缓存的对象不会自动失效,也就说该区域的数据长期有效。

region2 的配置:

<cache name="icache-global"
maxElementsInMemory="100"
eternal="true"
overflowToDisk="true"
/>

引入了第二个长效的region后,数据的读取流程是这样的:

1. 从 region1 读取数据,有则直接返回

2. region1 没数据则启动数据更新线程(下面介绍),然后从 region2 读数据,有则返回

3. region2 也没有数据
这种情况属于系统刚刚启动,缓存还没有填充数据的情况,没办法,这时候肯定会卡,或者你应该在系统启动的时候,自行填充一下数据,很简单,我一般在tomcat启动后,用命令访问下首页就有了缓存数据。

这样做的目的是为了正常的缓存失效后,无需等待重新从数据库中获取数据,而是直接在 region2 中获取数据并返回。因此对用户来讲,不会感觉请求被堵塞。

虽然请求顺畅了,但是数据还得更新,因此重要的还是启动数据更新线程是如何处理的。

线程本身所执行的方法很简单,无非就是到数据库中读取数据,然后将数据填充到 region1 ,但记得要同时填充到 region2,以确保下次缓存失效时,获取得到的是最新的数据。

就这么简单,其实也可以工作,但会有一个问题:假设缓存失效的时候,同时来了100个请求,那么这100个请求会同时启动100个数据更新线程,这100个数据更新线程会到数据库执行同样的SQL语句获得同样的结果,因此这种做法对数据库的压力并没有降低。

于是我需要在线程的执行方法里做一些调整,下面是伪码:

String data = CacheManager.get(String.class, region1, key);
if(data == null){
ReentrantLock lock = g_locks.get(key);

if(!lock.tryLock())
  return null;

try{
//1. 执行SQL查询获取数据
//2. 数据填充到 region1
//3. 数据填充到 region2
}finally{
    lock.unlock();
 }
}

首先还是要判断下缓存数据是否已存在,然后使用了一个 ReentrantLock 锁对象来控制不让多余的线程去执行数据更新过程。

这只是个大体的思路,仅供参考,目前已经在 oschina 上使用。

别提什么页面静态化,我对那个一点都不感冒。

下一篇:c#IndexOf用法
留下脚印压缩包密码:sosuo8
名字:
全部评论:
loading...
申明:本站部分文章来自网络,由于各种原因对文章的来源无从考究,如果您是“ oschina 上的一种双缓存思路 ”的原作者,若侵犯您的版权,请与我联系!联系方法:email:ahuinan@21cn.com  QQ:106494262
文章档案
  • 作者:佚名
  • 来源:转载
  • 日期:2011/12/9 14:08:00
  • 点击:loading...
网友投票(您觉得这篇文章怎样?)
loadding...请稍侯......