论坛首页 Java企业应用论坛

应用层缓存 VS ORM缓存

浏览 16498 次
精华帖 (0) :: 良好帖 (1) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-06-02  

   最近做一个比较大的电子商务项目,预计每天订单量将在5万多单,客服人员需要频繁的下单、查询订单、操作订单,客人预订完订单后,会立即进入处理流程,为了提高服务质量,要求流水化作业,平均要在40分钟-80分钟内处理完订单,对于疑难订单要到第二天,才能处理完。所以订单在创建后,会在短时间内,被频繁的修改和查看。
  由于在项目中ORM层主要是基于Hibernate框架,所以在调优时,很自然的就想到打开Hibernate的二级缓存,以次来减小由于Load 订单大对象时N+1次查询给数据造成的压力,自己做的测试效果也非常好,也顺利通过压力测试。
  但在上线时,性能却并不佳,经过分析业务的操作特点,查找原因有以下几占:,

    1.但由于中台每天在工作当中,频繁的批量分配工单,
   
    因为要批量将订单分配给某一个工作人员处理,在代码当中执行了一个bulkUpdate的操作:
  template.bulkUpdate("update order set owner = ? where id in (?, ?,?)");
   
    这时Hibernate会直接将Order对象的二级缓存清楚掉。
    由于二级缓存,总是被刷掉,再查询时,需要重新从数据库Load,所以二级缓存变相直接起的作用很少。

    2.由于工作人员在处理订单时,每一次查看之后,都有更新操作,在更新之后,订单被清除缓存,下一组人在处理订单时,又得重新LOAD,所以效果并不好。
    3.无论是白盒测试,还是压力测试时,所基于的案例太过于简单,没有更深入的模仿业务操作,对于压力测试的脚本,也很难精确的模拟出真实的流程化的业务操作过程。


    开始想到,直接获得Session,直接使用JDBC来编写更新代码,并在更新后,使用sessionFactory.evict(Order.class, id);来有目标的逐个清除特定的对象,以避免全部清楚缓存。
    但样做,会对DAO层,修改过大。

    由于整个模块最核心的商业对象就是订单,最后决定在Service层对订单开小灶,对订单缓存的单独的定制处理。

    我觉得应用缓存存在以下优点:
      1。速度要快于ORM缓存,
      2。对于缓存的控制权更大,可以直接控制缓存工具的API进行操作,可以避免一些盲目清除的操作。
      3。更灵活的控制缓存中对象的失效,如根据事件来清除缓存,如订单的处理流程结束时,将该订单从缓存中清除掉,
      4。在更新数据库时,不是直接清除缓存,而是更新缓存(尽管这有风险),当业务层抛出异常时,才去清空缓存,避免由于频繁更新,而清空缓存。

    缺点:
     1。订单的更新操作,必须是单点的,只能通过IOrderService提供的接口,进行更新操作,否则数据不一致的风险较大。
     2。想要透明化,需要有一定的代码工作量,不容易达到ORM缓存最强大的那种透明化和灵活可配置,你可以使用Ehcache, 也可以选Jboss,有钱的话,可以用Tangosol。

     3。如果不对第三方缓存包,进行一定的封装的话,会直接耦合于第三方的缓存包,不能像Hibernate那样,灵活选择和配置缓存工具。
     4。对业务层代码有一定的侵入

   

    目前的方案是采用应用层的现代化,同时使用如Proxy模式来提供透明化的设计,

      IOrderService -》  OrderService -》 CacheableOrderService

    通过Spring的Bean配置,一样可以实现透明化的操作。


    结论:
    1。缓存的清空与更新,要尽量精确的去操作受到更新影响的对象,而不是全部搞掉。
      在Hibernate当中,也提供了sessionFactory.evict(class, id)这样细粒度的清空缓存对象的方法。
          sessionFactory.evice(class)的操作,要看这样的操作是否频繁,如果频繁,对于缓存的作用就会大大的折扣。
   2。如果缓存对象过多,对于失效的算法与处理,要与业务对象的特性紧密的联合起来,通过事件来驱动对象的失效。
   3。对于商业对象的缓存,必须要深刻分析对象的生命周期,业务特性。
   4。对于数据不一致的风险,要有足够的认识与预防手段。
   5。合理的估计订单对象的大小,分配足够的内存
   6。如果只使用中心缓存,只能减小数据库的压力,对于网络带宽的压力,还是有的,速度上也远远逊于本地缓存的效果,所以要结合本地缓存+中心缓存的策略方案,即提高速度,避免群集复制时的瓶颈。


    

 

 

 

 

  

   发表时间:2007-06-02  
不要使用bulk update.使用jboss cache不要使用readwrite cache
0 请登录后投票
   发表时间:2007-06-02  
可以用一下BDB做Cache,使用Quary定时将这些数据持久化到数据库.
可以提高很多的效率
0 请登录后投票
   发表时间:2007-06-02  
这种应用场景下一次需要分配多少个任务,有必要用bulkUpdate这个难用的东东么?

引用

4。在更新数据库时,不是直接清除缓存,而是更新缓存(尽管这有风险),当业务层抛出异常时,才去清空缓存,避免由于频繁更新,而清空缓存。

在核心的订单模块写入缓存??难道你用的缓存支持事务隔离?不怕出人命啊...
0 请登录后投票
   发表时间:2007-06-02  
每天五萬筆資料, 算是小數目, 但
搞這麼多 ORM的東西了, 請問你們的機器多大?
level 2 cache 吃多少memory?
0 请登录后投票
   发表时间:2007-06-02  
大型的电子商务系统不适合使用Hiberante这些持久层框架,
0 请登录后投票
   发表时间:2007-06-02  
引用
    因为要批量将订单分配给某一个工作人员处理,在代码当中执行了一个bulkUpdate的操作:
  template.bulkUpdate("update order set owner = ? where id in (?, ?,?)");
   
    这时Hibernate会直接将Order对象的二级缓存清楚掉。
    由于二级缓存,总是被刷掉,再查询时,需要重新从数据库Load,所以二级缓存变相直接起的作用很少

用bulkUpdate肯定要清除二级缓存了 否则会导致数据不一致
我觉得最好还是测试一下循环update和bulkUpdate这两者的性能, 在数据多和数据少的时候 差别有多大 然后结合项目实际情况决定用那种那种
在没有测试性能之前 盲目的优化不提倡
0 请登录后投票
   发表时间:2007-06-03  
Readonly 写道
这种应用场景下一次需要分配多少个任务,有必要用bulkUpdate这个难用的东东么?




bulkUpdate 是spring封装的方法,真正调用的仍然是Hibernate的

 query.executeUpdate(hsql);方法。

 如果批量更新,又使用Hibernate, 请问用什么方法,hibernate可以明确的清楚发生更新影响的对象?

引用

在核心的订单模块写入缓存??难道你用的缓存支持事务隔离?不怕出人命啊...


 

 应用层缓存,也就是缓存的行为发生应用层,事务是在DAO层完成的,这与事务隔离没有关系,
 更新缓存,一定是在更新数据库成功之后,返回应用层,才进行的操作。

 
0 请登录后投票
   发表时间:2007-06-03  
Lordaeron 写道
每天五萬筆資料, 算是小數目, 但
搞這麼多 ORM的東西了, 請問你們的機器多大?
level 2 cache 吃多少memory?


一个订单在缓存中存活的生命周期,不超过80分钟,很快就被移出了。

5万笔是一天的总单量,在一个时刻,正在流转,尚没有结束的,同时存活在缓存中的订单不过几百个。

这点memory,如果应用服务器都吃不消,还做什么服务器。
0 请登录后投票
   发表时间:2007-06-03  
知道是频繁更新的东西为什么要cache??
直接JDBC就好了.  如果坚持要OO style的话用上iBATIS.
2 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics