Redis 分布式锁

redis实现分布式锁

锁的目的是保证同一资源在同一个时间内只有一个线程访问该资源,实现ACID种的隔离性;
一般实现锁的方式有这么几种:

  • synchorinized 代码锁
  • 数据库行锁或者表锁(例如乐观锁)
  • redis分布式锁

前2种锁大部分情况下主要用在单体应用下,而redis分布式锁则主要用在分布式系统种。下面简单的列举一下redis分布式锁的实现流程:

在使用锁之前,我们得先考虑一些问题:

  • 互斥性
  • 防死锁
  • 锁的续期
  • 加所和解锁必须为同一个进程

带着这些问题,我们简单的介绍一下redis中如何解决:

  1. 加锁

要想获得锁,我们必须现获得一个锁,redis中获取一个分布式锁的伪代码:

// setnx 命令即为获取redis分布式锁,返回1,则为获取到了锁,反之为没有获取到锁
setnx(key,value)
  1. 释放锁
    获取到锁了以后,在执行同步代码以后,我们得释放锁,伪代码:
del(key)

锁无法释放的问题
那么这里有一个问题:线程A和线程B同时获取分布式锁,线程A先获取到,但是意外发生了,线程A挂掉了,这时候还没来得及进行del释放锁;那么线程B永远获取不到锁,
在这里插入图片描述
那么这里我们就要给线程A获取到的锁添加一个过期时间。伪代码:

//获取锁
> setnx(key,value)

//设置过期时间 :30s
> expire(key,30)

....执行同步代码块.....

> del(key)

也就是解决了上面一个问题,但是也引发了另外一个问题:由于setnx(key,value) 和expire(key,expiretime) 这是两个命令,无法保证原子性;这样一来,上叙问题又重现了,没有在根本上解决问题,而setnx又不支持同时设定过期时间,那么有没有一条命令就把两件事干完呢?答案:有 如下伪代码:

// set(key,value,expireTime,NX)
> set("mylock","11121233343dfasdfe12312",30,NX)

锁提前释放的问题

我们在set(key,value,expireTime,NX)时设置了过期时间,但是30s我们的代码还没处理完业务,这个lock就过期了,这个锁就释放了,而这个时候线程B又获取到了锁,当线程A处理完业务后,执行del,其实这个时候del的是线程B的锁,

这时候我们不妨在执行del时,先判断一下是否时线程A的锁。那么我们在set key时,可以把当前节点的ID或者线程ID 一同设置到key中,这样判断起来就有根据;
在这里插入图片描述
线程A线程B并发的问题

虽然我们通过 set value时 添加线程ID或者节点ID可以避免误删锁,但是这里又有一个问题,就是在同一时间内,线程A和线程B都访问了同一资源,这显然不符合隔离性;

我们可以通过给线程A添加一个守护线程,隔一段时间就去查一下线程A是否还持有锁,业务有没有处理完,没有,守护线程就给线程A的锁续命20s,线程A业务处理完以后,同步销毁守护线程。

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值