如何基于 Redis 实现分布式锁
什么是分布式锁
分布式锁:不同进程必须以互斥方式使用共享资源的一种锁方法实现。
实现分布式锁的基础
互斥。任何时刻,只有一个客户端持有锁。
无死锁。最终总是有可能获得锁,即使持有锁的客户端已经崩溃。
单个 Redis 分布式锁实现
上锁
上锁需要考虑俩点
- 原子性
- 锁能自动释放
首先要考虑持有锁的客户端挂掉后,锁一直得不到释放的情况,这时候需要借助 Redis 的 Expire 自动过期功能,在上锁时设置一个过期时间,锁到期后自动释放,就可以避免死锁的状况。
但问题来了,现在有个难题,上锁和设置过期时间是俩个步骤,如果用 Redis的 SETNX+EXPIRE 俩条指令,这不能保证上锁这一步骤是互斥的。假设现在有个线程A 已经执行完 SETNX,正在执行 EXPIRE 指令,Redis 宕机了,这锁就有概率变成死锁了。
为了避免死锁的产生,我们要将上锁步骤设置为原子性。这里有俩种方式实现:
- Lua
- SET EX NX
使用上述俩种,都能保证上锁是原子性的,死锁问题解决。
持有锁
上锁时设置了锁的过期时间。假如锁已经过期释放了,但业务还没执行完,这时候另外一客户端得到锁。此时临界区资源同时被俩进程使用,违背互斥。
为了解决这一问题,持有锁的客户端得定期去延长锁的过期时间。但如果去延期锁呢?直接 SET KEY EXPIRE 的话,其他进程也可以随意修改锁的过期时间,不安全。
所以需要一个能够一个 UUID 证明是锁的持有者。在上锁时,将锁的 value 设置为该线程的 UUID;在延期锁时,先获取锁的 value 对比该线程持有的 UUID,一致后才能延期。
释放锁
释放锁的时候也需要先证明是锁的持有者,然后再执行 delete 操作。证明+释放操作是俩步的,我们也要将其变成原子性的,一般使用 Lua 脚本执行证明+释放锁操作。
多 Redis 实例的分布式锁实现
现在我们已经完成一个对于单个始终可用的 Redis 实例的分布式锁版本。下面我们来分布式锁拓展到分布式 Redis 系统中。
我们可以将基于单实例的 Redis 分布式锁思路应用到多 Redis 环境里来。在示例中,我们有 5 个 Redis Master 实例,我们需要确保在这些 Redis 实例中锁信息是一致的。
为了获取锁,客户端执行以下操作:
- 以毫秒为单位获取当前时间。
- 尝试按顺序获取所有 N 个实例中的锁,在所有实例中使用相同的键名和随机值。在步骤 2 中,在每个实例中设置锁时,客户端以一个比锁的自动释放时间更小的超时时间来获取锁。例如,如果锁的自动释放时间为 10 秒,则获取锁的超时时间应该设置为 5 ~ 50 毫秒范围内。这可以防止客户端长时间处于阻塞状态,尝试与已关闭的 Redis 节点通信:如果实例不可用,我们应该尽快尝试与下一个实例通信。
- 客户端通过从当前时间减去在步骤 1 中获得的时间戳来计算获取锁所经过的时间。当且仅当客户端能够在大多数实例(至少 3 个)中获取锁,并且获取锁所用的总时间小于锁有效期时,锁被视为已获取。
- 如果获取了锁,则其有效时间被视为初始有效时间减去经过的时间,如步骤 3 中计算的那样。
- 如果客户端由于某种原因(无法锁定 N/2+1 个实例或有效时间为负)未能获取锁,那么将尝试解锁所有 Redis实例(甚至是客户端认为无法获取锁的实例)
项目实现
以下项目是基于上述思路实现分布锁的成功案例,我们在开发过程中可以上手即用,不必自己重复造轮子。
- Redlock-py (Python implementation).
- Redisson (Java implementation).
- Redsync (Go implementation).
- node-redlock (NodeJS implementation). Includes support for lock extension.
参考链接:
https://redis.io/docs/manual/patterns/distributed-locks/
https://juejin.cn/post/6936956908007850014
如何基于 Redis 实现分布式锁的更多相关文章
- 基于redis 实现分布式锁的方案
在电商项目中,经常有秒杀这样的活动促销,在并发访问下,很容易出现上述问题.如果在库存操作上,加锁就可以避免库存卖超的问题.分布式锁使分布式系统之间同步访问共享资源的一种方式 基于redis实现分布式锁 ...
- 基于redis的分布式锁
<?php /** * 基于redis的分布式锁 * * 参考开源代码: * http://nleach.com/post/31299575840/redis-mutex-in-php * * ...
- 基于Redis的分布式锁真的安全吗?
说明: 我前段时间写了一篇用consul实现分布式锁,感觉理解的也不是很好,直到我看到了这2篇写分布式锁的讨论,真的是很佩服作者严谨的态度, 把这种分布式锁研究的这么透彻,作者这种技术态度真的值得我好 ...
- 基于 Redis 的分布式锁
前言 分布式锁在分布式应用中应用广泛,想要搞懂一个新事物首先得了解它的由来,这样才能更加的理解甚至可以举一反三. 首先谈到分布式锁自然也就联想到分布式应用. 在我们将应用拆分为分布式应用之前的单机系统 ...
- 基于redis的分布式锁(转)
基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...
- 基于redis的分布式锁实现
1.分布式锁介绍 在计算机系统中,锁作为一种控制并发的机制无处不在. 单机环境下,操作系统能够在进程或线程之间通过本地的锁来控制并发程序的行为.而在如今的大型复杂系统中,通常采用的是分布式架构提供服务 ...
- 基于redis的分布式锁(不适合用于生产环境)
基于redis的分布式锁 1 介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分 ...
- 基于 redis 的分布式锁实现 Distributed locks with Redis debug 排查错误
小结: 1. 锁的实现方式,按照应用的实现架构,可能会有以下几种类型: 如果处理程序是单进程多线程的,在 python下,就可以使用 threading 模块的 Lock 对象来限制对共享变量的同步访 ...
- 转载:基于Redis实现分布式锁
转载:基于Redis实现分布式锁 ,出处: http://blog.csdn.net/ugg/article/details/41894947 背景在很多互联网产品应用中,有些场景需要加锁处理,比如 ...
- redis系列:基于redis的分布式锁
一.介绍 这篇博文讲介绍如何一步步构建一个基于Redis的分布式锁.会从最原始的版本开始,然后根据问题进行调整,最后完成一个较为合理的分布式锁. 本篇文章会将分布式锁的实现分为两部分,一个是单机环境, ...
随机推荐
- Kibana探索数据(Discover)详解
设置时间过滤器 时间过滤器按照指定的时间段展示搜索结果.设置了 index contains time-based events 和 time-field 的索引模式可以使用时间过滤器. 时间过滤器默 ...
- filebeat测试output连通性
在默认的情况下,直接运行filebeat的话,它选择的默认的配置文件是当前目录下的filebeat.yml文件. filebeat.yml文件内容 filebeat.inputs: - type: l ...
- 容器监控:cAdvisor
CAdvisor是Google开源的一款用于展示和分析容器运行状态的可视化工具.通过在主机上运行CAdvisor用户可以轻松的获取到当前主机上容器的运行统计信息,并以图表的形式向用户展示. 在本地运行 ...
- 分布式存储系统之Ceph集群存储池、PG 与 CRUSH
前文我们了解了ceph集群状态获取常用命令以及通过ceph daemon.ceph tell动态配置ceph组件.ceph.conf配置文件相关格式的说明等,回顾请参考https://www.cnbl ...
- 关于Redhat-7.x-下docker的安装记录
今天因公司项目,需要部署docker环境,能根据指定的镜像创建容器 于是首先就得先部署docker环境,过程记录如下: 在Redhat 7.x - (aws上的Redhat) 环境下部署过程 1.安装 ...
- HDU2196 Computer (树形DP-换根)
dp[u][0]表示u向下走的最大距离: dp[u][1]表示u向下走的次大距离: dp[u][2]表示u向上走的最大距离: 最后的答案就是每个点的max(dp[u][0],dp[u][2]); 求解 ...
- SpringBoot(三) - Slf4j+logback 日志,异步请求,定时任务
1.Slf4j+logback 日志 SpringBoot框架的默认日志实现:slf4j + logback: 默认日志级别:info,对应了实际生产环境日志级别: 1.1 日志级别 # 常见的日志框 ...
- esp32把玩记-④ 星星点灯 (点亮led)
注意 全程使用Micropython,不会安装看我第一篇文章感谢 正式开始 用Thonny烧录(运行)以下代码 import time from machine import Pin led=Pin( ...
- SpringBoot内置工具类,告别瞎写工具类了
不知大家有没有注意到,接手的项目中存在多个重复的工具类,发现其中很多功能,Spring 自带的都有.于是整理了本文,希望能够帮助到大家! 一.断言 断言是一个逻辑判断,用于检查不应该发生的情况 Ass ...
- 如何用webgl(three.js)搭建一个3D库房,3D仓库,3D码头,3D集装箱可视化孪生系统——第十五课
序 又是快两个月没写随笔了,长时间不总结项目,不锻炼文笔,一开篇,多少都会有些生疏,不知道如何开篇,如何写下去.有点江郎才尽,黔驴技穷的感觉. 写随笔,通常三步走,第一步,搭建框架,先把你要写的内容框 ...