缓存框架所要解决的基本问题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
缓存框架所要解决的基本问题
Cache 框架,顾名思义即数据的暂存场所和管理。那么该系统的两个核心功能就开始上演了,即存放数据的一个容器和管理缓存容器。就像数据库服务器软件一样,他有一个和新的数据存放场所,同时还有一个管理数据的管理系统。在这个管理系统中就出现了一系列的事务处理,比如说添加,删除,更新以及刷新,删除不成功时如何操作等等。那么该缓存框架需要完成的基本任务就是如何来实例化这么一个数据存储的仓库以及如何有效的来管理仓库中的这些数据,除了上述的这些操作外,还有当仓库中的数据当容量值是再次放入一个缓存实体时该如何有效的淘汰已存在的缓存实体以及该缓存仓库中的数据是否持久有效还是分区管理等等。那么又该如何实例化这么一个缓存仓库呢?首先要考虑的第一问题就是采用何种数据结构来高效的存储这些数据?
1、如何来管理缓存中的对象?----OScache中是通过AbstractConcurrentReadCache和Cache强强联手来管理的
2、如何来管理内存容量的问题?
3、给缓存中添加一个新的缓存实体时,需要注意哪些问题?
当向缓存中添加一个实体时,应该完成哪些必要的业务逻辑呢?我们可以把缓存看做是一个组件,添加一个新的实体是促发该组件的一个事件,该组件能够对该事件进行捕捉并能够进行相应的处理。
4、如何有效的来淘汰缓冲池中对象?
5、如何来管理缓存实体的刷新问题?
实体的更新状态信息具体分应该分为以下几种:分别是还没更新、处于更新状态中、更新完成、更新取消。其中用一个变量来保存当前的更新状态,也即跟踪每一个缓存缓存对象当前处于一种什么状态。同时用什么来表明一个缓存实体过期的标识呢?这里有两种方案:其一就是线程拥有的数量,当线程拥有的数量变为0时,就从缓存容器中释放。其二就是设置一个TTL 发呆的最大
时间。就像是Seesion来管理他内部存储的对象一样。如果再多长时间内没有访问,则及时清除缓存中的一部分对象。这里应该分两种情况来管理缓存中的实例。不然就是去了缓存的真实作用。如果实时性比较高的数据,比如说股票等,那就给这些缓存实体设置一个TTL时间,如果不是实时性数据,那么就将该值设置为-1,比如用户信息这一类的数据。那么如何来判断该缓存实体是否需要刷新呢(OsCache中的CacheEntry的needsRefresh方法)?
(1)当该缓存实体从来都没有更新时,则更新;
(2)如果该实体之前已经刷新过了,则需要刷新
(3)如果传入的参数为0,那么说明该缓存须立即刷新,则刷新;
(4)如果实体刷新策略对象()不为空
(5)当缓存实体的生命周期时间到期了(用设置的刷新期加上最后一次访问的时间距现在的时长为标准,如果小于当前的时长,则说明已经过期了,则需要刷新,否则不需要),
6、如何检测缓存中的数据和数据库中的数据同步与不同步的问题?
7、如何实现磁盘缓存?
磁盘缓存该在什么时候实现呢?这里有两种方案:
(1)当基于内存缓存时容器满时,被淘汰的缓存实体该如何来处理,是直接被jvm的垃圾回收机制回收还是将他们暂持久化到本地?如果是暂时的持久化到本地,那么这些实体又该什么时候置换进内存呢?当内存中未命中时此时应该到外存去查找是否存在。因此系统也应该保留一个缓存文件的集合,因此到时就可以直接在这集合中判断外存是否具有该实体的本地持久化,若有则表示外存命中,则此时应该根据具体的替换算法将内存缓存的实体进行置对换出。从而完成一次内外存一次数据的对换。注意是在当内存未命中时外存命中的情况下进行对换。
(2)基于数据库驱动的网站可以是先将一部分的数据读取出来,这些数据通常是固定式在短时间内不会发生很大变动的数据。这些数据就可以在缓存系统启动的时候通过配置文件的方式配置好。系统就可以在后台悄悄的将这些数据提取出来进行优化处理,下次系统需要取出数据时就可以直接从本地持久化文件中进行提出或者直接从内存中,这将会大大提高系统的响应速度,同时也减少了数据库并发链接的负载。从而给那些实时性较高的数据同数据库的连接提供了比较宽松的机会。如果该部分数据量较大,比如达到上千万级别的java
对象,这时如果jvm的内存配置的较小的话能可能很快就会出现内存溢出的现象,那么又该如何解决该问题?其中的方法就是给出缓存实体容器的大小,这样一来,既不失缓存的最初设想,加入这部分数据一下子全部取出那么在处理时既会带来相应异常的产生,同时也是眉毛胡子一把抓,就没有区分度。如果设置实体缓存的大小,我们强烈建议数据库健表示给出一个计数,即该行数据被选中的次数。那么每当系统启动时就可以有区分度的将这部分数据进行事先的提取。如果数据库建表时没有添加该字段信心,那么缓存系统应该设计自学习算法。该自学习算法需要完成以下基本的任务:
Ⅰ、此时持久化到本地的实例已经不是原生态的java实例,即刚刚从数据库中提取出来的实例。系统对这些实例进行了一次升级,我们称之为对象的升级。该升级需要完成以下几部分内容,给每一个对象添加一个命中的计数,同时添加在同一阶段在命中次数相同的情况每次命中的时间间隔,以备当内外存置换时当命中的次数相同时来更好的体现该缓存实体在时间局部性上更占有优势。
Ⅱ、这些对象该以何种数据结构来存储呢?HashMap?HashSet?Or TreeSet或者其他的数据结构。要使用何种数据结构必须对每种数据结构的特性要了解的相当清楚才能更好熟练的加以运用。这里简单的介绍一下常用集中集合的特点:
ArrayList:内部的实现方式是基于数组的,无容量的限制。但是有个默认的初始容量。因此在插入元素时可能要扩展此时可能会降低系统的性能,但在删除元素时并不会减少数组的容量,但系统也提供了一个后门可以让程序员来维护该容量的大小,即trimTosize方法。当内存紧缺时可以使用该方法来优化内存的使用效率。当要从中查找某个特定的元素时或者判断该集合中是否包含某个特定的元素时底层的实现是通过equals方法来实现的。因此当系统打算用ArrayList集合来存储一个java实例时,可考虑是否要重写父类的equals方法;若要向集合中进行数据的插入或者移除,将会是比较耗时的,但是基于角标的查找其事件复杂度为O(1);并且有时非线程安全的。
LinkedList:基于双向链表机制的实现,元素的插入和移动较快,当是查找的事件复杂度为O(n),当查找某个特定的元素时也是基于equals方法来实现,同时该集合的内部操作也都是非线程安全的,这就需要我们程序员自己来维护多线层访问的安全性。