使用Redis缓存存在的问题

使用Redis缓存存在的问题

使用redis缓存的初衷:缓解数据库压力,提高性能。

1、缓存穿透

缓存穿透是指客户端请求的数据在缓存中和数据库中都不存在,这样缓存永远不会生效,这些请求都会打到数据库。

在这里插入图片描述

2、缓存雪崩

缓存雪崩是指在同一时段大量的缓存key同时失效或者Redis服务宕机,导致大量请求到达数据库,带来巨大压力。

在这里插入图片描述

3、缓存击穿

缓存击穿问题也叫热点Key问题,就是一个被高并发访问并且缓存重建业务较复杂的key突然失效了,无数的请求访问会在瞬间给数据库带来巨大的冲击。

在这里插入图片描述

案例:

优惠券秒杀问题

在这里插入图片描述

超卖问题:多线程存在安全问题

如下图所示

在这里插入图片描述

当线程1查询完库存大于0 还未扣减库存的时候,线程2也查询库存大于0 然后一起扣减 就会出现库存为负数的情况。

超卖问题是典型的多线程安全问题,针对这一问题的常见解决方案就是加锁
在这里插入图片描述

  • 悲观锁:添加同步锁,让线程串行执行
    优点:简单粗暴
    缺点:性能一般

  • 乐观锁:不加锁,在更新时判断是否有其它线程在修改
    优点:性能好
    缺点:存在成功率低的问题

一人一单问题

需求:修改秒杀业务,要求同一个优惠券,一个用户只能下一单

流程图变更如下
在这里插入图片描述

可通过加锁解决(单机情况):

同一个用户一把锁 ,注意:userId.toString() 每次都会new出来,需要使用userId.toString().intern(),才能锁住。

在大多数情况下 都是集群部署 通过负载均衡

通过加锁可以解决在单机情况下的一人一单安全问题,但是在集群模式下就不行了

在这里插入图片描述

每个服务都会有单独的JVM,JVM中的锁监视器只能锁本JVM。导致两个服务没有被同一把锁锁住。

解决方法

分布式锁(经典加一层)
在这里插入图片描述

分布式锁的核心是实现多进程之间互斥,而满足这一点的方式有很多,常见的有三种:

在这里插入图片描述

这里将使用Redis进行分布式锁

Redis中SetNX命令 SETNX key value

将 key 的值设为 value ,当且仅当 key 不存在。
若给定的 key 已经存在,则 SETNX 不做任何动作。

故可以利用它来实现锁的效果

误删锁问题

在这里插入图片描述

当线程1获取到锁之后,业务阻塞,造成锁的超时释放,此时线程2进来便可以拿到锁,然后线程1继续执行,就可以把线程2的锁删除掉。

原来业务流程:
在这里插入图片描述

解决方法:在删除锁之前先看看锁是不是自己的。
在这里插入图片描述

改进Redis的分布式锁

在这里插入图片描述

但是上面误删问题仍可能在极端情况下发生;

例如:让线程1验证完是自己的锁的时候,被阻塞(垃圾回收机制),此时超时释放锁,然后线程2便进入了锁,线程1唤醒后,执行删除锁的业务,便也造成误删问题。

在这里插入图片描述

解决方法:只需要保证 验证锁是否是自己的和删除锁是一个原子性的操作即可。

这里我们将使用Lua脚本。

Redis提供了Lua脚本功能,在一个脚本中编写多条Redis命令,确保多条命令执行时的原子性。Lua是一种编程语言,它的基本语法大家可以参考网站:https://www.runoob.com/lua/lua-tutorial.html

一人一单问题总结

  • 基于Redis的分布式锁实现思路:
    利用set nx ex获取锁,并设置过期时间,保存线程标示
    释放锁时先判断线程标示是否与自己一致,一致则删除锁

  • 特性:
    利用set nx满足互斥性
    利用set ex保证故障时锁依然能释放,避免死锁,提高安全性
    利用Redis集群保证高可用和高并发特性

基于setnx实现的分布式锁存在下面的问题:

在这里插入图片描述

Redisson

Redisson是一个在Redis的基础上实现的Java驻内存数据网格(In-Memory Data Grid)。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务,其中就包含了各种分布式锁的实现。

  • 不可重入Redis分布式锁:
    原理:利用setnx的互斥性;利用ex避免死锁;释放锁时判断线程标示
    缺陷:不可重入、无法重试、锁超时失效
  • 可重入的Redis分布式锁:
    原理:利用hash结构,记录线程标示和重入次数;利用watchDog延续锁时间;利用信号量控制锁重试等待
    缺陷:redis宕机引起锁失效问题
  • Redisson的multiLock:
    原理:多个独立的Redis节点,必须在所有节点都获取重入锁,才算获取锁成功
    缺陷:运维成本高、实现复杂
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值