Redis 应用01 分布式锁

分布式锁

在处理分布式应用并发的时候,常常会使用锁。

为什么使用锁

比如我们有个 num = 3, 应用对num操作

  1. 去数据库取值

  2. 取完值,在内存中,进行逻辑运算后重新赋值

  3. 存回数据库

当多个应用同时对num操作的时候

比如 a和b 都对num进行操作

取值 a1 b1

赋值 b1 b3

在数据库操作中,如果执行顺序是a1 a3 b1 b3 ,那num的值是正确的。

如果执行顺序是 a1 b1 a3 b3 ,那么num值就会异常

所以需要将 a1 b1 绑在一起执行,中间不能穿插其他操作。

如何实现锁

基本实现

setnx命令
当key 不存在时,为key设置一个字符串
设置成功,返回 1 。 设置失败,返回 0

我们将这个key当做是一个锁的标志
当redis中存在这个key,说明锁在别人手上,反之不存在key的时候,我们设置这个key,抢到锁。
然后我们执行一些逻辑操作,完成后,然后释放锁 就是删除这个key

> setnx lock_codehole true
OK

...do something

> del lock_codehole
(integer) 1

但是上面存在一些问题,就是一定要释放锁,如果因为一些原因没有 del,就会造成死锁

这个我们可以再此基础上,设计可以给lock_codehole 加上一个过期时间。

> setnx lock:codehole true
OK

> expire lock:codehole 5

... do something critical ...

> del lock:codehole
(integer) 1

但是 在setnxexpire 中间 也不能出现异常。

所以我们可以执行 set lock:codehole true ex 5 nx,合二为一。

redis2.8后,加入了这个命令,没有加之前都是使用的第三方分布式锁 library 。

所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch 线程切换。

超时问题

知道了实现锁的基本原理,并且加上了过期时间,还有问题。

就是如果我们的业务逻辑不能在过期时间内完成,那么我们删除锁的操作,其实删除的是其他程序的锁。

为了解决这个问题,我们使用分布式锁定时候,尽量不要处理耗时较长的业务

偶尔出现超时,我们需要人工干预,设置一个随机数。

释放锁时先匹配随机值是否一致,然后再删除 key

tag = str(uuid.uuid4())  # 随机值
if redis.set(key, tag, nx=True, ex=5):
    do_something()
    redis.delifequals(key, tag)  # 假想的 delifequals 指令

# 查看取出key的值 与 tag 是否相等,相等再删除

但是还有遗留问题,就是虽然锁的问题解决了,但是我们的业务逻辑已经执行,有些可能需要回滚(?),或者想办法延长锁的时间(?),还是其他办法呢。

除了以上的简单实例,还可以更复杂,比如锁可以被多个程序同时持有,但可以设置上限N。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 撸撸猫 设计师:C马雯娟 返回首页