11Redis-缓存穿透、击穿与雪崩(面试高频,工作常用)分布式锁

目录

缓存穿透 (查不到)

概念

解决方案

(1)布隆过滤器

(2)缓存空对象

(3)设置可访问的名单(白名单):

(4) 进行实时监控:

缓存击穿 (查询量太大,缓存过期)

概述

解决方案

缓存雪崩

概念

解决方案

(1)redis高可用

(2)限流降级

(3)数据预热

分布式锁

问题描述

分布式锁主流的实现方案:

1.基于数据库实现分布式锁

2.基于缓存(Redis等)

3.基于Zookeeper

每一种分布式锁解决方案都有各自的优缺点:

1.性能:redis最高

2.可靠性:zookeeper最高这里

基于redis实现分布式锁

1、使用setnx上锁,通过del释放锁

2、锁一直没有释放,设置key过期时间自动释放 

3、上锁之后突然出现异常,无法设置过期时间

 问题:锁的误删

uuid防止误删

保证原子性 


缓存穿透 (查不到)

概念

缓存穿透的概念很简单,用户想要查询一个数据,发现redis内存数据库没有,也就是缓存没有命中,于是向持久层数据库查询。发现也没有,于是本次查询失败。当用户很多的时候,缓存都没有命中,于是都去请求了持久层数据库。这会给持久层数据库造成很大的压力,这时候就相当于出现了缓存穿透。

解决方案

(1)布隆过滤器

布隆过滤器是如何解决redis中的缓存穿透呢?布隆过滤器是一种数据结构,很简单首先也是对所有可能查询的参数以hash形式存储,当用户想要查询的时候,使用布隆过滤器发现不在集合中,就直接丢弃,不再对持久层查询。

(2)缓存空对象

当存储层不命中后,即使返回的空对象也将其缓存起来,同时会设置一个过期时间,之后再访问这个数据将会从缓存中获取,保护了后端数据源;

但是这种方法会存在两个问题:

        1、如果空值能够被缓存起来,这就意味着缓存需要更多的空间存储更多的键,因为这当中可能会有很多的空值的键;

        2、即使对空值设置了过期时间,还是会存在缓存层和存储层的数据会有一段时间窗口的不一致,这对于需要保持一致性的业务会有影响。

(3)设置可访问的名单(白名单):

使用bitmaps类型定义一个可以访问的名单,名单id作为bitmaps的偏移量,每次访问和bitmap里面的id进行比较,如果访问id不在bitmaps里面,进行拦截,不允许访问。

(4) 进行实时监控:

当发现Redis的命中率开始急速降低,需要排查访问对象和访问的数据,和运维人员配合,可以设置黑名单限制服务

缓存击穿 (查询量太大,缓存过期)

概述

这里需要注意和缓存击穿的区别,缓存击穿,是指一个key非常热点,在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求数据库,就像在一个屏障上凿开了一个洞。 

比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。

缓存击穿是指缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没读到数据,又同时去数据库去取数据,引起数据库压力瞬间增大,造成过大压力。

解决方案

1、设置热点数据永不过期

这样就不会出现热点数据过期的情况,但是当Redis内存空间满的时候也会清理部分数据,而且此种方案会占用空间,一旦热点数据多了起来,就会占用部分空间。

2、加互斥锁(分布式锁)

在访问key之前,采用SETNX(set if not exists)来设置另一个短期key来锁住当前key的访问,访问结束再删除该短期key。保证同时刻只有一个线程访问。这样对锁的要求就十分高。

缓存雪崩

概念

缓存雪崩是指,缓存层出现了错误,不能正常工作了。于是所有的请求都会达到存储层,存储层的调用量会暴增,造成存储层也会挂掉的情况。

解决方案

(1)redis高可用

这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群。

(2)限流降级

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

(3)数据预热

数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

分布式锁

问题描述

        随着业务发展的需要,原单体单机部署的系统被演化成分布式集群系统后,由于分布式系统多线程、多进程并且分布在不同机器上,这将使原单机部署情况下的并发控制锁策略失效,单纯的Java API并不能提供分布式锁的能力。为了解决这个问题就需要一种跨JVM互斥机制控制共享资源的访问,这就是分布式锁要解决的问题!

分布式锁主流的实现方案:

1.基于数据库实现分布式锁

2.基于缓存(Redis等)

3.基于Zookeeper

每一种分布式锁解决方案都有各自的优缺点:

1.性能:redis最高

2.可靠性:zookeeper最高这里

基于redis实现分布式锁

1、使用setnx上锁,通过del释放锁

127.0.0.1:6379> setnx k1 10
(integer) 1
127.0.0.1:6379> setnx k1 20
(integer) 0
127.0.0.1:6379> del k1
(integer) 1

2、锁一直没有释放,设置key过期时间自动释放 

127.0.0.1:6379> setnx users 20
(integer) 1
127.0.0.1:6379> expire users 20
(integer) 1
127.0.0.1:6379> ttl users
(integer) 16

3、上锁之后突然出现异常,无法设置过期时间

上锁时候同时设置过期时间就可以  (原子性操作)

127.0.0.1:6379> set k2 15 nx ex 12  # nx 设置锁  ex 设置过期时间
OK
127.0.0.1:6379> ttl k2
(integer) 10

 问题:锁的误删

uuid防止误删

保证原子性 

使用LUA脚本

LUA脚本是类似redis事务,有一定的原子性,不会被其他命令插队,可以完成一些redis事务性的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gh-xiaohe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值