Redis之(三) 分布式锁

   Redis分布式锁

       分布式应用进行逻辑处理时经常会遇到并发问题。对于单进程的并发场景,我们可以使用语言或者类库提供的锁,而对于分布式场景,我们可以使用分布式锁。

       分布式锁的实现方法也有很多,Memcached分布式锁、Zookeeper分布式锁等等,当然,Redis分布式锁也是很有代表性的分布式锁的实现方式。

       例子:

       某个操作需要修改用户的状态,首先需要读取出用户的状态,在内存中进行修改后再把它存回去。这样的操作如果同时进行了,就会出现并发问题,因为读取和保存状态这两个操作不是原子的。

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

       

       这个时候就要使用到分布式锁来限制程序的并发执行,Redis分布式锁使用非常广泛。

 


 如何使用

 

       分布式锁本质上要实现的目标就是在Redis里面占一个座位,当别的进程也要来坐这个位置时,发现座位已经被占了,就只能等待或稍后再查看。

       占座位(也就是加锁)一般用  setnx(set if not exists)指令,并且只允许被一个客户端占领,先来先占领,用完了,再使用del指令释放。

// 这里的冒号:就是一个普通的字符,没特别含义,它可以是任意其它字符,不要误解
> setnx lock:codehole true
OK
... do something critical ...
> del lock:codehole
(integer) 1...

       但是如果我们加锁后,一个得到锁的进程在执行过程中挂掉或者是我们忘记了释放锁,那么这块资源会被永久地锁住,造成死锁,锁永远得不到释放。

       于是我们在拿到锁之后,可以给锁 expire命令 再增加一个过期时间,比如说5s,那么及时中途出现异常亦可以保证5s后锁会自动释放。 

> setnx lock:codehole true
OK
> expire lock:codehole 5
... do something critical ...
> del lock:codehole
(integer) 1

       但是这样也还是有可能出现问题的。原因就在于setnx 和 expire 这两条指令是  非原子性  的指令。

       我们可以设想以下的场景:

       

 

 

       节点1中线程A执行了 setnx 指令,获得了锁但是还没有执行 expire 指令,这个时候突然节点1的机器宕机了。

 

 

       这样一来,这把锁就没有了过期时间,变得永不过期,依旧会出现死锁。

       为了解决这个问题,Redis在2.6.12以上的版本中增加了  set指令以及其可选参数 ,取代了setnx指令,使得setnx和expire指令可以一起执行。

    

> set lock:codehole true ex 5 nx
OK
... do something critical ...
> del lock:codehole

    


   超时问题

       Redis的分布式锁不能解决超时问题,如果在加锁和释放锁之间的逻辑执行的太长,超出了锁的超时限制,就会出现问题。

 

 

       因为这个时候锁过期了,第二个线程重新持有了这把锁,但是紧接着第一个线程执行完之后,会将这个锁给释放掉。

 

 

       这会导致一个后果:第三个线程会在第二个线程的执行过程之间拿到锁。

 

       为了避免这个问题,Redis 分布式锁不要用于较长时间的任务。如果真的偶尔出现了,数据出现的小波错乱可能需要人工介入解决。

 


    解决超时自动释放的一种方式。

       我们可以让获得锁的线程开启一个守护线程,用来给快要过期的锁续航。

 

       过去了29s,线程A还没有执行完毕,这个时候守护线程会执行 expire 指令。为这把锁续命20s,守护线程在29s后,每20s执行一次。

 

       

       线程A执行完之后,则关闭守护线程。

 

 

       

 

转载于:https://www.cnblogs.com/WeirdRomance/p/9556102.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值