`

关于系统性能的思考

阅读更多

 在评价一个系统的时候,性能指标是很重要的,那么在当前J2EE的系统开发当中,如何来提高系统的性能呢?我觉得应该从对象管理入手,从对象的生命周期开始。虽然大家可能会说,Java有垃圾收集器,我们的对象的生命周期不需要我们自己管理,但是如果要是真的过分依赖java语言本身的特性,那么我相信,系统的性能肯定好不到哪去。所以,下面就主要从三个方面入手来说一下我的想法。

第一:容器化系统功能性组件

    在每个系统中,我想都会存在功能性的组件,比如当前开发当中的service,这些功能性的服务一般来说都是没有状态的,是可以多用户共享的,这种共享的服务对象,我们也需要将其进行统一的管理,幸运的是目前已经存在很多这样的管理功能性服务的框架或者容器,比如目前比较流行的各种IOC容器,或者是重量级的EJB容器,它们都提供了对系统中各种服务组件的管理。

第二:缓存化业务对象

  在说缓存之前,我不得不说一下面向对象的设计,可能有些人认为,为什么缓存会与面向对象的设计扯上关系,其实这就是缓存的关键。首先设想一下,如果开发系统的过程中,都是采用面向过程,面向数据库的思维编程,每一次业务操作,我们都是调用通过数据库操作来完成,这其实就是POEAA中的事务脚本,只适合一些简单的系统的开发,或者一个项目中,比较简单模块的开发,对于复杂的模块,更好的方式就是采用面向对象的方法来进行开发。

  好了,说到了面向对象的设计问题,至于这个问题已经有很多书籍以及很多人讨论了很多年了,就我个人来说,我觉得采用DDD建模是目前比较适合的一种方式。DDD中涉及到得每种模式或者说是每一种模型元素对于缓存设计来说都是很重要的,下面我说说我的想法:

 首先我说一下关于聚合的问题,为什么说聚合对于缓存非常重要呢?这其实涉及到了一种控制访问的问题,一个聚合根控制了对整个聚合的访问,要想访问聚合里的对象必须要通过聚合的根。

 好了,我们以一个实例来说话,比如一个论坛的设计,论坛中有Forum以及ForumState对象,Forum对象是聚合的根,是一个实体模型,而ForumState是一个值对象,并且是属于Forum这个聚合根的子对象,我们把ForumState对象从Forum对象分离出来,好处主要有两个,从事务的角度来说,当我们更新ForumState对象的时候,不用锁住Forum对象,从缓存设计的角度来说,当我们更新ForumState对象的时候不用刷新Forum对象的缓存,因为Forum不是经常改变的,所以不必要因为经常改变属性的改变而改变。那么具体怎么来设计呢?我们可以这样做,在ForumState对象中设置一个状态位,表示它的状态是否已经改变,当Forum状态发生改变,比如有人创建新的帖子或者回复了帖子后,我们可以设置这个状态位为true,表示状态已经改变,这样当再次从缓存中取得Forum时,查看状态位,如果发现已经变化了,那么就重新从数据库加载ForumState。当然要想达到这种效果,我们一定要设计好聚合,所有对子对象的访问都要通过聚合的根,比如所有对ForumState对象的访问都要经过Forum对象,并且要保证所有的数据库操作,都首先从统一的缓冲入口进行,这样保证了整个系统中用的是同一个缓存,大家操作的所有对象都是同一个缓存中的对象。所以这里也给出了一条对象设计的提示,将经常变化的熟悉和不经常变化的属性分开,并且将经常变化的属性独立出去,作为聚合根的 一个子对象,这样做到变和不变分离,不仅有利于高内聚,而且有利于事务的控制和缓存的更新。

 

 

 

<!--EndFragment-->

   上面是关于Repository在对象建模中的作用,下面我也说说关于工厂的作用,既然是工厂,那么它肯定要生产东西出来,但是它不能随便乱生产,它生产出来的应该是整个聚合的根,并且要保证这个聚合的不变量受到保护,这样通过工厂提供一个集中的模型创建的访问点,也方便了控制访问。要设计一个好的工厂,我们首先需要设计一个好的对象模型,分辨出合理的聚合,这样工厂才会发挥真正的效力。

    最后既然说到了缓存,还有一点需要注意,那就是这个缓存的范围,我这里说的缓存是全局的缓存,是一个application级别的缓存。我个人是比较反对在Httpsession中保存大量数据的,这样当用户增多的情况下,比如会浪费很多的内存,浪费性能。所以我们更应该需要的是全局的缓存,这样底层的缓冲框架我们还可以采用分布式的缓存系统,这样以来我们的系统在集群环境下也免去了一些session failover的开销。这其实也是一种SNA架构的思想。

第三:数据库系统优化

 数据库在我们大多数的系统开发中都会涉及到,这方面的优化,主要是基于一些索引等的优化。

    最后,我想说的就是我们应该尽量采用一种面向对象的方式来开发我们的系统,而不是过分的依赖数据库来编程,在系统开发当中,我们操作具体的模型对象,而我们的模型对象由存储在缓存中,尽量减少对数据库的访问操作,从而提升系统的性能。

 

 

 总结上面所述,要想提高系统的性能,我们面临的难题就是对象建模,只有我们针对自己的具体的业务有了合理的对象模型后,我们才能有针对性的对业务对象进行缓存,从而使得缓存的效果最大化,提高系统的性能。

<!--EndFragment-->

分享到:
评论
65 楼 xuyan2680 2010-01-14  
<p>兄台讲的和  jforum 好类似。<img src="/images/smiles/icon_biggrin.gif" alt=""></p>
64 楼 jasonshi 2009-11-25  
icewubin 写道


我发现楼主不太了解Hibernate,虽然hibernate达不到你理想中的ORM,但是在一个事务中,合理的编程,Hibernate也是不会触发多余的sql,实际上在尽量不触发sql上,Hibernate是做了大量的工作的。而你说Hibernate会触发大量的sql,我只能说你们使用上有问题。

而由于这个原因使得你期望重造轮子,唉。。。
。。。



同意楼上的观点,当系统有几十万甚至几百万代码的时候,不能指望所有的代码性能都是非常优化,并且协同工作时也是最优的。
这时用好hibernate不仅不会有多余的sql,而且比自己写的jdbc代码少很多倍的sql访问。hibernate的一级cache机制做得非常好的,很有用
63 楼 lonelybug 2009-10-02  
我借此帖提出自己的疑惑。

在域模型中,缓存技术很重要,但是,我一直有一个不明白的地方,因为领域模型中一个Aggregate的生命周期基本上要靠Factory和Repository来控制,特别是后者。

那么,就是说,一个Aggregate的不论是根还是子对象更改之后,需要真正提交更新的时候是要通过Repository对一个Aggregate从头到尾完全遍历来进行具体的更新操作。所以,这时候使用Application的缓存,有一个问题就是,当多个线程同时修改同一个Aggregate的时候,如何做到线程安全,或者说,如何提供线程锁?

就如同LZ所说,如果对Value Object进行锁是很好,也是DDD作者提倡,但是,问题是加在那里?

我一直不太知道这两个问题的解决方法。有人告诉我对每一个线程创建一个新的Aggregate(缓存的话,应该是克隆),但是,这样子就是说,一个系统中会存在大量的拥有相同全局ID的Aggregate根对象,这是不是违反了DDD的基本原则呢?因为DDD书中明确标明,区别Entity的方法在于Identity而不是内存中的Reference(就是指针地址)。
62 楼 icewubin 2009-05-07  
狂放不羁 写道
6 java确实不太适合做富模型,但是就是我在实战中采用富模型的情况下,使用hibernate导致很多sql,并且hibernate要想往一个one-to-many的集合中增加数据,首先要取出所有的数据才能增加,这点不知道你有什么好的办法,我的解决方法目前都是设计到many一端数据太多的情况下,直接用jdbc操作了。

看来楼主Hibernate实战经验不够啊。

Hibernate因为过于灵活,用法可以千奇百怪的,我只写一些个人观点:
1.因为关系型数据库的关系,不要过于幻想把Hibernate封装成完全OO的框架,只把他当成一个非常非常高级的SQL生成器是最好的方式,我是这么认为的。也就是说,你编程的时候,大脑中就是一条条sql,当然在我脑中是hql,我比较熟了(QBC、QBE、QBDC我都很熟)。

2.从细节上来讲,我不赞成配置一对多,基于使用EntityDao(单dao设计,这个EntityDao可以直接使用,也可以继承之后实例化),一句话就能轻易查询一对多的信息,没必要配置在映射配置中,我一般只在映射配置中放多对一的信息,其他的几乎都不使用,偶尔用用多对多(极少)。只要EntityDao设计的好,或者再做个父类,一般性的service编程(不需要DAO编程),已经很简单了,虽然是面向sql的编程,带一点点OO的样子。利用Hibernate的update和delete命令,完全可以自己封装出,既高效,又还算OO的操作方式。

其实数据库中并没有一对多的关系,硬是要那么操作,当然容易造成性能问题。以你说的一对多添加的例子,假设是小组中加个同学吧。
StudentService.java:
    public void insert(String groupId, Student student) {//假设ID是String的,之所以把这个参数单独传进来,往下看就知道了
        student.setGroup(new Group(groupId));//假设Group有这个构造函数
        studentDao.insert(student);
    }

这段代码其实是以同学为主导思想的,那个groupId这所以这样,主要目的是便于复用,只需要传一个groupId就行了,不会担心发生什么性能问题,这个方法确保只触发一条insert sql,而且还能减少web层编程的复杂度,web层对于小组信息只要获取一个groupId即可。(当然这里还隐含了“小组-同学”管理页面UI的设计问题,不同的UI操作方式对后台方法的需求也不太一样)

3.然后在POJO和VO(或者叫DTO)的选择上是2-8原则,大部分的业务操作,CRUD,pojo足够了,少部分的特殊操作,如复杂查询,则用VO来传递信息到web层。

4.从我对Hibernate的了解成来说,我认为你现在想解决的问题,hibernate的作者也想解决,但是因为关系数据库的问题,在实际实践中,碰到了很多阻力(所以Hibernate对处理某一种问题,往往提供了N多种的解决办法,这既是它的优点也是它的缺点,学习成本高啊),必须要自己掌握平衡点,做选择,例如一对多的思维方式用不用,二级缓存用不用、saveOrUpdate用不用,merge方法是否真的有必要等等。

hibernate对于对象状态的控制和对象图的控制其实已经还算不错了,不管你是否承认是否造轮子,我认为你很难做的封装能比Hibernate更好。
61 楼 狂放不羁 2009-05-07  
ithero 写道

楼主不要见叶就是森林,至于你说领域模型举例那个Forum好像也是jdon中的例子。高性能高并发的应用设计。不是抽象几个概念就能解决的。不过下面大家的跟贴中部分牛人的思路很正。



对,jdon中的那个帖子也是我发的。
60 楼 狂放不羁 2009-05-07  
icewubin 写道
狂放不羁 写道
1 RDBMS有坚实的数学理论基础。相反的面相对象的数据库在数学理论方面欠缺。还有您推荐的<<pojo in action>>以前看过但是没看完,最近在看。个人觉得很多和POEAA很像,也可以说是POEAA的实践版本。

2 缓存和数据库确实不是一个级别,JVM也确实有限制,但是之所以叫缓存那就是暂时存储一部分数据,大小限制也没事,只是一部分,不是全部。

3 缓存同步确实是存在问题,但是session同步也存在严重的问题,我说缓存一方面集群环境下是减少session同步问题,如果不集群的情况下,缓存可以减少数据库操作。比如tomcat那种多机备份策略,同步更加有问题。而对于分布式缓存的同步由分布式缓存系统来完成。其它的应用服务器采用不同的策略,以前看过TSS上一篇文章,揭开J2EE集群神秘面纱,写的很好。


4 hibernate缓存我也不喜欢使用,除了一些不常变化的数据,比如一些地址等的信息。我一般是以前在service层通过开源的缓存系统,通过拦截器或者代理模式来做缓存,并且目前我做的一个项目是通过Repository(DDD概念)和builder模式控制了缓存。

5 正是您所说的不是每个项目都适合SNA的,这里的缓存也可以是SNA中那种缓存服务器的缓存,也可以采用jbosscache torrecotte等分布式缓存系统


6 这样主要是减轻了hibernate向RDBMS映射的痛苦(尤其是业务对象设计的关联比较多的时候,每次hibernate都要生产N多sql。


7 现在开源的缓存系统有很多,我并没有自己开发分布式的缓冲,只是通过封装好的业务对象模型来实现状态的并发更新,所以我说面向对象的设计不仅对于设计一个好的对象模型很重要,同时对于设计对象模型的缓冲也很重要,一个没有经过良好设计的,状态到处暴漏的丑陋的模型,即使用了缓存,也是自找苦吃,状态并发更新的情况下,头痛死了。对于并发编程方面,我个人比较推荐<<java 并发编程实践>>

8 在数据库集群的时候也存在同样的问题。

1.pojo in action中的离线悲观锁,看一看,很有意思的。

2.对呀,既然暂存一部分数据,必然有缓存失效的问题。
缓存作为生存空间,这不就是相当于自己另外造了一个ORM么?只不过你认为Hibernate让你不满意而已。
我总感觉楼主的缓存概念太局限在JVM中了,前台squid+memcached的页面缓存结构和后台的数据库如何做缓存的都应该适当了解一下。

3.问题就是,你认为单机的结构,能够很顺利的迁移到多机的,基于分布式缓存系统的框架下,这个愿望是美好的,实际操作却是非常痛苦的。自己造这种级别的轮子是需要很多的实战经验的,例如单例模式的陷阱等等。

6.Hibernate映射RDBMS不需要很痛苦,简单映射,不使用高级功能,仍然面向过程好了,pojo in action中的script pattern没什么不好啊,java不太适合充血模型的,大多还是写在Service中的Script Pattern而已。

我发现楼主不太了解Hibernate,虽然hibernate达不到你理想中的ORM,但是在一个事务中,合理的编程,Hibernate也是不会触发多余的sql,实际上在尽量不触发sql上,Hibernate是做了大量的工作的。而你说Hibernate会触发大量的sql,我只能说你们使用上有问题。

而由于这个原因使得你期望重造轮子,唉。。。

7.恩?两个问题,第一,同一个JVM中的并发编程,和多台机器中不同的JVM中的程序互相通讯是两码事吧,<<java 并发编程实践>>帮不上太多的忙吧。第二,多台机器之间的通讯(即使是建立在成熟的分布式缓存产品之上),实际的调试和测试成本仍然是高得惊人。
恩。。。你是单机吧,第二点我说了没啥用,这样说好了,单击情况下,假如我用SSH做项目,一般不会有并发问题的,是不是因为你自己在造ORM工具这个大轮子的时候,碰到了很多并发问题呢?

8.数据库集群可以另开一个很大的话题了,这里不讨论。


哈哈,老哥上班时间满充足的。

1 正好还没看到这里哈。

2 缓存的有很多种,但是我这里的主要意思还是业务对象model缓存。

3 我和朋友现在自己接的一个项目打算实战一下分布式缓存,虽然钱少,但是主要是锻炼哈(台湾客户满扣的呵呵),还有那个单例模式,确实是的,单例是相对于类加载器的,我在我的另外一篇帖子里也说了这个问题。如果在采用EJB的情况下,web容器和ejb容器的类加载器体系很容易造成单例实例非单例。

6 java确实不太适合做富模型,但是就是我在实战中采用富模型的情况下,使用hibernate导致很多sql,并且hibernate要想往一个one-to-many的集合中增加数据,首先要取出所有的数据才能增加,这点不知道你有什么好的办法,我的解决方法目前都是设计到many一端数据太多的情况下,直接用jdbc操作了。

7 我其实没有自己制作ORM大轮子,重复发明轮子我也没有那个能力也不想。采用SSH开发,对于无状态的操作当然没有并发问题,但是一旦模型放到缓存中就有并发问题了,真正的业务模型对象是有状态的,并且状态很多,不变量约束有很多状态构成,这个时候就要求严格的面相对象的设计,封装非常重要。其实我所说的仅仅是利用已经有的轮子(开源缓存系统)和良好的面相对象设计来设计系统而已。

59 楼 ithero 2009-05-07  
楼主不要见叶就是森林,至于你说领域模型举例那个Forum好像也是jdon中的例子。高性能高并发的应用设计。不是抽象几个概念就能解决的。不过下面大家的跟贴中部分牛人的思路很正。
58 楼 icewubin 2009-05-07  
狂放不羁 写道
1 RDBMS有坚实的数学理论基础。相反的面相对象的数据库在数学理论方面欠缺。还有您推荐的<<pojo in action>>以前看过但是没看完,最近在看。个人觉得很多和POEAA很像,也可以说是POEAA的实践版本。

2 缓存和数据库确实不是一个级别,JVM也确实有限制,但是之所以叫缓存那就是暂时存储一部分数据,大小限制也没事,只是一部分,不是全部。

3 缓存同步确实是存在问题,但是session同步也存在严重的问题,我说缓存一方面集群环境下是减少session同步问题,如果不集群的情况下,缓存可以减少数据库操作。比如tomcat那种多机备份策略,同步更加有问题。而对于分布式缓存的同步由分布式缓存系统来完成。其它的应用服务器采用不同的策略,以前看过TSS上一篇文章,揭开J2EE集群神秘面纱,写的很好。


4 hibernate缓存我也不喜欢使用,除了一些不常变化的数据,比如一些地址等的信息。我一般是以前在service层通过开源的缓存系统,通过拦截器或者代理模式来做缓存,并且目前我做的一个项目是通过Repository(DDD概念)和builder模式控制了缓存。

5 正是您所说的不是每个项目都适合SNA的,这里的缓存也可以是SNA中那种缓存服务器的缓存,也可以采用jbosscache torrecotte等分布式缓存系统


6 这样主要是减轻了hibernate向RDBMS映射的痛苦(尤其是业务对象设计的关联比较多的时候,每次hibernate都要生产N多sql。


7 现在开源的缓存系统有很多,我并没有自己开发分布式的缓冲,只是通过封装好的业务对象模型来实现状态的并发更新,所以我说面向对象的设计不仅对于设计一个好的对象模型很重要,同时对于设计对象模型的缓冲也很重要,一个没有经过良好设计的,状态到处暴漏的丑陋的模型,即使用了缓存,也是自找苦吃,状态并发更新的情况下,头痛死了。对于并发编程方面,我个人比较推荐<<java 并发编程实践>>

8 在数据库集群的时候也存在同样的问题。

1.pojo in action中的离线悲观锁,看一看,很有意思的。

2.对呀,既然暂存一部分数据,必然有缓存失效的问题。
缓存作为生存空间,这不就是相当于自己另外造了一个ORM么?只不过你认为Hibernate让你不满意而已。
我总感觉楼主的缓存概念太局限在JVM中了,前台squid+memcached的页面缓存结构和后台的数据库如何做缓存的都应该适当了解一下。

3.问题就是,你认为单机的结构,能够很顺利的迁移到多机的,基于分布式缓存系统的框架下,这个愿望是美好的,实际操作却是非常痛苦的。自己造这种级别的轮子是需要很多的实战经验的,例如单例模式的陷阱等等。

6.Hibernate映射RDBMS不需要很痛苦,简单映射,不使用高级功能,仍然面向过程好了,pojo in action中的script pattern没什么不好啊,java不太适合充血模型的,大多还是写在Service中的Script Pattern而已。

我发现楼主不太了解Hibernate,虽然hibernate达不到你理想中的ORM,但是在一个事务中,合理的编程,Hibernate也是不会触发多余的sql,实际上在尽量不触发sql上,Hibernate是做了大量的工作的。而你说Hibernate会触发大量的sql,我只能说你们使用上有问题。

而由于这个原因使得你期望重造轮子,唉。。。

7.恩?两个问题,第一,同一个JVM中的并发编程,和多台机器中不同的JVM中的程序互相通讯是两码事吧,<<java 并发编程实践>>帮不上太多的忙吧。第二,多台机器之间的通讯(即使是建立在成熟的分布式缓存产品之上),实际的调试和测试成本仍然是高得惊人。
恩。。。你是单机吧,第二点我说了没啥用,这样说好了,单击情况下,假如我用SSH做项目,一般不会有并发问题的,是不是因为你自己在造ORM工具这个大轮子的时候,碰到了很多并发问题呢?

8.数据库集群可以另开一个很大的话题了,这里不讨论。
57 楼 狂放不羁 2009-05-07  
icewubin 写道
狂放不羁 写道
通过存储过程确实是个不好的应用模式。同样的还有一种情况也是不好应用模式。比如采用SSH开发,一个事务性的操作,action-service-dao这种方式进行,还是一种面向过程的思维,整个的事务性操作中逻辑还是依赖于service,依赖于dao,这种情况下还是会造成大量的数据库操作,并且此时领域对象就是数据容器,不是一个真正的富模型。所以我想要向摆脱对数据库的频繁的操作,就需要实现一个富模型,一个事务性的操作中,操作的是具有业务意义的对象,并且业务逻辑也是由领域对象(比如一个聚合根领域对象)来实现的,这样等到最后的时候再进行数据库的操作显著的减少对数据库的操作次数。所以我觉得采用SSH开发,还是要求有良好的面向对象设计的功底,尽管系统中的功能性的组件生命周期由容器管理的,但是系统中真正的业务对象还是要靠我们自己来管理(比如通过工,builder,repository,缓存等来管理)。

呵呵,我这篇文章的意思主要也是通过缓存来缓存业务对象,缓存中存储的是我们系统中的富有业务意义的,有不变量保证,以及方法后验条件保证(所有的这些保证领域对象的不变量约束)的的领域对象,而不是普通的数据(如果缓存普通的数据,还不如不缓存,因为并发环境下,缓存中的数据不变量很难控制,只有设计良好的,严格封装的的对象模型才是一个好的对象模型,才是一个能在并发环境下安全发布的模型),这个时候业务对象的生命周期中就有两个生存的空间:缓存和数据库。而不是以前那样,业务对象的生命周期期间只有一个生存空间:数据库。

1.数据库最早发明的时候就是对象数据库,但是为什么关系型数据库能够得到普及和流行呢(这个自己了解一下吧)?只要后台的存储方式还是关系型数据库,就不可避免的有面向过程的味道掺杂在其中。我再推荐一本书吧《Pojo In Action》。

2.数据库和缓存空间本来就不在一个级别上,之前我已经提醒JVM的内存管理大小是有限制的,JVM中能够缓存的业务对象模型的数量也是有限制的。

3.SSH并发下难道会不安全么?并发问题不是什么大问题,集群下的节点间的通讯(例如缓存的同步,HttpSession的同步才是大问题吧)。

4.我相信你应该知道Hibernate的二级缓存吧,如果把Hibernate的二级缓存放在一个比较成熟的缓存结构中,不就是你描述的效果么(可能还有点差别吧)?

5.我是不赞成使用Hibernate的二级缓存的,或者是引用你的话,就是不赞成业务对象的生命周期有两个生存空间,这和SNA的设计思想是矛盾的,SNA的设计思想简单来说就是尽可能避免某一个节点中出现有状态的东西(例如缓存,但不是绝对的)。

6.你这样的想法不是不可以,而且你说了你也实践过,整个过程中,你觉得开发上“省”下的时间成本,在调试、部署和运维上是不是又加倍在还债呢?

7.你的这套方案的假设是,你认为数据库性能不佳,要尽可能地减少对数据库的操作。那我顺着你的想法来回折腾一下,既然缓存也是业务对象的生存空间,那必然也有数据库的事务特性吧,那是不是你在创造一个分布式对象数据库呢(只不过这个对象数据库跑在内存里)?

恩,有人会说缓存框架也可以脱离JVM内存嘛,空间不够了写磁盘啊,哦,一旦写了磁盘,那和传统数据库还有啥区别啊,传统数据库也是磁盘加缓存的结构啊,要知道中间层的缓存技术,数据库也不是不能用的啊,只不过缓存的粒度不一样而已。

再说说,假入数据不大的话,数据库本身也可以放在内存中,或者说把数据库的数据文件指向虚拟硬盘,那数据库的操作性能也是很好的啊。。。

8.你认为缓存结构性能一定比数据库好,是要有量化数据作保证的。假设两台机器集群,两台机器之间做缓存同步,你要有具体的数字评估缓存的效果,因为两台机器之间要做缓存同步,缓存同步是需要时间的,你必须要量化测试的,而且随集群数量的增加,缓存同步的开销甚至于成指数形式上升。



1 RDBMS有坚实的数学理论基础。相反的面相对象的数据库在数学理论方面欠缺。还有您推荐的<<pojo in action>>以前看过但是没看完,最近在看。个人觉得很多和POEAA很像,也可以说是POEAA的实践版本。

2 缓存和数据库确实不是一个级别,JVM也确实有限制,但是之所以叫缓存那就是暂时存储一部分数据,大小限制也没事,只是一部分,不是全部。

3 缓存同步确实是存在问题,但是session同步也存在严重的问题,我说缓存一方面集群环境下是减少session同步问题,如果不集群的情况下,缓存可以减少数据库操作。比如tomcat那种多机备份策略,同步更加有问题。而对于分布式缓存的同步由分布式缓存系统来完成。其它的应用服务器采用不同的策略,以前看过TSS上一篇文章,揭开J2EE集群神秘面纱,写的很好。


4 hibernate缓存我也不喜欢使用,除了一些不常变化的数据,比如一些地址等的信息。我一般是以前在service层通过开源的缓存系统,通过拦截器或者代理模式来做缓存,并且目前我做的一个项目是通过Repository(DDD概念)和builder模式控制了缓存。

5 正是您所说的不是每个项目都适合SNA的,这里的缓存也可以是SNA中那种缓存服务器的缓存,也可以采用jbosscache torrecotte等分布式缓存系统


6 这样主要是减轻了hibernate向RDBMS映射的痛苦(尤其是业务对象设计的关联比较多的时候,每次hibernate都要生产N多sql。


7 现在开源的缓存系统有很多,我并没有自己开发分布式的缓冲,只是通过封装好的业务对象模型来实现状态的并发更新,所以我说面向对象的设计不仅对于设计一个好的对象模型很重要,同时对于设计对象模型的缓冲也很重要,一个没有经过良好设计的,状态到处暴漏的丑陋的模型,即使用了缓存,也是自找苦吃,状态并发更新的情况下,头痛死了。对于并发编程方面,我个人比较推荐<<java 并发编程实践>>

8 在数据库集群的时候也存在同样的问题。
56 楼 icewubin 2009-05-07  
要么我还是抽时间说说SNA相关的一些简单的实践技巧和好处吧。

1.测试简单,无状态啊,设计上不要产生有状态的东西,不出现脏读,就可以了,相对于缓存同步机制,调试非常简单,集成测试也很简单。

2.实际的策略一般是,需要负载均衡配合,粘性路由策略,例如某个IP发送的请求,在半小时之内都指向同一台应用服务器,这样的话,就不需要HTTP Session同步了。

3.系统更新非常简单,一台一台更新就是了,不需要把所有服务器全部停止再一起更新。

4.系统横向扩展也非常简单,机器随便加,如果必要的话。

5.即使没有缓存同步,依然可以在设计上做一些缓存,例如数据字典的缓存,几乎不会有太大变化的,有些事几年才变化一次的,例如中国的省份和直辖市的名称列表,缓存失效时间(不是LRU,就是总的缓存有效时间)可以设为24小时,有些是每天只有几次变化甚至于一次一次变化都没有,例如某个企业的部门中的员工信息,缓存时间可以设为10-60秒,这样使得高并发的时候,对单台应用服务器来说,这些信息的获取不再会对数据库造成很多的查询压力。

6.至于更高一级的,例如页面缓存,完全可以用squid这类的反向代理加反向代理所在机器的本地缓存,在应用服务器之前做集群(这个一般企业应用不会用到)。

7.一个业务系统,无论前台和中间层,如何优化最终该操作数据的还是得操作数据库(业务固有的复杂度是不会消失的),我想说的是,基于SNA的思想的做法和基于缓存同步的集群的思想,都是可以有各自的办法来减少无谓的数据库操作,但是无状态的简单结构能够极大的降低调试和运维成本,横向扩展性也非常好。
55 楼 icewubin 2009-05-07  
狂放不羁 写道
通过存储过程确实是个不好的应用模式。同样的还有一种情况也是不好应用模式。比如采用SSH开发,一个事务性的操作,action-service-dao这种方式进行,还是一种面向过程的思维,整个的事务性操作中逻辑还是依赖于service,依赖于dao,这种情况下还是会造成大量的数据库操作,并且此时领域对象就是数据容器,不是一个真正的富模型。所以我想要向摆脱对数据库的频繁的操作,就需要实现一个富模型,一个事务性的操作中,操作的是具有业务意义的对象,并且业务逻辑也是由领域对象(比如一个聚合根领域对象)来实现的,这样等到最后的时候再进行数据库的操作显著的减少对数据库的操作次数。所以我觉得采用SSH开发,还是要求有良好的面向对象设计的功底,尽管系统中的功能性的组件生命周期由容器管理的,但是系统中真正的业务对象还是要靠我们自己来管理(比如通过工,builder,repository,缓存等来管理)。

呵呵,我这篇文章的意思主要也是通过缓存来缓存业务对象,缓存中存储的是我们系统中的富有业务意义的,有不变量保证,以及方法后验条件保证(所有的这些保证领域对象的不变量约束)的的领域对象,而不是普通的数据(如果缓存普通的数据,还不如不缓存,因为并发环境下,缓存中的数据不变量很难控制,只有设计良好的,严格封装的的对象模型才是一个好的对象模型,才是一个能在并发环境下安全发布的模型),这个时候业务对象的生命周期中就有两个生存的空间:缓存和数据库。而不是以前那样,业务对象的生命周期期间只有一个生存空间:数据库。

1.数据库最早发明的时候就是对象数据库,但是为什么关系型数据库能够得到普及和流行呢(这个自己了解一下吧)?只要后台的存储方式还是关系型数据库,就不可避免的有面向过程的味道掺杂在其中。我再推荐一本书吧《Pojo In Action》。

2.数据库和缓存空间本来就不在一个级别上,之前我已经提醒JVM的内存管理大小是有限制的,JVM中能够缓存的业务对象模型的数量也是有限制的。

3.SSH并发下难道会不安全么?并发问题不是什么大问题,集群下的节点间的通讯(例如缓存的同步,HttpSession的同步才是大问题吧)。

4.我相信你应该知道Hibernate的二级缓存吧,如果把Hibernate的二级缓存放在一个比较成熟的缓存结构中,不就是你描述的效果么(可能还有点差别吧)?

5.我是不赞成使用Hibernate的二级缓存的,或者是引用你的话,就是不赞成业务对象的生命周期有两个生存空间,这和SNA的设计思想是矛盾的,SNA的设计思想简单来说就是尽可能避免某一个节点中出现有状态的东西(例如缓存,但不是绝对的)。

6.你这样的想法不是不可以,而且你说了你也实践过,整个过程中,你觉得开发上“省”下的时间成本,在调试、部署和运维上是不是又加倍在还债呢?

7.你的这套方案的假设是,你认为数据库性能不佳,要尽可能地减少对数据库的操作。那我顺着你的想法来回折腾一下,既然缓存也是业务对象的生存空间,那必然也有数据库的事务特性吧,那是不是你在创造一个分布式对象数据库呢(只不过这个对象数据库跑在内存里)?

恩,有人会说缓存框架也可以脱离JVM内存嘛,空间不够了写磁盘啊,哦,一旦写了磁盘,那和传统数据库还有啥区别啊,传统数据库也是磁盘加缓存的结构啊,要知道中间层的缓存技术,数据库也不是不能用的啊,只不过缓存的粒度不一样而已。

再说说,假入数据不大的话,数据库本身也可以放在内存中,或者说把数据库的数据文件指向虚拟硬盘,那数据库的操作性能也是很好的啊。。。

8.你认为缓存结构性能一定比数据库好,是要有量化数据作保证的。假设两台机器集群,两台机器之间做缓存同步,你要有具体的数字评估缓存的效果,因为两台机器之间要做缓存同步,缓存同步是需要时间的,你必须要量化测试的,而且随集群数量的增加,缓存同步的开销甚至于成指数形式上升。
54 楼 狂放不羁 2009-05-07  
凤舞凰扬 写道
icewubin 写道
fjlyxx 写道
关于第二点 还需要仔细的斟酌,因为把业务弄得数据库要考虑数据库的压力问题.业务放置的位置要么在前台逻辑要么在数据库.放在前台可以减缓数据库压力,放在后台可以提高前台处理能力. 但是有这么一个问题,如果前台有需要进行群集的时候  后台数据库的业务逻辑如何处理. 这时候跑数据库也许就是一个瓶颈了. 总之还是要小心跑数据库这个陷阱,需要很充分的考虑.

第二点我没有说清楚,其实每一点都应该写得具体一点,手酸啊。

这一点我的理解是这样的,银行业务的特点一般是外围系统加核心系统,外围无论如何优化业务,都是要调用核心系统的接口,银行固有的业务特点使得相当一部分业务办理的操作无法做深层次的优化,例如借记卡余额的查询(这种查询操作是不可能做缓存的,对于外围系统来说,每次查询必须要调用核心系统的接口,而不能自说自话的做缓存)。

那么然后说核心系统,暂且不论核心系统是否通过缓存优化一些查询操作,至少目前基本上大部分操作还是依赖于数据库的。我叽叽歪歪说了这些,无非就是举个例子,有这样的场景,无论中间层或外围如何优化,最终对于数据库的压力是固有的,逃不掉的。例如每小时处理10000笔转账业务,这必然带来10000次数据库操作(肯定不止),这是业务特点加上目前的银行核心系统架构带来的固有的数据库的压力。

在这种场景下,因为银行的海量数据,不得不在核心数据库上动脑筋:
1.某人说,数据库做集群不就完了么?Scale Out,可惜几乎不可能,原因复杂一言难尽。

2.一般只能做Scale Up,加CPU,加内存,一般使用大型机,来提高吞吐量。

举这个例子也是想拓宽楼主视野,不同行业,不同业务特点带来的系统瓶颈的位置都不太一样。

   其实对于数据库的压力来说,OLTP是远远小于OLAP的,当出现大吞吐量的数据库事务操作时,首先撑不住的并不是数据库,而是业务系统。在实际应用中,数据库的分布式计算绝大多数场景都是在数据挖掘和数据仓库上,或者是消息中间件的转储。银行确实是个比较特殊的案例,但在银行系统中出现了数据库的集群并不能说明系统的性能瓶颈在数据库部分。
   不太清楚fjlyxx所说的前台是指什么?web表示层还是所有除数据库外的系统?不过至少,把大量的业务逻辑写在数据库(通过存储过程的方式)并不是一个好的应用模式


通过存储过程确实是个不好的应用模式。同样的还有一种情况也是不好应用模式。比如采用SSH开发,一个事务性的操作,action-service-dao这种方式进行,还是一种面向过程的思维,整个的事务性操作中逻辑还是依赖于service,依赖于dao,这种情况下还是会造成大量的数据库操作,并且此时领域对象就是数据容器,不是一个真正的富模型。所以我想要向摆脱对数据库的频繁的操作,就需要实现一个富模型,一个事务性的操作中,操作的是具有业务意义的对象,并且业务逻辑也是由领域对象(比如一个聚合根领域对象)来实现的,这样等到最后的时候再进行数据库的操作显著的减少对数据库的操作次数。所以我觉得采用SSH开发,还是要求有良好的面向对象设计的功底,尽管系统中的功能性的组件生命周期由容器管理的,但是系统中真正的业务对象还是要靠我们自己来管理(比如通过工厂,builder,repository,缓存等来管理)。

呵呵,我这篇文章的意思主要也是通过缓存来缓存业务对象,缓存中存储的是我们系统中的富有业务意义的,有不变量保证,以及方法后验条件保证(所有的这些保证领域对象的不变量约束)的的领域对象,而不是普通的数据(如果缓存普通的数据,还不如不缓存,因为并发环境下,缓存中的数据不变量很难控制,只有设计良好的,严格封装的的对象模型才是一个好的对象模型,才是一个能在并发环境下安全发布的模型),这个时候业务对象的生命周期中就有两个生存的空间:缓存和数据库。而不是以前那样,业务对象的生命周期期间只有一个生存空间:数据库。
53 楼 fjlyxx 2009-05-07  
前台是指除数据库外的系统  我的意思是  如果把逻辑放在数据库 有可能为以后应用群集带来麻烦. 这时候数据库的业务逻辑就是一个瓶颈了.
52 楼 凤舞凰扬 2009-05-07  
icewubin 写道
fjlyxx 写道
关于第二点 还需要仔细的斟酌,因为把业务弄得数据库要考虑数据库的压力问题.业务放置的位置要么在前台逻辑要么在数据库.放在前台可以减缓数据库压力,放在后台可以提高前台处理能力. 但是有这么一个问题,如果前台有需要进行群集的时候  后台数据库的业务逻辑如何处理. 这时候跑数据库也许就是一个瓶颈了. 总之还是要小心跑数据库这个陷阱,需要很充分的考虑.

第二点我没有说清楚,其实每一点都应该写得具体一点,手酸啊。

这一点我的理解是这样的,银行业务的特点一般是外围系统加核心系统,外围无论如何优化业务,都是要调用核心系统的接口,银行固有的业务特点使得相当一部分业务办理的操作无法做深层次的优化,例如借记卡余额的查询(这种查询操作是不可能做缓存的,对于外围系统来说,每次查询必须要调用核心系统的接口,而不能自说自话的做缓存)。

那么然后说核心系统,暂且不论核心系统是否通过缓存优化一些查询操作,至少目前基本上大部分操作还是依赖于数据库的。我叽叽歪歪说了这些,无非就是举个例子,有这样的场景,无论中间层或外围如何优化,最终对于数据库的压力是固有的,逃不掉的。例如每小时处理10000笔转账业务,这必然带来10000次数据库操作(肯定不止),这是业务特点加上目前的银行核心系统架构带来的固有的数据库的压力。

在这种场景下,因为银行的海量数据,不得不在核心数据库上动脑筋:
1.某人说,数据库做集群不就完了么?Scale Out,可惜几乎不可能,原因复杂一言难尽。

2.一般只能做Scale Up,加CPU,加内存,一般使用大型机,来提高吞吐量。

举这个例子也是想拓宽楼主视野,不同行业,不同业务特点带来的系统瓶颈的位置都不太一样。

   其实对于数据库的压力来说,OLTP是远远小于OLAP的,当出现大吞吐量的数据库事务操作时,首先撑不住的并不是数据库,而是业务系统。在实际应用中,数据库的分布式计算绝大多数场景都是在数据挖掘和数据仓库上,或者是消息中间件的转储。银行确实是个比较特殊的案例,但在银行系统中出现了数据库的集群并不能说明系统的性能瓶颈在数据库部分。
   不太清楚fjlyxx所说的前台是指什么?web表示层还是所有除数据库外的系统?不过至少,把大量的业务逻辑写在数据库(通过存储过程的方式)并不是一个好的应用模式。
51 楼 路过心中 2009-05-06  
高性能在是主要,至于技术实现 是次要。
50 楼 路过心中 2009-05-06  
高性能在是主要,至于技术实现 是次要。
49 楼 路过心中 2009-05-06  
高性能在是主要,至于技术实现 是次要。
48 楼 路过心中 2009-05-06  
高性能在是主要,至于技术实现 是次要。
47 楼 狂放不羁 2009-05-06  
icewubin 写道

这一点我的理解是这样的,银行业务的特点一般是外围系统加核心系统,外围无论如何优化业务,都是要调用核心系统的接口,银行固有的业务特点使得相当一部分业务办理的操作无法做深层次的优化,例如借记卡余额的查询(这种查询操作是不可能做缓存的,对于外围系统来说,每次查询必须要调用核心系统的接口,而不能自说自话的做缓存)。

那么然后说核心系统,暂且不论核心系统是否通过缓存优化一些查询操作,至少目前基本上大部分操作还是依赖于数据库的。我叽叽歪歪说了这些,无非就是举个例子,有这样的场景,无论中间层或外围如何优化,最终对于数据库的压力是固有的,逃不掉的。例如每小时处理10000笔转账业务,这必然带来10000次数据库操作(肯定不止),这是业务特点加上目前的银行核心系统架构带来的固有的数据库的压力。

在这种场景下,因为银行的海量数据,不得不在核心数据库上动脑筋:
1.某人说,数据库做集群不就完了么?Scale Out,可惜几乎不可能,原因复杂一言难尽。

2.一般只能做Scale Up,加CPU,加内存,一般使用大型机,来提高吞吐量。

举这个例子也是想拓宽楼主视野,不同行业,不同业务特点带来的系统瓶颈的位置都不太一样。


呵呵,非常认同这一点。我实习的时候也参与了一个建行项目的培训和开发,所有的压力,我们都是丢给了建行核心的业务处理服务器去处理,我们所做的就是知道如何调核心接口就OK了,结果最后性能非常慢,也只能依靠垂直伸缩了,水平伸缩性的可能性很小。最后我们也只能对客户说“IBM的东东都用了,这性能还是上不去,我们也没啥子办法”呵呵。

ps:经过讨论自己也学到了很多,每天能理解深入一点,积累一点,快乐的成长,感觉满好的。多谢各位老哥耐心的讨论和无私的经验分享。真希望通过我们大家共同努力使得中国的软件行业能变的强大起来,登上国际舞台。
46 楼 icewubin 2009-05-06  
fjlyxx 写道
关于第二点 还需要仔细的斟酌,因为把业务弄得数据库要考虑数据库的压力问题.业务放置的位置要么在前台逻辑要么在数据库.放在前台可以减缓数据库压力,放在后台可以提高前台处理能力. 但是有这么一个问题,如果前台有需要进行群集的时候  后台数据库的业务逻辑如何处理. 这时候跑数据库也许就是一个瓶颈了. 总之还是要小心跑数据库这个陷阱,需要很充分的考虑.

第二点我没有说清楚,其实每一点都应该写得具体一点,手酸啊。

这一点我的理解是这样的,银行业务的特点一般是外围系统加核心系统,外围无论如何优化业务,都是要调用核心系统的接口,银行固有的业务特点使得相当一部分业务办理的操作无法做深层次的优化,例如借记卡余额的查询(这种查询操作是不可能做缓存的,对于外围系统来说,每次查询必须要调用核心系统的接口,而不能自说自话的做缓存)。

那么然后说核心系统,暂且不论核心系统是否通过缓存优化一些查询操作,至少目前基本上大部分操作还是依赖于数据库的。我叽叽歪歪说了这些,无非就是举个例子,有这样的场景,无论中间层或外围如何优化,最终对于数据库的压力是固有的,逃不掉的。例如每小时处理10000笔转账业务,这必然带来10000次数据库操作(肯定不止),这是业务特点加上目前的银行核心系统架构带来的固有的数据库的压力。

在这种场景下,因为银行的海量数据,不得不在核心数据库上动脑筋:
1.某人说,数据库做集群不就完了么?Scale Out,可惜几乎不可能,原因复杂一言难尽。

2.一般只能做Scale Up,加CPU,加内存,一般使用大型机,来提高吞吐量。

举这个例子也是想拓宽楼主视野,不同行业,不同业务特点带来的系统瓶颈的位置都不太一样。

相关推荐

    电力拖动自动控制系统运动控制系统课后思考题习题答案

    电力拖动自动控制系统运动控制系统课后思考题习题答案 本资源为电力拖动自动控制系统运动控制系统课后思考题习题答案,涵盖了电力拖动自动控制系统运动控制系统的主要知识点,包括直流电动机的调速方法、直流PWM...

    航空订票系统性能方案(手写完整版)

    航空订票系统性能方案(手写完整版) 航空订票系统性能方案是 LR 自带航空订票系统的性能方案,旨在指导航空订票系统的测试。该方案对航空订票网站系统的性能测试进行了详细的规划和设计。 航空订票系统的主要功能...

    系统性能测试报告

    在进行系统性能测试时,通常会依据一套既定的框架来组织测试报告,这份XX系统的性能测试报告即是按照这样的框架来展开的。下面将基于报告内容,详细解释系统性能测试中需要考虑的关键点。 首先,测试目的清晰地指出...

    及偶极子对系统性能的影响

    在自动控制系统设计中,系统性能的评估至关重要,主要包括稳定性、动态性能和稳态性能三个方面。稳定性是控制系统的基础,它衡量的是系统在受到扰动后能否自行恢复到平衡状态。一个稳定的系统,其闭环特征方程的所有...

    系统性能测试报告模板

    - **测试结果:** 在长时间运行后的系统性能指标。 - **结果分析:** 分析稳定性测试的结果,评估系统长期运行下的可靠性和性能下降情况。 **5.4 EOD 批处理测试** - **日常批处理:** 日常需要进行的批量处理任务...

    性能测试-系统吞吐量及用户并发量

    ### 性能测试中的核心知识点解析 #### 一、系统吞吐量的理解 - **定义**: 系统吞吐量是指单位时间内系统...这些知识点对于理解和优化系统的性能至关重要,有助于开发者和测试人员更好地评估和提升系统的性能表现。

    电力拖动自动控制系统第4版_思考题答案

    电力拖动自动控制系统是...总的来说,电力拖动自动控制系统的分析和设计涉及电动机的电气特性、控制策略、反馈机制等多个方面,需要深入理解电动机的工作原理以及自动控制理论,以便有效地实现系统的调速和性能优化。

    web应用系统性能测试

    ### Web应用系统性能测试 #### 一、引言与背景 随着互联网技术的快速发展和企业信息化建设的深入,Web应用已成为现代企业业务运作的核心部分。然而,随着Web应用的广泛使用,用户数量激增和数据量剧增的问题也日益...

    软件系统性能的常见指标.doc

    软件系统性能的常见指标 软件系统性能的常见指标是衡量软件系统性能的重要指标,它们可以帮助我们了解软件系统的运行状况,查找性能瓶颈,并优化系统性能。下面是常见的软件系统性能指标: 1. 响应时间(Response ...

    Go-《关于Go性能优化的思考》概述了编写高性能Go代码的最佳实践

    《关于Go性能优化的思考》这本书提供了许多关于如何编写高效Go代码的策略和技巧。本文将深入探讨这些最佳实践,帮助开发者提升程序性能。 1. **内存管理与垃圾回收** Go语言采用自动垃圾回收机制,但在某些场景下...

    从啤酒游戏看系统思考.pptx

    【啤酒游戏】是一种模拟供应链管理的互动教学工具,旨在揭示系统思考的重要性。在这个游戏中,参与者分别扮演制造商、批发商和零售商的角色,通过订单和交货进行互动,模拟真实市场环境中的供求关系。游戏的设计旨在...

    经典性能测试用例参考模板

    - **结果评估标准**:测试结果需满足预设的系统性能需求。 **结果评估**: 1. **响应时间**:通过测试收集的数据,分析平均响应时间是否在10秒以内,以验证系统在高并发下的处理速度。 2. **资源利用率**:监控...

    成功的Web应用系统性能测试

    【Web应用系统性能测试】是确保系统稳定性和用户体验的关键步骤。在进行性能测试时,我们需要考虑多种因素,包括但不限于Web服务器配置、FTP服务、日志服务器以及邮件中继服务等。性能测试的目标是评估系统在高负载...

    淘宝性能测试白皮书V1.0

    性能测试模型,如PV计算模型、PV-&gt;TPS转换模型、TPS波动模型以及共享中心性能测试模型和前端页面性能测试模型,都是为了更准确地模拟和预测系统性能而构建的。这些模型有助于测试人员深入理解系统行为,并以此为基础...

    深度:国产嵌入式操作系统发展思考.docx

    LiteOS 是一个轻量级的嵌入式操作系统,具有低功耗、低成本和高性能的特点。 二、国产嵌入式操作系统的挑战 国产嵌入式操作系统面临着许多挑战,例如技术门槛高、人才缺乏、市场竞争激烈等。同时,国产嵌入式操作...

    系统工程 思考与练习题.docx

    系统分析是系统工程的核心,它包括问题定义、模型建立、方案评估和决策制定等步骤,旨在优化系统性能。 第四章关注系统模型的特性,如解释结构模型,它用于表示系统元素之间的因果关系。模型化是理解和预测系统行为...

Global site tag (gtag.js) - Google Analytics