缓存漫谈

缓存是在提升系统响应时常用的一种技术,在我之前的blog中也提及过好几次这部分的技术,今天还是想从缓存涉及的一些方面再次的去谈谈,在系统缓存上通常采用的是有页面缓存、处理缓存和数据缓存这三种具体的类别,应该说这三种缓存在实现上还是稍有不同,尽管底层的缓存实现是一样的。
页面缓存
页面缓存是指对页面中的内容片断进行缓存的方案。比如页面中有一个部分是显示栏目中的内容的,那么就可以缓存这个部分,在进行第二次请求的时候就直接从缓存中取出这部分的内容(其实就是这部分的html了),这种情况下,缓存的作用其实非常明显,在典型的action+service+dao这样的结构中,在采用页面缓存后就意味着不需要经过action、service、dao这些层次的处理了,而是直接就返回了,对于系统响应速度的提升来说是非常明显的。
页面缓存通常采用oscache来进行实现,oscache提供了一个jsp tag,可通过这个tag来包含需要缓存的内容部分,当然,缓存的这个内容部分需要有对服务器的请求或逻辑计算等的,可想而知,去缓存一段静态html是没有意义的。
其次需要定义缓存的这段内容的key,例如我们要去缓存页面中某个栏目的某页的内容,对于这段内容而言唯一的key就是栏目ID以及当前页数,这样就组成了这段缓存的key了,其实这个部分看起来好像是很简单,但有些时候会很麻烦,要仔细的想清楚这段内容的唯一的标识的key到底是什么,^_^,通常的做法其实可以从action中需要获取的参数或service接口的参数来决定....
页面缓存中还需要做的一个步骤就是通知缓存需要更新,页面缓存和其他缓存稍有不同,需要告诉它,这个时候不能再使用缓存中的内容了,需要从后台再重新获取来生成新的缓存内容,这个其实很简单,因为很难在后台发生变化的时候自己来更新缓存的内容,只能是去通知它,然后让它再次发起请求来生成新的内容放入缓存中。
页面的缓存的使用对于系统的响应速度确实会有很大的提升,在实现页面缓存时最麻烦的主要是缓存的key的定义以及缓存更新的通知,缓存key的定义这个自然框架是没法解决的,不过缓存更新的通知其实在框架中可以考虑一种通知模型的,^_^,就像事件通知那样........在实际的项目中,可以自己去实现一个这样的通知模型或者就是简单的采用单例方式来标识某个key是否需要更新。
页面缓存在实际的项目中使用非常的多。
处理缓存
处理缓存是指对于action、service、dao或者系统层次中的某方法进行缓存,说直接点,就是对某个类的某个方法的结果做缓存,这样在下次进行完全相同的请求的时候就可以直接取缓存了,这种响应速度的提升也是非常明显的。
处理缓存在现在的情况下其实采用任务的缓存工具包都可以实现,如oscache、ehcache、jbosscache等,但目前还没有处理缓存框架的出现,这个和处理缓存是否应该存在的意义也是有关系的,处理缓存框架要做到的其实就像拦截一样的方式,和oscache tag类似。
同样,处理缓存的麻烦也在于怎么样去定义这个key,很多情况下可以根据方法的输入作为key,方法的输出作为key的值,但也会有其他一些复杂的情况,这个时候定义key就会变得复杂些了。
处理缓存同样有通知更新缓存的情况,和页面缓存基本是一样的。
应该说,处理缓存和页面缓存非常的相似,从实现上来说基本是完全一致的,在使用上来讲处理缓存使用的好像不多。
数据缓存
数据缓存估计大家都很熟悉,就是对系统的数据进行缓存的方式,典型的就是Hibernate的一级、二级数据缓存。
数据缓存在实现上如果是用hibernate的话更多的是直接使用hibernate的一级、二级以及查询缓存,如果自己要实现的话可以去参考hibernate的实现机制。
数据缓存的key在一级、二级缓存中采用的都是数据的标识键的值的方式,查询缓存采用的是查询参数、查询语句的方式。
数据缓存的更新则是hibernate在进行存储时直接更新缓存的内容,而对于查询缓存则是采用全部直接清除的方式,这样在下次进行查询时自然会重新去查询,^_^,大家可能会想,为什么页面缓存和处理缓存不采用这样的方式来实现缓存的更新,稍微想想就知道了,在后台发生改变的时候其实是不知道需要移除哪些key的,所以hibernate为了避免这个麻烦,采用的就是当数据一旦发生改变的时候就清除全部的查询缓存,而不是只去清除相关的缓存,其实这里可以采用一种订阅式的模型,呵呵,当然,也增加了框架的复杂度。
数据缓存使用的应该是最多的,效果也是很明显的。

以上三种缓存是目前缓存实现时通常碰到的三种状况,里面按使用的多少来排序应该是:数据缓存、页面缓存和处理缓存;实现的难度上从难到易的顺序应该是:处理缓存、页面缓存、数据缓存;对于系统响应速度提升的效果来说从最好到好的顺序应该是:页面缓存、处理缓存、数据缓存。

posted on 2006-06-02 23:38 BlueDavy 阅读(4387) 评论(9)  编辑  收藏 所属分类: Java

评论

# re: 缓存漫谈 2006-06-03 12:03 zkjbeyond

hibernate虽然提供比较完善的一级、二级数据缓存机制。但对于开发人员使用起来很不方便,也比较复杂。

一级缓存也就是session级别的,感觉作用很小,基本上命中率不高。因为一个session执行相同查询几率较小。
而二级缓存也只能在 session.load,session.iterate,lazy load中才用到,可一般人代码直接用 session.list();查询。

所以一般项目,我都把这类缓存放到逻辑层,也是“处理缓存”,用spring+ehcache效果不错。

  回复  更多评论   

# re: 缓存漫谈 2006-06-03 13:04 C[ETI]O@quaffsoft

@zkjbeyond

有没有可能对DetachedCriteria这样的查询做缓存?  回复  更多评论   

# re: 缓存漫谈 2006-06-03 13:28 BlueDavy

@zkejbeyond
自己做处理缓存你是采用拦截的方式还是什么别的方式呢?

@quaffsoft
应该是可以的吧,hibernate做查询缓存是根据查询的参数、语句等来做的,不过我对DetachedCriteria那种方式不熟......无法判断  回复  更多评论   

# re: 缓存漫谈 2006-06-03 13:30 BlueDavy

其实Hibernate的一级、二级缓存的作用还是很明显的,只要熟悉hibernate对于一级、二级缓存的处理机制就OK了  回复  更多评论   

# re: 缓存漫谈 2006-06-03 15:36 zkjbeyond

@C[ETI]O@quaffsoft

其实我自从hibernate2.17后项目中就没用过了。

1 相信很多人和我一样,用hibernate,也用spring来管理,当用spring,hibernateSupport时,很多hibernate Session的原生方法都不方便访问,当然可以用inner class实现。我除了分页用inner class外,一般直接用spring方法。
2 很多mis系统,表字段用了数据字典,如果用hiberbate处理many to one关系是很恶心的事(有个同事这样干过)。如果PO/VO得到的是字典值,如 address1="33012323",而它代表**市**区,可能在业务层需要对VO翻译一下,那么你在dao做cache,还不如在logic层cache呢。

所以我一般不用hibernate cache .用spring AOP方式 做 Cache.

http://www.springframework.org/docs/api/org/springframework/cache/ehcache/package-summary.html
http://www.onthoo.com/blog/programming/2004/09/spring-aop-cache.html
http://opensource.atlassian.com/confluence/spring/display/DISC/AOP+Cache

其实就是上面例子扩展了更新通知。

  回复  更多评论   

# re: 缓存漫谈 2006-06-03 16:52 guitarpoet

@BlueDavy

Hibernate的二级缓存机制最好还是不要用,因为一个项目不可能保证所有的数据库访问全部交由Hibernate进行处理,而越过Hibernate 访问数据库的方式很容易就造成了Hibernate的缓存数据不一致的问题。

另外对于Hibernate的内置缓存是不支持集群的,即使采用oscache这种支持集群的Cache,你也会发现,由于缓存本身实现的特殊性,服务器端压力的增加是很多的,也就是说,如果使用不当,对服务器端是压力的增大而不是减少。

而使用得当的必须是对Hibernate熟悉的并且对JavaEE技术和服务端技术非常了解的开发人员,对于业务开发人员而言,这种要求过高了。

如同HttpSession的实现也是争论不休一样,Hibernate二级缓存能够给你带来的优点不多,但是给你的系统带来的隐患却不少,我的建议是,尽量不要用。只有在非常需要的情况下慎用。

如果你有项目开发的经验,那么你就会明白,其实系统的更多的瓶颈是在于基本的编程错误的设计和技术的错误使用方式,对于二级缓存这种只是需求频率不足10%的需要考虑的问题,大可在系统出现致命的瓶颈问题时再考虑

至于你说的处理缓存和页面缓存,他们的最应该出现的地方应该是,耗费资源的几乎不发生改变对象的构建(比如一些图形、PDF或者需要通过脚本解析、远程服务调用而获得的Java对象),这些东西由于构造它们非常耗费服务器资源,而重复构造更是服务器资源的浪费,那么缓存它们是必不可少的

但是,别忘了,对于缓存而言,集群内部同步和内部对象失效和刷新机制也不是什么好玩的东西。想当然的认为使用它就会减轻系统的负担的想法是不负责任的。必须在压力测试的前提下进行试验。

所以,我认为:除了耗费资源的几乎不发生改变对象之外,其他所有的缓存(尤其是Hibernate的查询缓存)都应该经过试验后慎用,最好是不用,只在出现性能瓶颈的时候通过AOP的形式加入进去,我认为Spring框架就比较推荐这种方式   回复  更多评论   

# re: 缓存漫谈 2006-06-03 20:34 BlueDavy

@guitarpoet
^_^,其实数据缓存的方式自然不会有页面缓存和处理缓存带来那么明显的提升,不过在很多场合下效果还是不错的,当然,如果系统不是完全用Hibernate的话,自然是不能用Hibernate的二级缓存。
对于页面缓存和处理缓存,它们的效果是很明显的,在我以前的一个项目中,在采用页面缓存后整体页面的刷新速度从10秒左右提升到了1秒以内...
缓存在集群下的测试是要特别注意的...

缓存在性能提升的时候是很重要的一种手段,很多时候通过程序去提高效率的方式不如采用简单的缓存策略去实现,毕竟硬件的代价比研发付出的成本低很多。

Spring AOP实现cache的方式一直想尝试的...处理缓存对于系统效率的提升肯定是非常明显的...
  回复  更多评论   

# re: 缓存漫谈 2006-06-03 21:35 BlueDavy

@zjkbeyond
看了下spring aop cache的几篇文章,确实不错,不过要是那个缓存框架完整就好了,^_^,其实就是要加个通知模型而已..  回复  更多评论   

# re: 缓存漫谈 2007-07-27 17:21 sitinspring

好文章,做个记号,有空细看.  回复  更多评论   


只有注册用户登录后才能发表评论。


网站导航:
 

公告

 









feedsky
抓虾
google reader
鲜果

导航

<2006年6月>
28293031123
45678910
11121314151617
18192021222324
2526272829301
2345678

统计

随笔分类

随笔档案

文章档案

Blogger's

搜索

最新评论

阅读排行榜

评论排行榜