缓存穿透

读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存。
一些恶意的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。

如何避免

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

2:对不存在的key进行过滤。可以把存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

 

缓存雪崩

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

如何避免

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

2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长期

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

 

redis热key问题 

缓存中的一个Key(比如一个促销商品),在某个时间点过期的时候,恰好在这个时间点对这个Key有大量的并发请求过来,

这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,大并发的请求可能会把数据库压垮。

解决方案:

加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;

其他进程如果发现有锁就等待,然后等解锁后返回数据或者进入DB查询

 

缓存和数据库的数据一致性

方式一:

读请求和写请求串行化,串到一个内存队列里去,这样就可以保证一致性。

串行化之后,就会导致系统的吞吐量会大幅度的降低,用比正常情况下多几倍的机器去支撑线上的一个请求。

方式二:

读的时候,先读缓存,缓存没有的话,就读数据库,然后取出数据后放入缓存。
更新的时候,先更新数据库,然后再删除缓存。

 

 

redis的过期策略以及内存淘汰机制

redis采用的是定期删除+惰性删除策略。
为什么不用定时删除策略
定时删除,用一个定时器来负责监视key,过期则自动删除。虽然内存及时释放,但是十分消耗CPU资源。

在大并发请求下,CPU要将时间应用在处理请求,而不是删除key,因此没有采用这一策略.

定期删除+惰性删除是如何工作的呢?
定期删除,redis默认每个100ms检查,是否有过期的key,有过期key则删除。需要说明的是,redis不是每个100ms将所有的key检查一次,而是随机抽取进行检查。因此,如果只采用定期删除策略,会导致很多key到时间没有删除。
惰性删除也就是说在你获取某个key的时候,redis会检查一下,这个key设置了过期时间是否过期?如果过期了就删除。

 

采用定期删除+惰性删除就没其他问题了么?
如果定期删除没删除key。然后你也没即时去请求key,也就是说惰性删除也没生效。这样,redis的内存会越来越高。

那么就应该采用内存淘汰机制。
在redis.conf中有一行配置

 

maxmemory-policy volatile-lru

该配置就是配内存淘汰策略的
volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集中任意选择数据淘汰、

allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
allkeys-random:从数据集中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据,新写入操作会报错