>>比如我改变了哥哥的某个特性(比如统一一下两个人穿一样颜色的衣服),那么方法是先换一个人之后再换另一个人,还是招两个人给兄弟两个一起换那??如果是第一种方式,就需要同步时间(时间成本以及锁),第二种方式需要更多的资源(双线程,事务锁),同时如果是分布应用还需要网络传输。这些东西你从来不用考虑是么??

呵呵,这种情况下,兄弟俩穿一样颜色的衣服,这个状态就是不变量约束,而这种状态是有兄弟两个对象的状态共同组成的,所以我一般会将其封装,比如有一个名字叫"BrotherGroup"的对象,这个对象暴漏一个换衣服的方法,系统中所有的换衣服的操作,必须通过BrotherGroup的changeCloths()方法,而不是将兄弟两个随便暴漏给其他对象,让其随便换衣服,这样这个方法要保证兄弟两个的衣服一颜色在执行完这个方法后是一样的,而衣服颜色一样不仅是BrotherGroup对象的不变量约束,同时也是changeCloths()方法的后验条件,这样我们就通过控制外层的对象的方法达到了控制内部封装对象的状态,此时即使兄弟两个对象各自换衣服的方法不是线程安全的,只要我们保证BrotherGroup的changeCloths()方法是线程安全的就行了,这也是并发编程中的“实例限制”。

ps:多线程环境下的状态控制可以分为两种,一种是共享变量的控制,另外一种就是不共享变量来控制,至于我们讨论的缓存采取的是共享变量的并发访问控制,此时需要通过锁{JAVA内部锁,私有的对象锁,共享的外部锁(当然共享的外部锁个不推荐使用,因为状态很难跟踪)}来保证对象状态的不变量。而另外一种不共享状态的并发访问我们也可以采用threadlocal,栈限制等技术来解决。所以此时我们讨论的缓存是一个全局的缓存,就是共享的,所以通常只能通过锁的机制来保证状态的合法性。

所以我一直都说面向对象的设计对并发控制很重要,封装的越好,状态越容易控制,暴漏的越多,对象的安全发布就成为了大的问题。所以要想容易控制并发访问时对象的状态,请设计封装良好的对象模型,这样当我们系统中用了封装良好的对象模型后,自然而然的我会想到用缓存。对于那些丑陋的,没有经过封装以及不变量约束,方法后验条件保证的模型,即使你用了缓存,也是自找苦吃呵呵。

好,请时刻记住,你现在用的仍然是RDBMS。
其实,只要真正了解了RDB,就不会对缓存有这么些莫名其妙的说法的。

要消灭敌人,必须首先要了解敌人。你要消灭DB,也必须先要了解DB。
现在,有人退了一步,好像不打算消灭DB,而只想贬低DB了。可贬低DB,也需深入了解DB。

呵呵,我真的感到很无奈,xmuzyu我从来也没有说过设计的不重要性。你现在在做建行的项目什么??那么我想知道他们暴露给你的核心交易接口是数据库么??还是一个交易接口??是不是对帐务的变更只能通过接口来进行。(你可以去查数据库,查看变更,但是在生产系统中所有的帐务交易全部都经过且只经过一个接口),这算不算封装??
其次,你的那个设计方法如果是分布式应用,谁来保证你每个应用服务器上的数据同步??是你的容器么??那么你使用什么容器,容器同步时间是多少,容器采用何种方式同步,这在建行进行项目选型的技术文档中你一定会看到的,否则建行根本就不可能使用,不要说建行系统差,建行在技术领域多年来为其他银行培养了大批的人才。

》》所以我一直都说面向对象的设计对并发控制很重要,封装的越好,状态越容易控制,暴漏的越多,对象的安全发布就成为了大的问题。所以要想容易控制并发访问时对象的状态,请设计封装良好的对象模型,这样当我们系统中用了封装良好的对象模型后,自然而然的我会想到用缓存。对于那些丑陋的,没有经过封装以及不变量约束,方法后验条件保证的模型,即使你用了缓存,也是自找苦吃呵呵。
这一段话我深表同意,但是你觉得有比SQL更好的封装么??你之用四个就可以完成所有的操作,这种高度的封装难道不值得你的去学习么??

to Acoder老哥
呵呵,Acoder老哥,我也没说你不重视设计,从和你的讨论中我也能体会到,你是一个经验丰富的前辈。说话也比较中肯,这点也是我一直和你讨论的原因。我上面的那个例子没考虑分布式情况,也没仔细想,我是完全站在封装以及如何去应对多线程环境状态控制角度去考虑的,现在项目几乎不会用到真正的分布式,最多也就是做个集群而已。当然了,您做的电信项目可能经常使用到分布式。

呵呵,其实说句实话,真正财主们的系统,是靠人家的高性能的硬件配置满足的,人家更讲究规范的一致性,更讲究项目管理,对于系统的性能问题考虑的不多。我们现在做项目说实话,几乎都没有到OO,虽然用OO语言JAVA。为什么我这么说?因为我们模型是根据银行的数据库表,然后让封装好的IDE自动导出的,每个类都很多getter,setter,每个表都会自动生成一个模型类,每个类都没有经过严格的OO设计,比较松散,所以我们的类其实就是数据容器,所有的交易其实都是马丁大叔讲的事务脚本,领域模型没有,只有积累下来的数据库表。一个简单的交易hibernate都会生成很多的sql,我看的眼花缭乱呵呵。hibernate其实被误用了。

我觉得现在大家对设计不必讨论太多了。谁也没有不重视。
讨论的问题应该是只集中在一点:持久化。
banq的意思应该是对象的更新是由仓库通过基础层在内存/缓存做更新,同步到数据库这个会有后台进程做,通过集群保证数据冗余做容灾处理。
“反方”的质疑也是这种持久化机制,虽然可以保证一致性,但不能避免数据的丢失(缓存机器当掉或者数据库当掉),而且这部分有没有一个可以说服人的设计,说真的,我觉得这种同步挺麻烦。
当然,说数据丢失,数据库当掉也一样,只能通过redo恢复。但我觉得事务相关的东西数据库已经做得非常好了没必要缓存也做一套出来。

我个人觉得缓存只是在程序设计中一个辅助设计,对于一些读多写少的系统,使用缓存是比较好的选择(当然相当一部分系统属于这一范畴),但是对于实时性要求比较强,且更新频繁的系统使用缓存的时候最好考虑一下,特别是客户对于客户对于数据安全要求程度比较高的时候,有的时候使用缓存不一定是很好的事情。所以项目要因项目而设计,而不要说一样东西可以解决所有的问题。

最后说一下我理解的IBM,xmuzyu说建行是财主,我估计你看到的基本都是小型机一类的东西,十有八九就是IBM+EMC之类的组合,我工作中接触了不少这样的组合,IBM的东西速度快么?我个人认为还可以,不是非常快,但是IBM的产品线最大的特色是稳定,是超级稳定,IBM通过一系列的方式,软硬结合保证了数据的稳定性,所以对于大型企业,更愿意接受这样的东西。性能不行,可以通过技术来提高,但是数据如果丢了错了,那么官司是打不起的。

同意axlfu的看法,我提到的关于系统崩溃造成数据不同步的问题,没有人正面回答。都在大谈性能问题。我的观点是,一个系统如果连最基本的数据安全都无法保障,再好的性能也没用。

ACoder的看法很对,系统设计要看具体需求,DDD也许是好东西,但是不一定适合所有场合。

最后再强调一下我的问题:
缓存数据没有写入之前,系统崩溃造成的数据丢失和不一致,如何避免?不能避免的话,如何解决数据库里的不一致数据?

这个问题解决不了的话,什么设计,性能,都没用。

大家讨论很认真,焦点还是在数据库的稳定性,很多人总是想基于内存万一服务器崩溃怎么办?

如果是这种想法,我觉得大不必担心,因为他可能没有想到分布式缓存,分布式缓存就是多台服务器合在一起象一台大内存服务器,这个原理其实我已经在原来EJB集群中大量谈到,万一有一套服务器崩溃,其他会顶替上,而且可以做fail over,也就是把刚才失败的计算操作继续完成,5台服务器有一两台崩溃没有问题,5台不会全部崩溃。

再说了,数据库服务器常态是一台,难道五台或几十台集群服务器的稳定性都抵不上一两台数据库服务器的稳定性?所以,系统崩溃这个担忧是不必的。

那么我们为什么要追求在内存中进行并发写操作呢?因为高性能追求啊,高性能是无止境的,一个频繁修改的状态数据是在内存缓存改快呢?还是通过tcp/ip网络跑到数据库中修改,然后大家都到那里去读,哪个更快呢?一目了然。

大家更多能多读读本站EJB集群的讨论,就知道缓存 分布式缓存 云计算的发展必然性。要从一个更广更高的架构来看待技术问题。

>>万一有一套服务器崩溃,其他会顶替上,而且可以做fail over,也就是把刚才失败的计算操作继续完成,

这里要澄清一个概念,分布式缓存,同样数据是只在一台服务器存在,还是所有服务器都有。只有一台服务器有的话,应该没法fail over,继续操作,因为数据都没了。所有服务器都有的话,内存也太浪费了,而且还要承担缓存数据同步的开销。

>>难道五台或几十台集群服务器的稳定性都抵不上一两台数据库服务器的稳定性?所以,系统崩溃这个担忧是不必的。

集群服务器是否能保证任何一台服务器崩溃都不会造成数据丢失?即使能保证,集群失效或者数据库崩溃都会导致系统停止服务,增加集群只会使整个系统的可靠性下降。
没有不崩溃的系统,因为可能性小就不担忧是不对的。如果可以不担心,还要硬盘和备份干什么。
不管如何设计系统,采用什么技术,都是要保证业务功能正常完成和必要的数据安全。这是前提,性能是第二位的。

在此还要向banq请教个问题,采用DDD设计出域模型后,采用框架持久化到数据库,数据库结构是否由框架和模型自动生成?是否可以人工设计和干预?

非常推崇bang说的方案,从我的使用中可以验证这一点,虽然从目前的实际情况中,考虑事务异常,我没有以缓存对象为基准同步数据库,但保持数据的一致性不是一个问题。要提升系统的性能、并发性,缓存是最好的解决方案。

>>但保持数据的一致性不是一个问题

非常关心缓存崩溃造成数据丢失的风险,可否详细解释为什么这不是一个问题。

>集群失效或者数据库崩溃都会导致系统停止服务

多了解一下集群原理,集群就是多台服务器轮流干事,一个不行,另外一个顶替上,就像你工作岗位有两个人,你生病了,另外一个人顶替你可以继续干活,你可能钻牛角尖,两个人都生病了怎么办?那么就三个人,如果三个人生病了,怎么办?那么就四个人,如果四个人生病了,怎么办?那么就五个人,你总要我这样一直数下去,数到数目大到你觉得不会崩溃为止吧?

集群整体失效可能性就相当于人走路会摔死的可能性,如果都这么钻牛,那么你就别用电脑打字编程了,或者,你每一毫秒按一下保存,只有直接面对磁盘你才放心?如果磁盘坏了呢?那不如用白纸写下来,或者石刻吧。

banq你说的那叫应用程序的集群,即每个服务器都提供一样的服务,但是我们讨论的是数据的集群,这是完全不同的概念。你那种方式很好解决,但是数据集群没有那么简单。

>>那么我们为什么要追求在内存中进行并发写操作呢?因为高性能追求啊,高性能是无止境的,一个频繁修改的状态数据是在内存缓存改快呢?还是通过tcp/ip网络跑到数据库中修改,然后大家都到那里去读,哪个更快呢?一目了然。
而且你说那个快,你集群之间的机器什么怎么连接的,不都是TCP/IP协议么??你修改一次还要去集群寻址,如果是多台进行的还要事物,比一台计算机那个快??

banq误解了我的意思。我同意集群比单机的可靠性高。
但是应用集群,或者说分布式缓存集群可以看作一个整体,数据库是另一个独立的整体。应用集群和数据库功能上不可互相替代,也就是说互相独立。
一个系统由两个独立部分组成的话,整个系统的可靠性是两部分正常运行概率的乘积。
假设应用集群和数据库的正常概率都是0.9,那么整个系统的正常概率只有0.9*0.9=0.81。所以说,系统独立的部分越多,可靠性一般越低。
增加一层独立的缓存服务器只会是整个系统的可靠性下降。

另外,我也接受系统崩溃会丢失数据。我的问题再重复一次,问题是丢失以后造成的影响如何恢复。例如:数据库没有写入,缓存崩溃,必须先改正数据库才可以重新生成缓存。但是数据库由域模型和持久层自行设计,其结构重点必然是支持域模型。
作为维护人员,如何去维护这个根本不是自己设计的数据库?如何知道该怎样修改数据库数据才可以解决数据不一致问题?

在崩溃的情况下 数据不一致问题就不会发生,因为可以靠事务保证,要么全部持久化包括内存更新全部完成,要么内存也不更新,多个数据库也不更新,你可以了解一下分布式事务这些。