【转】缓存几个重要概念

缓存失效

平时设定一个缓存的过期时间时,可能有一些会设置1分钟、5分钟这些,并发很高时可能会出在某一个时间同时生成了很多的缓存,并且过期时间都一样,这个时候就可能引发一当过期时间到后,这些缓存同时失效,请求全部转发到DB,DB可能会压力过重。

解决思路: 

将缓存失效时间分散开,比如可以在原有的失效时间基础上增加一个随机值,比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件。

缓存雪崩

缓存雪崩可能是因为数据未加载到缓存中,或者缓存同一时间大面积的失效,从而导致所有请求都去查数据库,导致数据库CPU和内存负载过高,甚至宕机。

解决思路:

1、在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。这种办法虽然能缓解数据库的压力,但是同时又降低了系统的吞吐量。

2、分析用户行为,尽量让失效时间点均匀分布。避免缓存雪崩的出现。

3、如果是因为某台缓存服务器宕机,可以考虑做主备,比如:Redis主备,但是双缓存涉及到更新事务的问题,update可能读到脏数据。

缓存并发

有时候如果网站并发访问高,一个缓存如果失效,可能出现多个进程同时查询DB,同时设置缓存的情况,如果并发确实很大,这也可能造成DB压力过大,还有缓存频繁更新的问题。

解决思路:

对缓存查询加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询。

缓存穿透(缓存击穿)

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

解决思路:

1、如果查询数据库也为空,直接设置一个默认值存放到缓存,比如”^^”、“&&” ,这样第二次到缓存中获取就有值了,而不会继续访问数据库,这种办法最简单粗暴。

在返回这个&&值的时候,应用程序就可以认为这是不存在的key,那应用程序就可以决定是否继续等待继续访问,还是放弃掉这次操作。如果继续等待访问,过一个时间轮询点后,再次请求这个key,如果取到的值不再是&&,则可以认为这时候key有值了,从而避免了透传到数据库,从而把大量的类似请求挡在了缓存之中。

2、采用布隆过滤器,将所有可能存在的数据哈希到一个足够大的Bitmap中,不存在的数据将会被拦截掉,从而避免了对底层存储系统的查询压力。

大并发的缓存穿透会导致缓存雪崩。

缓存污染

一些非正常操作(eg:运营偶发性访问)而导致内存中出现很多冷数据,占用缓存有限的空间。

解决思路:选取合适的缓存算法(eg:LUR-N算法)。

缓存预热

单机web系统情况下比较简单。

解决思路:

1、直接写个缓存刷新页面,上线时手工操作下。

2、数据量不大,可以在WEB系统启动的时候加载。

3、搞个定时器定时刷新缓存,或者由用户触发都行。

分布式缓存系统,如Memcached、Redis,如果缓存系统比较大,由十几台甚至几十台机器组成,这样预热会复杂一些。

解决思路:

1、写个程序去跑。

2、单个缓存预热框架。

缓存预热的目标就是在系统上线前,将数据加载到缓存中。

缓存算法

FIFO算法:First in First out,先进先出。原则:一个数据最先进入缓存中,则应该最早淘汰掉。也就是说,当缓存满的时候,应当把最先进入缓存的数据给淘汰掉。

LFU算法:Least Frequently Used,最不经常使用算法。 

LRU算法:Least Recently Used,近期最少使用算法。

LRU和LFU的区别。LFU算法是根据在一段时间里数据项被使用的次数选择出最少使用的数据项,即根据使用次数的差异来决定。而LRU是根据使用时间的差异来决定的。

posted @ 2018-07-04 21:53  我只吃大碗  阅读(160)  评论(0编辑  收藏  举报