缓存穿透
缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询,发现也没有,于是本次查询失败。当用户有很多的时候,缓存都没有命中。
于是去请求了持久层数据库,这就会给数据库造成很大的压力,这就是相当于出现了缓存穿透。
解决办法
1.布隆过滤器。是一种数据结构,对于所有可能查询的参数以hash形式存储,在控制层进行校验,不符合直接丢弃。从而避免对数据库的压力。
2.假设缓存没有命中,设置空值缓存。但是会增加redis内存。即使设置空值过期时间,会造成缓存层和数据层有一段时间的窗口不一致,对于保持一致性的业务会有影响。
缓存击穿
指一个热点数据key,在某一瞬间这个热点key突然失效了,这时候大量的并发就会穿破缓存,直接请求数据库,就像在一个屏障上开了洞。
解决办法
1.设置热点数据永不过期,所以不会出现热点key过期后产生的问题
2.加互斥锁。保证每个key同时只有一个线程去查询后端服务,其他线程没有获得锁,只能等待。
缓存雪崩
某个时间段大量的key失效,或者直接redis宕机。比如双11,一波商品缓存的时间集中在一个时间段。假设缓存一个小时,那么凌晨一点钟的时候,这些商品的缓存都过期了。对这批商品的查询都落到数据库上了。
对于数据库而言,产生周期性的波峰压力。导致可能出现连数据库都会崩溃的场面发生。
解决办法
1.所以要保证所以要保证服务的高可用。停掉一些服务,保证一些服务的可用。或者增加一些机器,一台挂掉,其他还可以正常运行。
2.限流降级:在缓存失效后,通过加锁或者队列来控制读数据库的写缓存的线程数量,对于某个key只允许一个线程查询数据和写缓存。其他线程等待。
3.数据预热 正式部署前,我们把可能的数据预先访问一遍。这样大部分的访问数据就会加载到缓存中,在即将发生大并发访问前手动触发加载缓存不同的key,设置不同过期时间,让缓存失效的时间尽量均匀。
重要的是要理解下面这个思想
redis分布式环境下,保证服务的高可用?
为什么在分布式的环境下,redis不能保证高可用?不论在主从,哨兵还是cluster模式下都无法保证redis的高可用性呢
为什么呢?
因为可能会出现redis集群中master节点宕机后,master节点的数据如果还没有来得及同步到slave机器上。
假设这时候如果采用哨兵模式,选举出一个新的master,但是这个新的master产生后,假设之前旧的master修复开机后,它会从新的master同步数据,这时候的老的master节点的数据就会消失。
分布式环境下,如果新客户端请求上锁,请求来到新的master节点,setnx就会上锁成功,因为old的key已经不存在了(或者说没来得及同步到这台新的master上),这就会导致多个客户端拥有同一把分布式锁,不满足分布式锁的互斥性。
有一种办法可以借鉴参考下:当然这只是想法,毕竟如果你去面试如果有人问你
redis集群中master节点宕机的那一刻,某一台slave升级为主机后,假如之前挂掉的主机的部分数据还没来的及同步到slave机器上,这就尴尬了?怎么解决这个问题?
1.延迟启动。假设在设置ttl超时10s钟内主机宕机了,那么可以让新的主机在10s钟以后,待key失效后再上线。
如何尽量保证集群期间宕机,减少数据的丢失?
首先看下面2个参数:
min-replicas-to-write 3:至少需要3台健康的从机,主机节点才有机会写入命令。
min-replicas-max-lag 10: 延迟小于min-replicas-max-lag配置秒的slave才认为是健康的slave,假设配置10s 那么ping的时间需要小于10
1.这样如果开启以上两个配置,这样在master节点挂掉之后,可能也不会在处理客户端写的请求了。因为可能此时的从机数量小于配置的数量,或者机器之间的通信延时达不到配置的级别。
2.如果redis产生新的master节点并且拒绝了写的请求,但是客户端仍然在做一些大量写的操作。这时候可以将这些写的数据暂时存在消息队列里面,待集群恢复后,在将数据写入redis.