在之前的redis的的文章中,我们说过redis的主从复制,现在我们来说一说redis经常发生的集中问题
1,缓存穿透,是指一个缓存中没有的数据同时数据库中也没有,这样就会导致缓存没有命中,因为数据库中也没有这项数据,所以在请求之后也不会在写入缓存中,这样就会导致直接访问数据源,导致压垮数据源
2,缓存击穿,是指key对应的数据是存在的,但是在缓存中过期了。这时有高并发的大量数据请求过来,就会因为缓存中没有而导致直接去访问数据源,访问之后还需要将数据回写到数据源中,这是会容易把数据源压垮
3,缓存雪崩,这是在缓存服务器重启或者一个时间段内缓存失效,这会导致所有的缓存失效,从而压垮数据源
解决方式
对于缓存穿透,我了解的大概有两种方式
第一种是采用一个足够大的bitmap(采用bitmap,是因为可以更多的节省空间)将所有可能的key都放在里面,这样不存在的请求打过来就会被这个过滤掉
第二种是采用一个空值的存储,一个不存在的请求打过来之后,缓存中没有,就会去数据源中去查,此时因为数据源中没有所以我们不会去回写缓存,但是为了避免缓存穿透,我们可以也把这个空值存下来,只不过过期时间设置的短一点。
缓存击穿现在常用的是加锁的方式,但是小编在网上也看了几个不同的文章,里面也对这加锁的提出了不同程度的质疑,现在就给大家说一说我自己的看法。首先什么是缓存击穿,就是指一些热点的数据过期后出现了高并发请求,然后全部压到了数据库中,这样就会导致了缓存击穿。对于这个他们也提出了一种缓存永不过期的方法,即对于这些热点数据在快要过期的时候给他重新设置过期时间,这样这些热点的数据就不会出现缓存过期的问题,可是这样又存在一个问题,如果热点数据是一些经常性存在的数据他的热度一直都很高,这样可以区分出热点数据,可是一旦热点数据像一些热搜之类的,比如哪个明星出轨和结婚了,这样突然出现的数据直接就变成热点的数据,这样没办法去区分这些数据是不是热点的,所以这个热点数据永不过期的方法具有时效性。
所以永不过期也有一定的局限,那既然在面对一些突然出现的热点的数据,我们怎么处理,看过一些文章里面说采用加锁的方式,但一个请求获得锁的时候,在进行操作,如果没有获得就等待。只之前小编在网上看过一个采用redis里面的mutex key互斥锁的方式来进行加锁,就是在缓存中返回空的时候,不是去立马的加载数据,而是使用一些带成功返回值的方法如redis的setnx方法去设置一个mutex key,设置成功之后就去加载数据源,设置失败之后就等一下在重新获取数据(明天给大家补一下这个代码),这个方法也是业界比较常用的方法。还有一种用synchronized加锁的方式,只不过在服务中使用这个会有一定的风险,因为在使用这个锁的时候,假如一个进程获得了锁,那么其他的进程全部都是阻塞状态,如果没释放甚至其他进程都不会去尝试获取锁,这样容易导致其他进程进入阻塞状态,很容易影响服务。
同样加锁也会出现问题
假如在加锁的途中如果请求没有执行完,此时这个进程死掉了,同时锁也没有释放,这时就会出现一个问题,锁没释放,但是其他请求还在等待锁, 这样其他请求也拿不到数据,导致服务一直处于这个状态,这样服务也会出现问题。