java本地缓存

1、为什么要使用缓存

由于服务器、数据库、网络等资源有限,无法支撑越来越多的请求与计算量,所以将一部分数据放在缓存中,以此减小薄弱环节的计算量和请求流程。

网站中缓存的应用场景:
        1:可以缓存整个页面的html,提高访问响应能力;
        2:针对局部页面元素进行缓存;
        3:对复杂数据的结果进行缓存,例如一个查询需要结合多个数据集,然后根据这些数据集进行相应的运算,即使每个子集查询有缓存,但还是需要额外的运算,这种情况可以考虑缓存计算后的结果。
        4:对耗时的查询进行缓存,例如产品列表页的查询。
        5:和上下文相关的用户数据,例如用户从订单埴写页进入到订单成功页,或者是从产品列表页点击详细产品进行预订时的订单填写页,此时这两个页面之间都需要传递大量的相关数值,我们可以把所有的数值封装在一个类中,然后通过缓存进行通信。

2、缓存的属性

缓存有以下几个重要属性:

Ø  命中率:命中率指请求次数与正确返回结果次数的比例,越高越好。

影响缓存命中率的因素:
        1:数据时实性,每个业务系统都对自己的数据有相应的要求,有些数据的实时性非常强,像每日的股票信息,这种情况如果设置了缓存,缓存的命中率会特别低。
        2:缓存粒度问题,一般来说是缓存的跨度太大,即此时的KEY值包含的条件太多,会出现缓存命中率特别低的情况。

提高缓存命中率的方法:
        1:增大存储介质的容量;
        2:对非常热点的数据进行捕捉,可以采用实时更新缓存的方式来平衡缓存与实时性的问题,例如可以单独开启一个后台服务来定时做更新缓存的工作。
        3:调整缓存KEY值的算法,尽量保证缓存KEY的细粒度,KEY-VALUE就是很好的细粒度例子。
        4:根据业务调整缓存的过期策略。

Ø  最大元素:缓存中可以存放的元素的最大数量。

Ø  清空策略。清空策略通常有以下几种:

n  FIFO:最先进入缓存得数据在缓存空间不够情况下(超出最大元素限制时)会被首先清理出去

n  LFU:一直以来最少被使用的元素会被被清理掉。这就要求缓存的元素有一个hit 属性,在缓存空间不够得情况下,hit 值最小的将会被清出缓存。

n  LRU:最近最少使用的,缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。

Ø  预热策略

全量预热:一开始就加载全部数据,适用于不怎么变化的数据,比如地区数据

增量预热:查询不到时,从数据源取出放入缓存内。

3、需要注意的问题

3.1缓存穿透

什么是缓存穿透?

一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。如果key对应的value是一定不存在的,并且对该key并发请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免?

1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。

2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。【感觉应该用的不多吧】

缓存雪崩

3.2缓存雪崩

当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(比如DB)带来很大压力。

如何避免?

1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。

2:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

3:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期(此点为补充)

3.3分布式缓存系统

分布式缓存系统面临的问题

3.3.1缓存一致性问题

1:缓存系统与底层数据的一致性。这点在底层系统是“可读可写”时,写得尤为重要

2:有继承关系的缓存之间的一致性。为了尽量提高缓存命中率,缓存也是分层:全局缓存,二级缓存。他们是存在继承关系的。全局缓存可以有二级缓存来组成。

3:多个缓存副本之间的一致性。为了保证系统的高可用性,缓存系统背后往往会接两套存储系统(如memcache,redis等)

3.3.2缓存穿透和缓存雪崩

上面有讲述。

3.3.3缓存数据的淘汰

缓存淘汰的策略有两种: (1) 定时去清理过期的缓存。(2)当有用户请求过来时,再判断这个请求所用到的缓存是否过期,过期的话就去底层系统得到新数据并更新缓存。

两者各有优劣,第一种的缺点是维护大量缓存的key是比较麻烦的,第二种的缺点就是每次用户请求过来都要判断缓存失效,逻辑相对比较复杂,具体用哪种方案,大家可以根据自己的应用场景来权衡。

1. 预估失效时间 2. 版本号(必须单调递增,时间戳是最好的选择)3. 提供手动清理缓存的接口。

上一篇:中国开发者利好消息


下一篇:MFC 三种消息