返回顶部
首页 > 资讯 > 数据库 >Redis实现分布式锁要注意哪些事项
  • 811
分享到

Redis实现分布式锁要注意哪些事项

2024-04-02 19:04:59 811人浏览 独家记忆
摘要

本文小编为大家详细介绍“Redis实现分布式锁要注意哪些事项”,内容详细,步骤清晰,细节处理妥当,希望这篇“Redis实现分布式锁要注意哪些事项”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学

本文小编为大家详细介绍“Redis实现分布式要注意哪些事项”,内容详细,步骤清晰,细节处理妥当,希望这篇“Redis实现分布式锁要注意哪些事项”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

Redis实现分布式锁要注意哪些事项

Redis实现分布式锁

最近看分布式锁的过程中看到一篇不错的文章,特地的加工一番自己的理解:

Redis分布式锁实现的三个核心要素:

1.加锁

最简单的方法是使用setnx命令。key是锁的唯一标识,按业务来决定命名,value为当前线程的线程ID。

比如想要给一种商品的秒杀活动加锁,可以给key命名为 “lock_sale_ID” 。而value设置成什么呢?我们可以姑且设置成1。加锁的伪代码如下:

setnx(key,1)当一个线程执行setnx返回1,说明key原本不存在,该线程成功得到了锁,当其他线程执行setnx返回0,说明key已经存在,该线程抢锁失败。

2.解锁

有加锁就得有解锁。当得到锁的线程执行完任务,需要释放锁,以便其他线程可以进入。释放锁的最简单方式是执行del指令,伪代码如下:

del(key)释放锁之后,其他线程就可以继续执行setnx命令来获得锁。

3.锁超时

锁超时是什么意思呢?如果一个得到锁的线程在执行任务的过程中挂掉,来不及显式地释放锁,这块资源将会永远被锁住,别的线程再也别想进来。

所以,setnx的key必须设置一个超时时间,以保证即使没有被显式释放,这把锁也要在一定时间后自动释放。setnx不支持超时参数,所以需要额外的指令,伪代码如下:

expire(key, 30)综合起来,我们分布式锁实现的第一版伪代码如下:

if(setnx(key,1) == 1){
    expire(key,30)
    try {
        do something ......
    }catch()  {  }  finally {
       del(key)
    }

}

因为上面的伪代码中,存在着三个致命问题:

1. setnx和expire的非原子性

设想一个极端场景,当某线程执行setnx,成功得到了锁:

setnx刚执行成功,还未来得及执行expire指令,节点1 Duang的一声挂掉了。

if(setnx(key,1) == 1){  //此处挂掉了.....
    expire(key,30)
    try {
        do something ......
    }catch()
  {
  }
  finally {
       del(key)
    }
 
}

这样一来,这把锁就没有设置过期时间,变得“长生不老”,别的线程再也无法获得锁了。

怎么解决呢?setnx指令本身是不支持传入超时时间的,Redis 2.6.12以上版本为set指令增加了可选参数,伪代码如下:set(key,1,30,NX),这样就可以取代setnx指令

2. 超时后使用del 导致误删其他线程的锁

又是一个极端场景,假如某线程成功得到了锁,并且设置的超时时间是30秒。

如果某些原因导致线程A执行的很慢很慢,过了30秒都没执行完,这时候锁过期自动释放,线程B得到了锁。

随后,线程A执行完了任务,线程A接着执行del指令来释放锁。但这时候线程B还没执行完,线程A实际上删除的是线程B加的锁

怎么避免这种情况呢?可以在del释放锁之前做一个判断,验证当前的锁是不是自己加的锁。

至于具体的实现,可以在加锁的时候把当前的线程ID当做value,并在删除之前验证key对应的value是不是自己线程的ID。

加锁:
String threadId = Thread.currentThread().getId()
set(key,threadId ,30,NX)
doSomething.....
 
解锁:
if(threadId .equals(redisClient.get(key))){
    del(key)
}

但是,这样做又隐含了一个新的问题,if判断和释放锁是两个独立操作,不是原子性

我们都是追求极致的程序员,所以这一块要用lua脚本来实现:

String luaScript = 'if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end';

redisClient.eval(luaScript , Collections.singletonList(key), Collections.singletonList(threadId));

这样一来,验证和删除过程就是原子操作了。

3. 出现并发的可能性

还是刚才第二点所描述的场景,虽然我们避免了线程A误删掉key的情况,但是同一时间有A,B两个线程在访问代码块,仍然是不完美的。

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

当过去了29秒,线程A还没执行完,这时候守护线程会执行expire指令,为这把锁“续命”20秒。守护线程从第29秒开始执行,每20秒执行一次。

当线程A执行完任务,会显式关掉守护线程。

另一种情况,如果节点1 忽然断电,由于线程A和守护线程在同一个进程,守护线程也会停下。这把锁到了超时的时候,没人给它续命,也就自动释放了。

memcache实现分布式锁

首页top 10, 由数据库加载到memcache缓存n分钟
微博中名人的content cache, 一旦不存在会大量请求不能命中并加载数据库
需要执行多个io操作生成的数据存在cache中, 比如查询db多次
问题
在大并发的场合,当cache失效时,大量并发同时取不到cache,会同一瞬间去访问db并回设cache,可能会给系统带来潜在的超负荷风险。我们曾经在线上系统出现过类似故障。

解决方法

if (memcache.get(key) == null) {
// 3 min timeout to avoid mutex holder crash
if (memcache.add(key_mutex, 3 * 60 * 1000) == true) {
value = db.get(key);
memcache.set(key, value);
memcache.delete(key_mutex);
} else {
 
sleep(50);
retry();
}
}

在load db之前先add一个mutex key, mutex key add成功之后再去做加载db, 如果add失败则sleep之后重试读取原cache数据。为了防止死锁,mutex key也需要设置过期时间。伪代码如下

ZooKeeper实现分布式缓存

Zookeeper的数据存储结构就像一棵树,这棵树由节点组成,这种节点叫做Znode

Znode分为四种类型:

  • 1.持久节点 (PERSISTENT)

默认的节点类型。创建节点的客户端与zookeeper断开连接后,该节点依旧存在 。

  • 2.持久节点顺序节点(PERSISTENT_SEQUENTIAL)

所谓顺序节点,就是在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号:

Redis实现分布式锁要注意哪些事项

  • 3.临时节点(EPHEMERAL)

和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点会被删除:

Redis实现分布式锁要注意哪些事项

Redis实现分布式锁要注意哪些事项

Redis实现分布式锁要注意哪些事项

  • 4.临时顺序节点(EPHEMERAL_SEQUENTIAL)

顾名思义,临时顺序节点结合和临时节点和顺序节点的特点:在创建节点时,Zookeeper根据创建的时间顺序给该节点名称进行编号;当创建节点的客户端与zookeeper断开连接后,临时节点会被删除。

Zookeeper分布式锁恰恰应用了临时顺序节点。具体如何实现呢?让我们来看一看详细步骤:

  • 获取锁

首先,在Zookeeper当中创建一个持久节点ParentLock。当第一个客户端想要获得锁时,需要在ParentLock这个节点下面创建一个临时顺序节点 Lock1

Redis实现分布式锁要注意哪些事项

之后,Client1查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock1是不是顺序最靠前的一个。如果是第一个节点,则成功获得锁。

Redis实现分布式锁要注意哪些事项

这时候,如果再有一个客户端 Client2 前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock2

Redis实现分布式锁要注意哪些事项

Client2查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock2是不是顺序最靠前的一个,结果发现节点Lock2并不是最小的。

于是,Client2向排序仅比它靠前的节点Lock1注册Watcher,用于监听Lock1节点是否存在。这意味着Client2抢锁失败,进入了等待状态。

Redis实现分布式锁要注意哪些事项

这时候,如果又有一个客户端Client3前来获取锁,则在ParentLock下载再创建一个临时顺序节点Lock3

Redis实现分布式锁要注意哪些事项

Client3查找ParentLock下面所有的临时顺序节点并排序,判断自己所创建的节点Lock3是不是顺序最靠前的一个,结果同样发现节点Lock3并不是最小的。

于是,Client3向排序仅比它靠前的节点Lock2注册Watcher,用于监听Lock2节点是否存在。这意味着Client3同样抢锁失败,进入了等待状态。

Redis实现分布式锁要注意哪些事项

这样一来,Client1得到了锁,Client2监听了Lock1Client3监听了Lock2。这恰恰形成了一个等待队列,很像是Java当中ReentrantLock所依赖的AQS(AbstractQueuedSynchronizer)

Redis实现分布式锁要注意哪些事项

Redis实现分布式锁要注意哪些事项

  • 释放锁

释放锁分为两种情况:

1.任务完成,客户端显示释放

当任务完成时,Client1会显示调用删除节点Lock1的指令。

Redis实现分布式锁要注意哪些事项

2.任务执行过程中,客户端崩溃

获得锁的Client1在任务执行过程中,如果Duang的一声崩溃,则会断开与Zookeeper服务端的链接。根据临时节点的特性,相关联的节点Lock1会随之自动删除。

Redis实现分布式锁要注意哪些事项

由于Client2一直监听着Lock1的存在状态,当Lock1节点被删除,Client2会立刻收到通知。这时候Client2会再次查询ParentLock下面的所有节点,确认自己创建的节点Lock2是不是目前最小的节点。如果是最小,则Client2顺理成章获得了锁。

Redis实现分布式锁要注意哪些事项

同理,如果Client2也因为任务完成或者节点崩溃而删除了节点Lock2,那么Cient3就会接到通知。

Redis实现分布式锁要注意哪些事项

最终,Client3成功得到了锁。

Redis实现分布式锁要注意哪些事项

Redis实现分布式锁要注意哪些事项

Redis实现分布式锁要注意哪些事项

Zookeeper和Redis分布式锁的比较

下面的表格总结了Zookeeper和Redis分布式锁的优缺点:

Redis实现分布式锁要注意哪些事项

Redis实现分布式锁要注意哪些事项

读到这里,这篇“Redis实现分布式锁要注意哪些事项”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网数据库频道。

您可能感兴趣的文档:

--结束END--

本文标题: Redis实现分布式锁要注意哪些事项

本文链接: https://lsjlt.com/news/72415.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Redis实现分布式锁要注意哪些事项
    本文小编为大家详细介绍“Redis实现分布式锁要注意哪些事项”,内容详细,步骤清晰,细节处理妥当,希望这篇“Redis实现分布式锁要注意哪些事项”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学...
    99+
    2024-04-02
  • java加锁时要注意哪些事项
    在Java中,当我们使用锁来保护共享资源时,我们需要注意以下几个事项: 1.选择合适的锁类型:Java提供了多种锁类型,如synch...
    99+
    2023-10-24
    java
  • Ceph分布式存储集群搭建要注意哪些事项
    今天小编给大家分享一下Ceph分布式存储集群搭建要注意哪些事项的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。Ceph是可靠的...
    99+
    2023-06-27
  • 网页布局需要注意哪些事项
    这篇文章主要介绍“网页布局需要注意哪些事项”,在日常操作中,相信很多人在网页布局需要注意哪些事项问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”网页布局需要注意哪些事项”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-06-10
  • ubuntu中安装redis要注意哪些事项
    在Ubuntu中安装Redis时,需要注意以下事项: 检查Ubuntu版本:确保你的Ubuntu系统是最新的版本,并且已经更新到...
    99+
    2024-03-11
    ubuntu redis
  • docker中redis安装要注意哪些事项
    在安装Redis时,需要注意以下事项: 选择合适的Docker镜像:可以选择官方提供的Redis镜像,也可以选择其他第三方维护的...
    99+
    2024-04-09
    docker redis
  • redis导入数据要注意哪些事项
    确保数据格式正确:导入数据前,需要确认数据的格式和结构是否符合Redis支持的数据类型。例如,如果要导入的数据是字符串类型,需要...
    99+
    2024-03-11
    redis
  • Redis分布式锁的实现方式有哪些
    分布式锁是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此...
    99+
    2024-04-02
  • mysql悲观锁使用要注意哪些事项
    使用MySQL悲观锁时需要注意以下事项: 需要确保事务的隔离级别设置为Serializable,以确保事务之间的并发访问不会造成...
    99+
    2024-05-08
    mysql
  • Redis分布式锁有哪些
    Redis分布式锁有哪些?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧!我们通常使用的synchronized或者Lock都...
    99+
    2024-04-02
  • Redis——》实现分布式锁
    推荐链接:     总结——》【Java】     总结——》【Mysql】     总结——》【Redis】     总结——》【Kafka】     总结——》【Spring】     总结—...
    99+
    2023-09-03
    redis 分布式 过期 lua
  • Redis实现分布式锁
    单体锁存在的问题 在单体应用中,如果我们对共享数据不进行加锁操作,多线程操作共享数据时会出现数据一致性问题。 (下述实例是一个简单的下单问题:从redis中获取库存,检查库存是否够,>0才允许下单) 我们的解决办法通常是加锁。如下加单体锁...
    99+
    2023-08-16
    分布式 java jvm
  • Redis实现分布式锁的方法有哪些
    今天小编给大家分享一下Redis实现分布式锁的方法有哪些的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1. 单机数据一致性单...
    99+
    2023-07-02
  • Java分页查询要注意哪些事项
    在Java分页查询时,需要注意以下事项:1. 设置每页显示的数据量:在进行分页查询时,需要设置每页显示的数据量,以控制查询结果的数量...
    99+
    2023-09-15
    Java
  • mysql分割数据要注意哪些事项
    在进行MySQL数据分割时,一些需要注意的事项包括: 确定分割的准则:首先需要明确分割数据的准则,例如按时间、地域、业务等因素进...
    99+
    2024-04-09
    mysql
  • 微信小程序发布要注意哪些事项
    审核要求:确保你的小程序符合微信官方的审核要求,不违反相关规定。如果出现违规情况,可能会导致小程序被封禁或下架。 版权保护:...
    99+
    2024-04-02
  • docker中redis安装配置要注意哪些事项
    在安装和配置Redis时,需要注意以下事项: 确保使用官方提供的Redis镜像来安装Redis,避免使用不安全或不稳定的第三方镜...
    99+
    2024-04-16
    docker redis
  • redis分布式锁的实现
    一、使用分布式锁要满足的几个条件:1、系统是一个分布式系统(关键是分布式,单机的可以使用ReentrantLock或者synchronized代码块来实现)2、共享资源(各个系统访问同一个资源,资源的载体可...
    99+
    2024-04-02
  • Redis Template实现分布式锁
    今天就跟大家聊聊有关Redis Template实现分布式锁,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。可靠性首先,为了确保分布式锁可用,我们至少...
    99+
    2024-04-02
  • PHP+Redis实现分布式锁
    目录 一、分布式锁概述 二、redis实现锁的命令 1、redis实现锁的命令 3、释放锁的步骤 三、PHP+redis分布式锁示例 四、redis集群分布式锁 一、分布式锁概述         在分布式环境下,各个线程通过对公共资...
    99+
    2023-09-15
    分布式锁
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作