Redis实现分布式锁,及Golang代码展示分析 - Go语言中文社区

Redis实现分布式锁,及Golang代码展示分析


一、使用分布式锁要满足的几个条件:

  1. 系统是一个分布式系统
  2. 共享资源
  3. 同步访问

二、应用场景:

从redis取值N,对数值进行修改然后将N写回redis中,这种应用场景是很常见的,像秒杀,全场递增ID,IP访问限制等。

以IP访问限制来说,而已攻击者可能发起无限次访问,并大量比较大,分布式环境下对N的检测修改就不可靠了,因为从redis读取的N可能已经是脏数据了。

传统的加锁做法也没用,因为这是分布式环境,在这种情况下就需要分布式锁出场了。

分布式锁可以基于很多种方式实现,比如zookeeper、redis...不管哪种方式,他的基本原理都是不变的,用一个状态便是锁,对锁的占用和释放通过状态值来标识。这里我们来讨论一下redis实现分布式锁。

三、使用redis的setNX命令实现分布式锁

1、实现原理

Redis是单进程单进程模式,采用队列模式并发访问编程串行访问,且多客户端对Redis的连接并不存在竞争关系,Redis的SETNX命令可以方便的实现分布式锁。

2、基本命令解析

  • setNX(SET If Not Exists)

      

将key的值设为value,当且仅当key不存在。

若给定的key已经存在,则SETNX不做人和动作。

SETNX是[SET if Not Exists] (如果不存在,则SET)的简写

返回值:

设置成功,返回1。

设置失败,返回0。

例子:

所以我们可以使用执行下面的命令

SETNX lock.foo <current Unix time + lock timeout +1>

如果返回1,则客户端获得锁,吧lock.foo的键值设置为时间值表示该键已被锁定,该客户端最后可以通过DEL lock.foo来释放该锁。

如果返回0,则表示该锁已被其他客户端取得,这时我们可先返回或者进行重试等对方完成或等待锁超时。

  • GETSET

将给定key的值设置为value,并返回key的旧值(old value)

当key存在但不是字符串类型时候返回一个错误。

当key不存在时返回nil。

  • GET

当key不存在时,返回nil,否则返回key的值。

如果key不是字符串类型,那么返回一个错误。

四、解决死锁

上面的锁逻辑存在一个问题:如果一个尺有所的客户端失败或者崩溃了就不能释放锁了,怎么解决呢?

我们可以通过锁的键对应的时间戳来判断这种情况是否发生了,如果当前的时间已经大于lock.foo的值,说明该锁已经失效了,可以被重新使用。

发生这种情况时,可不能简单的通过DEL来删除锁,然后再SETNX一次,当多个客户端检测到锁超时后都会尝试去释放它,这里就可能出现一个竞态条件,让我们来看一下通常场景:

C0操作超时了,但它还持有着锁,C1和C2读取lock.foo检查时间戳,先后发现超时了,
C1发送DEL lock.foo
C1发送SETNX lock.foo并且成功了。
C2发送DEL lock.foo
C2发送SETNX lock.foo并且成功了。
然后问题就来了!C1,C2都拿到锁了!!

不过这种情况是可以避免的,如下:

C3发送SETNX lock.foo想要获取锁,由于C0还持有锁,所以Redis返回给C3一个0
C3发送GET lock.foo 以检查锁是否超时了,如果没有超时,则等待或重试。
反之,如果已超时,C3通过下面的操作来尝试获得锁:
GETSET lock.foo <current Unix time + lock timeout +1>
通过GETSET,C3拿到时间戳如果仍然是超时的,那就说明,C3如愿以偿的拿到了锁。
如果C3之前,有个叫C4的客户端比C3快一步执行了上面的操作,那么C3拿到的时间戳
就是一个未超时的值,这时候C3就没有拿到锁,需要再次等待或者重试。
这里需要注意的是虽然C3没有拿到锁,但是他改写了C4设置的锁的超时值,不过者一点
非常微小的误差带来的影响可以忽略不计。

注意:为了让分布式锁的算法更加稳健,持有锁的客户端再解锁之前应该再检查一次自己的锁是否已经超时,再去做DEL操作,因为可能客户端因为某个耗时的操作二挂起,操作完的时候锁因为超时已经被别人获取,这时候就不需要解锁了。

五、代码分析

          未完待续

参考文献:https://www.php.cn/redis/437668.htmlhttps://blog.csdn.net/yangxiaodong88/article/details/103560420https://books.studygolang.com/advanced-go-programming-book/ch6-cloud/ch6-02-lock.htmlhttps://learnku.com/articles/46788

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_41188944/article/details/108501619
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-05-21 20:50:34
  • 阅读 ( 1704 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢