【Redis】应用问题解决

一、缓存击穿

1、什么叫缓存击穿
系统中某个查询次数很多的热点key,在某个时刻过期,而此时又正好有大量并发请求查询这个key,但是缓存的重建还没有完成,这样,就会有大量请求涌向后端数据库,使得其压力骤增甚至崩溃

2、如何解决缓存击穿

  • 使用分布式互斥锁:只允许一个线程获取到锁,由它去查询数据库,然后将查询到的数据设置到缓存中,其他线程必须等待重建缓存的线程执行完,然后去缓存中获取数据
  • 设置永不过期
    • 在设置热点key的时候,不给key设置过期时间
    • 或者正常给key设置过期时间,不过在后台同时启一个定时任务去定时地更新这个缓存

二、缓存穿透

1、什么叫缓存穿透
缓存穿透的意思就是,应用查询一个不存在的数据,在缓存中查不到,去数据库查也查不到,这样就无法写入缓存。如果出现大量此类请求,每次查询都访问数据库,就会导致后端数据库压力骤增,缓存失去了对数据库的保护作用

2、为什么会发生缓存穿透

  • 自身的业务代码出了问题,如set和get的key不一致,导致查不到数据
  • 遭到恶意的网络攻击

3、如何解决缓存穿透

  • 缓存空对象:将数据库返回的null缓存起来,设置一个较短的过期时间
  • 使用布隆过滤器,可以结合博主之前写的bitmap理解
    • 简单来说就是在初始化布隆过滤器时,会先将所有key进行n次hash运算,这样就可以得到n个位置,然后将这n个位置上的元素改为1
    • 然后请求过来后,我们对要查询的key做hash运算得到某个位置,然后看布隆过滤器中对应位置元素的值是否为1
      • 如果对应位置元素的值为1,就证明key在库中存在,则继续向下查询
      • 如果对应位置元素的值不为1,那么就证明key在库中不存在,直接返回客户端空即可
  • 使用黑白名单:如果是恶意攻击,我们可以通过只允许某些IP访问我们的服务或者禁止某些IP访问我们的服务

三、缓存雪崩

1、什么叫缓存雪崩
缓存中有大量的key在同一时刻过期,或者Redis直接宕机了,导致大量的查询请求全部到达数据库,造成数据库查询压力骤增,甚至直接挂掉

2、如何解决缓存雪崩

  • 将每个key的过期时间打散,使它们的失效点尽可能均匀分布
  • 针对一些常用的数据设置成为永久有效
  • 使用高可用集群,防止redis宕机造成缓存不可用

四、分布式锁

1、什么是分布式锁
所有服务中的所有线程都去获取同一把锁,但只有一个线程可以成功的获得锁,其他没有获得锁的线程必须全部等待,直到持有锁的线程释放锁。在集群场景下,使用分布式锁,有助于保证数据的一致性

2、实现分布式锁的方案

  • 基于数据库实现
  • 基于缓存(Redis等,基于redis实现性能最高)
  • 基于zookeeper(可靠性最高)

3、使用setnx设置分布式锁

  • 使用setnx key value去设置数据,使用del key去删除数据
    这个命令的意思就是,如果key存在,就无法更改value
    所以不管是集群中哪个节点想修改这个key,在使用del之前都无法成功
  • 然后为了防止设置key之后,节点宕机无法执行del key操作导致这个key一直被锁定,我们还需要设置过期时间,所以我们执行完setnx key value之后使用expire key <time>命令给这个key设置过期时间
  • 还有一点需要考虑的是,如果在执行expire key <time>命令之前,节点宕机,那么这个key还是会被锁定,所以我们要考虑原子性操作,使用set key value nx ex <expireTime>命令来完成设置key和过期时间的操作(注意,此指令只能限制setnx命令,限制不了set命令)
127.0.0.1:6379> set k1 10 nx ex 60
OK
127.0.0.1:6379>
127.0.0.1:6379> setnx k1 20
(integer) 0
127.0.0.1:6379> ttl k1
(integer) 47
127.0.0.1:6379>
127.0.0.1:6379> set k1 20
OK
127.0.0.1:6379> get k1
"20"
127.0.0.1:6379>

4、通过uuid解决锁误删的情况

在多线程情况下,我们还可能会遇到锁被误删的问题
在这里插入图片描述
为了解决这种误删问题,我们在执行set key value nx ex <expireTime>命令时,value可以带上uuid作为区分其他线程的依据,业务代码在执行释放锁操作之前,先去判断获取到的value是否符合或包含自己的那个uuid,这样就避免了因为卡顿会误删别人的锁的情况

5、使用LUA保证删除操作原子性
在这里插入图片描述

由上图可知,在某些极端场景下,还是会出现误删他人锁的情况
所以我们的解决方法就是,将第三步中的判断和释放操作写在一段LUA脚本中,然后excute执行,以此来实现释放操作的原子性

五、redis6.0后的新特性

  • redis6.0之后新增了ACL,有兴趣可以自行百度
  • redis-cli支持cluster(5.0及以前想搭建集群还要安装ruby环境)
  • 另外支持网络数据读写以及协议解析的多线程(命令执行还是单线程)

如有错误,欢迎指正!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值