读书人

并发环境上JavaWeb的缓存过期策略

发布时间: 2012-09-04 14:19:30 作者: rapoo

并发环境下JavaWeb的缓存过期策略

最近公司的几个平台经常在高峰期挂掉,经检查是因为数据库有太多Slow Query导致的,当初也没细想为什么会出现这么多的Slow Query,而且大部分还是相同的查询,单独拿某个Sql查询消耗时间大都在毫秒级别,为了安全起见,对所有Sql又做了一次优化,并且写了监测脚本,定期杀掉太慢的查询,但这样的话还是会影响到有些用户的访问。

? ? ?网站采用了Spring+SpringJDBC+Servlet+Memcache的架构,数据库是一对Master-Slave的Mysql,有大概几十个接口和4个网站共用这个数据库,采用了proxool数据库连接池。因为数据的实时性,所以CDN和Memcache的缓存过期时间都是在5分钟左右,好了环境介绍完毕,开始着手解决这个问题。

? ? ?为了模拟高峰期并发环境,使用Apache的ab命令对网站进行压力测试,此时测试环境是没有Cache的,果不其然,log里出现了数据库连接已经占满的异常信息,猜测是在大并发环境下,缓存正好过期,所有的访问都去请求数据库导致连接占满,经过考虑,有了以下解决方案,不足之处请说明。

?

备注:以下过程中出现的client为Memcache的实例,省略了初始化的过程,所用到的Memcache库为xmemcache1.3.3

?

1、? 增加数据备份,防止缓存过期后同时请求数据库

2、? 增加同步机制,保证并发环境下只有一个用户在更新数据

3、? 增加数据更新回调接口,当缓存过期后,调用接口更新数据

4、? 验证数据正确性,防止在更新pojo类时出现的ClassCastException

?

定义数据更新回调接口:

12 + object.toString() + " Error: " + e.getMessage());13 }14 }

操作线程池更新缓存

 1 Map<String, Object> args = new HashMap<String, Object>(); 2 args.put("page", page); 3 args.put("sort", sort); 4  5 Map<String, Object> data = (Map<String, Object>) MemcachedMgr.get("your key", args, new MemcachedCallback() { 6              7             public Object update(Map<String, Object> args) { 8                 Map<String, Object> map = new HashMap<String, Object>(); 9                 //所有的参数都可以从args拿到10           //TODO 查询数据库,并将结果存入map11                 return map;12             }13             14             public boolean validate(Object data) {15                 Map<String, Object> map = (Map<String, Object>) data;16                 try {17                     //TODO 通过强制类型转换来判断是否有转换错误,或者自定义校验18                 } catch (Exception e) {19                     return false;20                 }21                 return true;22             }23         });24         //TODO request.setAttribute & 转发


算是告一段落,开始压力测试,模拟300个并发测试该接口,数据库只有一个process,而且QPS基本没什么变化。

据同事讲,缓存过期请求击穿数据库这种情况叫“Dogpile”,google了下dogpile,只发现hibernate里自带了DogpilePrevention,百度没有找到相关资料……

采用map存放页面所需所有数据感觉上还是不太好,暂时没想到更好的办法,先这么着吧,如果有好的解决方案,请大家不吝指教。

读书人网 >Web前端

热点推荐