>>>缓存缓存,一个“存”,一个“缓”,“存”自然是存在内存,
楼主的东西,可能指的是外存吧?本来是要存入外存(硬盘)的,缓一缓再存进去。
>>>它是class,当然是class,因为我用的是java。
我说错了,本来应该说是Object。误导了你。
这Object,一般是代码与数据的结合体。把整个Object缓存?有必要嘛?里面的code可是不变的、只读的。有必要也缓存嘛?本来存也不需要存的,何必缓呢?
我就是有许多不明白,才打搅的。

我不知道大家是不是真的明白缓存的意义。缓存是真的为了取代持久化的东西么??

你使用的硬盘,上面会标明有8M的缓存,CPU的cache是为了提高内存访问速度而设置的缓存,缓存就是为了提高访问速度而运用的一种手段,而不是必须得方法,不要神话它,这个技术在计算机发展的二十年前就已经存在且比较成熟了。

那么缓存里面存什么??比如你有一个箱子,你如果用来放衣服,那么你可以称之为衣箱,如果放水果,可以称之为水果箱。但所有的箱子就是来放东西的。当你放衣服的时候你查找的方式是按照一件一件的方式来找,如果是水果就是一个一个或者一种一种,但是对于箱子而言,放的是水果还是衣服有讨论的意义么??缓存就是那个箱子,里面放的是数据,你用OO的方式放进去的就要按照object来找,如果是放进去的是一个数组,那么你取出来就一定要是数组。哪有说缓存就是为了OO设计的。

缓存的对象跟方法有关么??无关!!不光缓存无关,就算你new了长千上万个对象,方法始终存在程序的代码区,有且只有一份,而属性放在了数据区,两个同类而不同的对象区别只在于属性,方法是无区别的。

最后劝一下banq不要对自己不知道的领域妄加评论。

缓存:就是以空间换时间,和Acoder说的一样和里边装什么没有关系;有关系的是DDD,如果把聚合缓存起来就不能不涉及到同步和加锁力度的问题,是粗了好还是细了好,他们各适用什么样的实际开发状况?

to acoder老哥。
>>我不知道大家是不是真的明白缓存的意义。缓存是真的为了取代持久化的东西么??

缓存不是取代持久化存储的。持久化存储不可能被取代。我想说的是,大家普遍认为的缓存应该是只需要读的,但是我们经过业务对象的建模,形成的业务对象是线程安全的,这样放到缓存中就可以全局的并发写操作。并且这样有个好处就是,锁是针对具体的场景的,因为我们自己最清楚那些业务对象的并发访问会很大,大访问量的业务对象可以采用细粒度的锁。如果不这样在并发情况下就需要采用事务隔离级别加乐观锁或者悲观锁来进行,但是悲观锁是粗粒度的锁,粒度粗了,并发性也就减低了,而乐观锁有会造成冲突事务只能重来,而通过细粒度的锁既能保证并发性,同时还可以保证操作都能成功。其实采用缓存+业务对象细粒度锁是一种新的思路。新的思路必然面对新的挑战,挑战在这个帖子的前面也讨论了很多。

>>哪有说缓存就是为了OO设计的。

呵呵,OO为了提高性能,提高伸缩性所以才用了缓存。缓存用的地方实在太多,我们只是借用一下缓存来缓存业务对象。


[该贴被xmuzyu于2009-05-31 12:14修改过]

>>把整个Object缓存?有必要嘛?里面的code可是不变的、只读的。有必要也缓存嘛?本来存也不需要存的,何必缓呢?

缓存整个object有必要,这个object其实多数是聚合根。因为我需要全局并发写操作,而不是依赖过去的乐观锁,悲观锁来控制并发访问。

>>>缓存整个object有必要,这个object其实多数是聚合根。因为我需要全局并发写操作,而不是依赖过去的乐观锁,悲观锁来控制并发访问。
1)你知道在objects里,code与data各占多少?一起“缓存”,将增加多少系统开销?
2)正如ACoder所说,code与data是在不同区域的,把它们合在一起缓存,增加的开销,比由1)计算出来的还大。
3)又正如ACoder所说,由同一个class创建出来的objects,譬如说有100个,那100份data是各自独立的,而100份code却只有1份。
“聚合根”、“全局”、“并发”、“乐观锁”、“悲观锁”,不管你说多少上层的词,这底层就是这样。
到底如何缓存,才能提高效率?而不是反而降低了效率?

诸位:不管你所使用的是什么样子的缓存系统,他们都只能缓存数据,也就是对于对于一个object而言只能缓存属性,而不能缓存方法,这个是由于硬件指令导致的,不是你采用什么语言决定的。

至于锁,这是一个非常复杂的问题,比如对于一个链表,从效率上讲在需要修改的一个元素上锁定就好了,但是这样做有的时候会使得链表上的iterator失效,所以必须在链表上加锁。

乐观锁与悲观锁的选择上,我原来就说过,一切应当以可靠性作为基础。

“缓存就是为了提高访问速度而运用的一种手段”
这句话说的很对,缓存只不过是一种优化的手段而已,目的就是在完成需求功能的基础上进一步提高(数据或对象)访问速度而已。

“缓存就是为了提高访问速度而运用的一种手段”
这句话说的很对,缓存只不过是一种优化的手段而已,目的就是在完成需求功能的基础上进一步提高(数据或对象)访问速度而已。最简单的买cpu的时候首先是看主频,几个核,附加才看一二级缓存多少一样
------------------------------------------------------------------------------------------
不过把整个应用中所有的对象都载入缓存这种策略不太可行,ddd中我记得有一段就是描述的这种情况(把应用中所有对象都载入缓存),最后被证明是很慢的。
------------------------------------------------------------------------------------------
其实说到面向对象系统中的缓存,主要有三个切入点
1.事务相关缓存:可能是一个数据库事务,可能是一个对话,只有在当前工作单位有效,这样的缓存不会被并发访问
2.process相关缓存,被并发的工作单元或事务共享,缓存中的数据被并发线程访问
3.集群相关缓存,同一台机器的多个process之间,或者集群下的多个机器之间共享,主要关注网络通信

对于应用以上几种缓存的一点经验是对于多用户,可伸缩性要求很高的web或企业级应用,应该避免内存中保存锁(除一些内容管理类型的应用程序),而推荐大量应用事务范围缓存(类型1),但是也有限制,比如内存要求很大,因为事务范围内存消耗和并发数成正比

对于process相关缓存(类型2)或集群范围缓存(类型3)一个比较好的备选
a.很少改变的对象
b.不重要的对象(如内容管理类型的应用)
c.应用程序固有(数量一定)的对象
d.被其他类的很多实例引用的实例(称为引用数据)
[该贴被yellowcat于2009-06-02 15:14修改过]
[该贴被yellowcat于2009-06-02 15:23修改过]

我不是反对缓存,只是想弄清楚,这缓存如何提高系统性能。
1)如果是为读而缓存
CPU的cache,在读取指令时确实能大幅度提高效率。因为,指令是顺序存放的,不遇到JMP、CALL、RET等指令时,是顺序提取。
但是,对于几百万、几千万条记录的数据库,几千、几万个用户来说,如何来保证访问的全集中在一块区域?
2)如果为写而缓存
事务不及时写盘,如何保证原子性?
3)读缓存也有问题
读的区域,别的进程做了更新,你再读,就是脏数据了。
我怕,在很多场合,缓存反而增加开销,降低系统性能。

的确,因为添加了一层中间件,增加了复杂性,但是提高性能是肯定的,好比微波炉,用得好自然能大大加快烹饪的速度。
存在即合理,如果不能提高性能,那么缓存为什么这么多人在用呢?

十个程序员里面有几个能够精通hibernate的使用呢?
[该贴被yellowcat于2009-06-02 22:53修改过]

看了xmuzyu的回复,提到业务对象要线程安全才可以并发写操作,这说明缓存并不能保证并发安全,也可以认为锁是在业务对象本身,和缓存没什么关系。
这样的话,缓存层又做了什么,是一块放对象的内存?那么放在缓存的对象和普通的又有什么区别。

看了回复ACoder说的还可以。

关于锁:
现在的web接入server,比如apache、tomcat之类的都是多进程的,一个请求一个进程。所以对共享内存进行正确操作就必须要有同步机制,加锁是必须的,上面有人所说的乐观锁、悲观锁我估计就是读锁、写锁。在linux/unix中锁从程度来说只有读锁、写锁、不锁,从时间上来说只有阻塞式锁、非阻塞式锁。

当然你也可以说你自己做一个逻辑server,web server全部接入到逻辑server处理数据,逻辑server起单进程,这样就可以不用共享内存,也就不用锁了。这样确实是不用锁了,这样你的程序会慢的吓死人,一堆请求堵在那里等着处理。所以,虽然很有必要做一个逻辑server来剥离web接入和逻辑数据处理,但是也必须是多进程的。当然锁就不可避免。

实现锁的方法也是多种多样的:原子操作,信号量,文件锁等等都是可以的。

缓存说白了就是一块共享内存。共享内存的意义就是进程间通讯。
缓存中还有一个概念叫做命中率,了解了这个概念之后就会明白被缓存起来的每组数据(比如一组数据就是一个用户的资料)越小越好,这样命中率才能更高,如果命中率低,那你的缓存是在降低效率而不是提高效率。所以缓存整个类的做法好不好大家也应该知道了。
命中率解释:举个例子,你现在从程序去A的相关信息,发现缓存里面有(这就命中了),直接返回给你;如果没有(没有命中),就要先到持久层(DB)去取数据,然后放到缓存里,再返回给你,这样比没有缓存还慢。所以,当你有100组数据要存,但是可用内存大小只能存50组数据(到了50之后的缓存数据就只能覆盖其他的),你的命中率应该就在50%左右,如果你每组的数据变小了,内存可以放80组数据了,那么你的命中率就提高了,自然程序响应速度就快多了,磁盘读写是相当慢的。所以,要使每组数据最小,而把整个类放到缓存的做法可取吗?
缓存也分2中:同步缓存和异步缓存。
这个主要是针对写而言,读是不存在的。所以任何高命中率的缓存对读的性能提高相当大。
同步:当更新数据时,先把数据更新到缓存,然后放入持久层,放入成功后再返回成功信息。
异步:当更新数据时,先把数据更新到缓存,然后返回成功,之后再去把数据放到持久层。
所以同步缓存对写操作来说没有任何的提高。异步缓存对写操作性能有很大的提高。
那为什么不全部用异步缓存呢?因为异步存在风险,万一更新到持久层失败了怎么办,万一在更新之前那块内存被覆盖了怎么办?
所以要看具体业务模型选择,异步缓存一般同步机制用消息队列,但是消息队列又不是无限大的,各个操作系统不一样。
上面是我所了解的,希望对大家了解缓存有一定帮助。

to usejava
缓存是对象在内存中的宿主,而数据库是对象被压扁后的数据的宿主。缓存仅仅只能保证放入和读取操作线程安全的在(至于缓存的设计不需要我们考虑,开源缓存很多),而业务对象的线程安全性要根据具体的项目需求,自己实现细粒度的锁控制,具体来说就是业务对象的状态尽量用并发容器而不是同步容器,加锁一般不要加载聚合根对象,而是将聚合根按照可变和不可变划分,加锁只加载可变的对象身上。这样通过细粒度的锁来提高系统的并发量。

至于你说的区别,区别就是缓存中的对象要保证自己的状态不变量,所以我以前也说过,对象的缓存中,首先是对象的设计,只有设计好了对象才适合放到缓存中。这些是我自己的做法,而面向对象的设计以及并发编程也是我自己的爱好。

不过这样做对团队整体素质要求很高,毕竟不是每个人对并发编程都很熟悉。

周大哥,你越来越强悍了!!!!