【Redis】再谈redis分布式锁

女爷i 2023-07-05 11:45 114阅读 0赞

在前面的博客中我们介绍了如何使用redis的setnx做分布式锁【Redis】redis的setnx使用

什么情况下需要用分布式锁呢?

随着互联网发展,我们做的项目越来越复杂,无论是抗压还是高可用方面都需要多台机器协同工作来解决问题,单台机器早已经不能满足我们的需求,现代互联网系统都是分布式部署,它可以带来性能和效率的提升,但同时也回产生另外的问题,就是数据一致性。也即是当某个资源被多个系统共享时,为保证大家访问资源一致,必须保证在同一时刻被同一客户端访问,否则会出现有人读有人写的情况。

系统部署在多台机器上,这些资源就不再是在线程间访问,而是在进程(服务器)间,为解决数据一致性的问题,我们就必须引入分布式锁,通过锁机制实现多客户端互斥访问共享资源。

分布式锁应具有的特性:

1、互斥
2、可重入性(同一节点的同一线程获取锁后还可再次获取锁)
3、锁超时(对锁设置超时时间,防止死锁。)
4、高效,高可用
5、支持阻塞和非阻塞(支持lock和trylock)

redis为什么能做分布式锁?

redis是单进程单线程,队列模式可将并发访问转为串行,且多个客户端对redis连接不存在竞争关系,代码中的实现主要是对同一数据加锁,防止多个线程写入(互斥性)。

redis分布式锁原理:

redis分布式锁,A获得锁成功,执行一些处理后释放锁,删除锁需要执行一段lua脚本:

  1. if redis.call(“get”,KEYS[1]) == ARGV[1] then
  2. return redis.call(“del”,KEYS[1])
  3. else
  4. return 0
  5. end

B也去获得锁,如果B没得到,会每隔1s再次尝试获取。

执行lua脚本命令:
redis-cli —eval ratelimiting.lua rate.limitingl:127.0.0.1 , 10 3
–eval参数是告诉redis-cli读取并运行后面的Lua脚本
ratelimiting.lua是脚本的位置
rate.limiting:127.0.0.1是要操作的键,可以再脚本中用KEYS[1]获取
“,”后面的10和3是参数,访问频率限制为每10秒最多3次,所以在终端中不断的运行此命令会发现当访问频率在10秒内小于或等于3次时返回1,否则返回0

对比zk分布式锁?

zk分布式锁原理:
获取zk锁时,先建立一个临时节点,创建成功表示获得锁成功,执行完一些处理后释放锁;如果获取锁失败,则在锁上注册监听器,如果临时节点被删除,zk会通知重新获取锁,如果再次获取失败,重复以上操作。

两种方法实现redis分布式锁:

1、使用原子操作命令:

  1. SETEX key seconds value

不可使用先设置值后加过期时间的操作,否则如果成功获取锁后还未来得及设置过期时间就宕机,锁就得不到释放了,获取锁的业务执行完后,要删除key,执行删除前先执行lua脚本,判断当前value与传过来的value是否相同,如果不同,则不能删除,因为可能其他线程有占用该锁。

2、Redlock算法实现redis分布式锁:
假设redis为5主5从集群,使用该算法执行以下步骤获得一把锁:在这里插入图片描述
由此见,这种方法比较繁琐,我们一般不用这个方法。

redis做分布式锁应注意几个问题:

1、超时
如果锁到期自动释放,使得业务代码不能串行执行,只能手动update数据库了,很糟糕吧。有人说可以将锁过期时间延长啊,好吧,如果延长过期时间,短期内是可以缓解锁到期自动释放的问题,但是一旦调用端的业务代码down掉,线程等待锁释放的时间会延长。

2、获取锁失败
一个线程获取锁失败,其他线程是轮询还是直接业务失败呢?如果继续轮询,可能导致当前线程一直阻塞,所以建议异步。

3、可重入性
如果基于redis的分布式锁要想支持可重入性,需要客户端封装,可以使用threadlocal存储持有锁的信息。这个封装过程会增加代码的复杂度,所以不推荐这样做。

4、redis挂了
多个客户端获取锁,结果redis其中一台挂了,一个客户端获取锁了,其他客户端在新的redis服务器上获取数据了,这样锁的意义就失效了,Redlock,以牺牲性能的方法解决了这个问题。

5、时钟跳跃问题
某些时候,redis服务器时间发生跳跃,锁的时间依赖于服务器时间,所以可能出现两个客户端同时获取锁的情况。

Redis分布式锁的应用:

使用Redis分布式锁处理并发,解决超卖问题
【Redis】redis的setnx使用

发表评论

表情:
评论列表 (有 0 条评论,114人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Redis持久化

    前面 [彻底理解Redis持久化][Redis] 之后,有朋友反馈说 讲的不够彻底,还有 Redis 混合持久化没有说。主要是我自己对Redis也是从小白开始学习的过程,有些

    相关 RedisRedis分布式

    在Java中,关于锁我想大家都很熟悉。在并发编程中,我们通过锁,来避免由于竞争而造成的数据不一致问题。通常,我们以synchronized 、Lock来使用它。 但是Java

    相关 Redisredis分布式(一)

    介绍 在以前,服务基本上都是处于一个进程中,在同一进程中的不同线程要访问和操作同一个资源,可以使用编程语言提供的同步锁机制;但现在那些庞大的服务都已经被服务化和分布式化了