数据缓存是提高性能的有效手段,但缓存什么内容,如何缓存,这是重要的设计理念.也就是如何提高你的缓存命中率.
1.小批量数据完全缓存.
象字典数据,如省份,地区等,还有一个公司的部门,员工(如果一个公司员工超地一万人一般不会要你去设计,因为他们会找非常专业的人,但那些非常专业的人其实也是象我这么做的)这些数据应该一次缓存,用不了多少空间的,在现地动辄上G的内存中,放上几兆这样的数据,比你每次都从数据库提取性能要高多了.
2.Fat对象根据JVM需要得用软/弱/虚引用
这类对象是在构造时需要消耗一定资源,不应该每次都构造,但不用时又不能常时间放在内存中占用系统资的对象.那么我们可以根据需要取得他的软/弱/虚,即JVM没有回收他时,我们可以随时引用它,而JVM需要回收时,我们没的强引用句柄,你要回收就回收吧.我需要的时候再创建.
3.大批量数据遵循二八原则.
其实这也是二八原则的应用技巧.
百分之八十的请求只访问那百分之二十的常用数据,你放在缓存中,非常快.如果有查询不在缓存中的对象,比如根据一个ID在hashmap中get时为空,这时需要从数据库中获取,可能会比从缓存中慢10倍或100倍,但不要紧.即使查不出来也不要紧(那是不可能的)
因为这是一个用户心理的问题,他在正常的时候查询那80%的贴子都很快,一点,shua!,出来了.他的感觉就是你这个应用很快,如果有一个查询很慢(从数据库获取,其实即使慢10倍用户也感觉不了来,只是慢一些,因为0.1秒和0.01秒对用户是没有区别是),假如就是慢到几秒才出来,用户的感觉不是你的程序慢,可能是网络出问题了.因为他查询大多数的贴子很快啊.
所以一个好的设计方案不仅仅技术的问题,而且要充分考虑用户的感觉,这是我的UOP设计思想.比如论坛的贴子,大多数用户可以说90%的查询是请求最后10-30天内的数据,这部分数据只占数据库的百分之几到千分之几,所以把这个数据缓存在内存中,命中率是非常高的.
如果你的缓存是限定大小,那么在缓存达到限额时,以什么原则来删除原来的数据?
一次删除定额的数据应该在25%,这是装填因数的一般原则(0.75),而要删除的对象,基本是两个原则.一是时间最长的,是一引用最少的,对于link,list这样的数据结构,可以根据加入顺序认定时间顺序,但象hashmap这样的数据你没有办法认定时间,除非你加入的时候给这个地象加上一个属性.
其实更好的方法是加上引用计数,设计一个count.然后在每次get的时候强用加1
下面是我用来定制规定大小的缓存实现:
importjava.util.*;
publicclassLimitHashMap<K,V>extendsHashMap<K,V>{
privateintsize;
publicLimitHashMap(intsize){
super();
this.size=size;
}
publicVget(Objectkey){
Vv=(V)super.get(key);
if(vinstanceofDataBeanAdapter){
((DataBeanAdapter)v).refCount++;
}
returnv;
}
publicvoidshrink(){
if(this.size()<size)return;
if(size<200)return;
HashMaptmp=newHashMap();
Iteratori=keySet().iterator();
while(i.hasNext()){
Stringkey=(String)i.next();
tmp.put(((DataBeanAdapter)get(key)).refCount,key);
}
i=tmp.keySet().iterator();
Object[]array=tmp.keySet().toArray();
Arrays.sort(array);
Listt=Arrays.asList(array);
t=t.subList(0,size*25/100);
Object[]keys=t.toArray();
for(intx=0;x<keys.length;x++){
remove(tmp.get(keys[x]));
}
tmp.clear();
}
}