一.redis缓存穿透怎么解决
布隆过滤器(Bloom Filter)
布隆过滤器的核心思想是使用多个独立的哈希函数对元素进行哈希计算,并将得到的哈希值映射到一个位图中的相应位置上。当对一个元素进行查询时,通过对该元素进行相同的哈希计算,并检查对应位图上的位置是否都为1,如果都为1,则表示该元素可能存在于集合中;如果某一位为0,则表示该元素一定不存在于集合中。
优点:空间效率高,因为位图基本上只需占用一个二进制位就可以表示元素的存在与否。另外,查询时只需要进行多次哈希计算和位图的判断操作,查询速度非常快。
缺点:当通过哈希函数计算出的索引位置被多个元素共享时,会出现误判现象,即某个元素可能并未被加入集合,但多个哈希函数都返回该位置为1,导致“误认为存在”。另外,无法删除已添加的元素,因为删除一个元素会影响到其他元素的判断。
缓存空对象(Cache Null Object)
缓存空对象是当查询一个不存在的键时,可以在缓存中存储一个表示空对象的值,用于表示该键对应的数据不存在。这样,在后续的请求中,当再次查询同一个键时,可以直接从缓存中获取到空对象的值,而不需要再次访问数据库。
二.redis缓存击穿解决方法
缓存击穿也叫做热点Key问题,就是少量被高并发访问并且缓存重建业务比较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的压力。
缓存击穿的常见解决方案有两种:
-
互斥锁
-
逻辑过期
互斥锁的实现思路就是在第一个线程到来的时候获取互斥锁,后面的线程来到之后尝试去获取互斥锁,获取失败,于是进行休眠重试。直到第一个线程缓存重建成功之后,释放互斥锁。之后其余线程在重试过程中就成功查询缓存命中了重建数据。
优点:
-
没有额外的内存消耗
-
保证一致性(数据库和redis数据一致)
-
实现简单
缺点:
-
线程需要等待,性能受影响
-
可能有死锁风险(一个方法里有多个查询操作,另一个方法也有多个重合的查询操作)
逻辑过期就是给缓存的数据添加一个逻辑过期字段,而不是真正的给它设置一个TTL。每次查询缓存的时候去判断是否已经超过了我们设置的逻辑过期时间,如果未过期,直接返回缓存数据;如果已经过期则进行缓存重建。
优点:
-
线程无需等待,性能较好
缺点:
-
不保证一致性(因为会返回过期数据)
-
有额外的内存消耗(同时缓存了逻辑过期时间的字段)
-
实现复杂
三.redis缓存雪崩解决方法
缓存层承载着大量的请求,有效保护了存储层。但是如果由于缓存大量失效或者缓存整体不能提供服务,导致大量的请求到达存储层,会使存储层负载增加,这就是缓存雪崩的场景。
保持缓存层的高可用性
使用Redis 哨兵模式或者Redis 集群部署方式,即便个别Redis 节点下线,整个缓存层依然可以使用。除此之外,还可以在多个机房部署 Redis,这样即便是机房死机,依然可以实现缓存层的高可用。
限流降级组件
无论是缓存层还是存储层都会有出错的概率,可以将它们视为资源。作为并发量较大的分布式系统,假如有一个资源不可用,可能会造成所有线程在获取这个资源时异常,造成整个系统不可用。降级在高并发系统中是非常正常的,比如推荐服务中,如果个性化推荐服务不可用,可以降级补充热点数据,不至于造成整个推荐服务不可用。常见的限流降级组件如 Hystrix、SenTInel 等。
优化缓存过期时间
设计缓存时,为每一个 key 选择合适的过期时间,避免大量的 key 在同一时刻同时失效,造成缓存雪崩。