当前位置: 首页 > news >正文

什么是分布式锁?Redis实现分布式锁详解

目录

前言:

分布式系统买票示例

引入redis做分布式锁

引入过期时间

引入校验id

引入lua脚本

过期时间续约问题

redlock算法

小结:


前言:

    在分布式系统中,涉及多个主机访问同一块资源,此时就需要锁来做互斥控制,避免出现类似线程安全问题。而Java中的synchronized只是对当前进程中的线程有效,多个主机实际上是多个进程,那么它就无能为力了,此时就需要分布式锁。

分布式系统买票示例

    客户端访问买票服务器进行买票操作,当买到票之后数据库余票执行减1操作。

    客户端1先执行查询余票操作,发现余票还有一张,买票成功后服务器操作数据库执行减1操作。如果此时客户端1还没有执行数据库减1操作,客户端2执行了查询余票操作,发现余票也是一张,那么也进行数据库减1操作,那么此时客户端1和客户端2都会买到票。把一张票卖给了两个人,显然这是不合理的。

引入redis做分布式锁

    引入分布式锁,所谓分布式锁实际上就是一个/一组单独的服务器程序,给其他服务提供 “加锁” 服务。redis是一种典型的实现分布式锁的方案,但不是唯一一种。

    为了解决上述超卖问题,买票服务器在进行买票的时候,就需要先加锁。

    加锁实际上就是在redis上设置一个特殊的键值对,完成上述买票操作再删除这个键值对。(此时认为这个键值对就是分布式锁)

    其他服务器在买票的时候,也去redis尝试设置这样的键值对,如果发现键值对已经存在,就认为“加锁失败”,此时该进程是放弃还是阻塞就看具体的实现策略了。

    这样就可以保证第一个服务器执行查询-更新的过程中,第二个服务器不会执行查询操作,也就解决了上述超卖问题。

注意:

    上述买票的场景也可以使用MySQL的事务解决,批量执行查询-更新操作。但是分布式系统中数据库不一定是MySQL,也可能是其他数据库没有事务,因此使用redis作为分布式锁是比较好的解决方案。

引入过期时间

    redis中使用 set nx 命令可以实现加锁效果,解锁使用 del 命令来完成。

    如果某个服务器 set nx 成功了,还没有执行 del 命令就挂了,此时redis上的锁就无法删除,其他服务器就无法获取到锁。

解决方案:

    可以在set key 的时候设置过期时间,一旦时间到锁自动就释放了。redis中可以使用 set ex nx命令完成。此时这个过期时间范围设置就显得尤为重要了,后面会有解释(过期时间续约问题)。

注意:

    务必使用 set ex nx 命令一次性执行加锁和设置过期时间操作。如果使用set nx 设置锁,然后使用 expire 设置过期时间,就可能出现这两个命令一个成功一个失败,就算使用redis事务只能保证两条命令一块执行,但不能保证其正确性。相比之下一条命令直接操作就比较稳妥。

引入校验id

    是否会出现服务器1执行了加锁操作,被其他服务器删除的情况呢?

    这种情况有可能出现,代码总会有bug,需要提前去防止。

解决方案:

    给服务器编号,每个服务器都有自己的唯一标识。进行加锁的时候,设置键值对.key对应要对哪个资源加锁(比如车次),value就可以存储服务器编号,标识出这个锁是哪个服务器加的。

    解锁的时候就可以进行校验,先查询这个锁的服务器编号,和自己服务器编号进行对比。如果一致则执行解锁操作,否则就失败。服务器这边需要执行校验逻辑,此时就可以有效避免误解锁。

引入lua脚本

    一个服务器内部也可能是多线程的,就有可能存在两个线程执行上述判断然后解锁操作。由于不是原子的,就有可能出现问题。

    服务器1的线程A和线程B都执行解锁操作,如果线程A拿到锁判断完后,还没有执行DEL操作,此时线程B也拿到锁判断也会成功,那么就会执行两次DEL操作。

    如果在线程A执行DEL之后,线程B执行DEL之前,服务器2的线程C在redis中进行加锁操作(此时由于线程A已经执行了DEL操作,因此可以加锁成功)。由于线程B已经校验完成,那么执行DEL就会删除掉服务器2加的锁。该问题就是因为GET和DEL操作不是原子的,就会出现问题。

    解决上述问题,可以使用redis事务,保证GET和DEL的原子性,在执行期间不会有插队情况出现。但是一般不会这样做,引入lua脚本是更加有效的解决方案。

    lua是一门编程语言,作为redis内嵌脚本,lua语言特别轻量,实现一个lua的解释器消耗系统资源非常小。

    可以使用lua编写一些逻辑,把这个脚本上传到服务器上,然后客户端就可以控制redis执行这些脚本了。redis执行lua脚本的时候,是原子的,相当于执行一条命令一样。(redis官方文档中提出lua属于是redis事务的替代方案)。

过期时间续约问题

    在加锁的时候key需要设置过期时间,那么这个时间设置多少合适呢?

    如果设置短,那么有可能在业务逻辑还没执行完,锁就被释放了。

    如果设置长,那么锁释放就会不及时。

动态续约:

    初始情况下设置一个时间比较短的过期时间(灵活进行调整),如果发现时间快到的时候,业务逻辑还没执行完,那就在续上一些过期时间(无限续约)。直到业务逻辑执行完成,锁也可以在较短时间内被释放。

    如果服务器中途挂了,那也没有负责续约的线程了,此时锁也可以在较短时间内被释放。

    动态续约往往需要服务器这边一个专门的线程负责,把这个线程就叫做看门狗(watch dog)。

redlock算法

    使用redis作为分布式锁,那么就需要保证redis的高可用。

    使用redis哨兵机制,当主节点挂了可以投票选举从节点作为主节点。但是如果在主节点加锁后还没来得及同步给从节点,主节点就宕机了。此时哨兵选举的从节点也就不存在该锁了。

    作为分布式系统,就需要随时考虑某个节点挂了,不会影响大局。

    redlock算法核心思想就是:冗余

    此处加锁会按照一定顺序,对这些redis主节点都进行加锁。如果某个节点宕机了,没关系继续给下一个redis主节点加锁。如果加锁成功节点个数超过总个数一半,就视为加锁成功。同理,解锁需要把上述节点都执行解锁操作。这里就不会因为某个节点挂了,而导致加不上锁的情况。

小结:

    这里实际上实现了互斥锁,还可以使用redis做读写锁,可重入锁,公平锁等等。 

相关文章:

什么是分布式锁?Redis实现分布式锁详解

目录 前言: 分布式系统买票示例 引入redis做分布式锁 引入过期时间 引入校验id 引入lua脚本 过期时间续约问题 redlock算法 小结: 前言: 在分布式系统中,涉及多个主机访问同一块资源,此时就需要锁来做互斥控制…...

ubuntu挂载硬盘方法

1.关闭服务器加上新硬盘 2.启动服务器,以root用户登录 3.查看硬盘信息 fdisk -l4.格式化分区 找到需要分区的目录,并记录分区的uuid,用于后面修改/etc/fstab永久挂载配置文件 mkfs.ext4 /dev/nvme0n1 mkfs.ext4 /dev/nvme1n1 Filesystem UUID: a1c…...

【go入门】表单

4.1 处理表单的输入 先来看一个表单递交的例子&#xff0c;我们有如下的表单内容&#xff0c;命名成文件login.gtpl(放入当前新建项目的目录里面) <html> <head> <title></title> </head> <body> <form action"/login" meth…...

②⑩① 【MySQL】什么是分库分表?拆分策略有什么?什么是MyCat?

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ 目录 ②⑩① 【MySQL】什么是分库分表&#xf…...

点击url如何唤起nativescript应用程序?

1、低于ios 9.0的版本 可以使用 nativescript-urlhandler&#xff0c;通过在app.component.ts中添加handleOpenURL来实现。 2、高于ios 9.0的版本 可以使用 nativescript-community/universal-links来实现 https://github.com/nativescript-community/universal-links 安装&a…...

【华为网络-配置-021】- MSTP 多实例配置及安全保护等

要求&#xff1a; 1、vlan 10 从红色链路转发。 2、vlan 20 从黄色链路转发。 一、基础配置 [SW1]vlan batch 10 20 [SW1]interface GigabitEthernet 0/0/1 [SW1-GigabitEthernet0/0/1]port link-type trunk [SW1-GigabitEthernet0/0/1]port trunk allow-pass vlan all [SW…...

信息收集小练习

信息收集小练习 本文章无任何恶意攻击行为&#xff0c;演示内容都合规无攻击性 演示如何绕过cdn获取真实ip 使用多地ping该网站 发现有很多ip地址&#xff0c;证明有cdn 此处使用搜索引擎搜索&#xff0c;得到ip 演示nmap工具的常用参数 此处以testfire.net为例 使用多地p…...

清华提出 SoRA,参数量只有 LoRA 的 70%,表现更好!

现在有很多关于大型语言模型&#xff08;LLM&#xff09;的研究&#xff0c;都围绕着如何高效微调展开。微调是利用模型在大规模通用数据上学到的知识&#xff0c;通过有针对性的小规模下游任务数据&#xff0c;使模型更好地适应具体任务的训练方法。 在先前的工作中&#xff…...

FO-like Transformation

参考文献&#xff1a; [RS91] Rackoff C, Simon D R. Non-interactive zero-knowledge proof of knowledge and chosen ciphertext attack[C]//Annual international cryptology conference. Berlin, Heidelberg: Springer Berlin Heidelberg, 1991: 433-444.[BR93] Bellare M…...

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(三)

通过ros系统中websocket中发送sensor_msgs::Image数据给web端显示(三) 不使用base64编码方式传递 #include <ros/ros.h> #include <signal.h> #include <sensor_msgs/Image.h> #include <message_filters/subscriber.h> #include <message_filter…...

Navicat 技术指引 | 适用于 GaussDB 的模型功能

Navicat Premium&#xff08;16.2.8 Windows版或以上&#xff09; 已支持对 GaussDB 主备版的管理和开发功能。它不仅具备轻松、便捷的可视化数据查看和编辑功能&#xff0c;还提供强大的高阶功能&#xff08;如模型、结构同步、协同合作、数据迁移等&#xff09;&#xff0c;这…...

Ubuntu18.4中安装wkhtmltopdf + Odoo16配置【二】

deepin Linux 安装wkhtmltopdf 1、先从官网的链接里下载linux对应的包 wkhtmltopdf/wkhtmltopdf 下载需要的版本&#xff0c;推荐版本&#xff0c;新测有效&#xff1a; wkhtmltox-0.12.4_linux-generic-amd64.tar.xz 2、解压下载的文件 解压后会有一个wkhtmltox文件夹 3…...

RC-MVSNet:无监督的多视角立体视觉与神经渲染--论文笔记(2022年)

RC-MVSNet&#xff1a;无监督的多视角立体视觉与神经渲染--论文笔记&#xff08;2022年&#xff09; 摘要1 引言2 相关工作2.1 基于监督的MVS2.2 无监督和自监督MVS2.3 多视图神经渲染 3 实现方法3.1 无监督的MVS网络 Chang, D. et al. (2022). RC-MVSNet: Unsupervised Multi-…...

gradle构建项目速度优化及排查方式

文章目录 一、前言二、Android项目优化1、相关配置2、构建速度分析 三、Gradle项目通用优化1、分析构建耗时2、使用配置进行优化3、优化依赖解析a. 避免不必要和未使用的依赖项b. 优化存储库顺序 c. 最小化动态和快照版本d. 通过构建扫描查找动态和变化的版本e. 通过构建扫描可…...

MSI Center,XBox从任务栏取消固定

1&#xff0c;设置查看方式中隐藏项目可见 2&#xff0c;进入文件夹&#xff1a;C:\Users\Default\AppData\Local\Microsoft\Windows\Shell 找到下面这两个文件夹&#xff1a; 3&#xff0c;修改文件名或者删除这两个文件即可...

1、postman的安装及使用

一、安装、登录 1.安装 下载地址 2.注册登录&#xff08;保存云服务进度&#xff09; 二、界面介绍 三、执行接口测试页面 请求页签&#xff1a; 1、params&#xff1a;当是get请求时&#xff0c;通过params传参 2、authorization&#xff1a;鉴权 3、headers&#xff1…...

VUE简易计划清单

目录 效果预览图 完整代码 效果预览图 完整代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>…...

c++日志单例实现

为了使项目的所有日志都打印到同一个日志中&#xff0c;必须使得所有类使用同一个日志&#xff0c;因此将日志类实现为单例。 .h文件 #pragma once#include<fstream>class LogHablee { private:LogHablee(std::string& dbg_dir);LogHablee(const LogHablee&) …...

C/C++实现:找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和 某知名企业笔试题

目录 题目描述: 示例 1: 示例 2: 示例 3: 提示: 思路:...

Qt实现绘制自定义形状

先创建一个继承自QWidget的控件&#xff1a; class MyPainterWidget:public QWidget 重写各种鼠标方法&#xff1a; protected:void paintEvent(QPaintEvent *) override;void mousePressEvent(QMouseEvent *e) override; //按下void mouseMoveEvent(QMouseEvent *e) …...

在软件开发中正确使用MySQL日期时间类型的深度解析

在日常软件开发场景中&#xff0c;时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志&#xff0c;到供应链系统的物流节点时间戳&#xff0c;时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库&#xff0c;其日期时间类型的…...

大型活动交通拥堵治理的视觉算法应用

大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动&#xff08;如演唱会、马拉松赛事、高考中考等&#xff09;期间&#xff0c;城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例&#xff0c;暖城商圈曾因观众集中离场导致周边…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

【网络安全产品大调研系列】2. 体验漏洞扫描

前言 2023 年漏洞扫描服务市场规模预计为 3.06&#xff08;十亿美元&#xff09;。漏洞扫描服务市场行业预计将从 2024 年的 3.48&#xff08;十亿美元&#xff09;增长到 2032 年的 9.54&#xff08;十亿美元&#xff09;。预测期内漏洞扫描服务市场 CAGR&#xff08;增长率&…...

【快手拥抱开源】通过快手团队开源的 KwaiCoder-AutoThink-preview 解锁大语言模型的潜力

引言&#xff1a; 在人工智能快速发展的浪潮中&#xff0c;快手Kwaipilot团队推出的 KwaiCoder-AutoThink-preview 具有里程碑意义——这是首个公开的AutoThink大语言模型&#xff08;LLM&#xff09;。该模型代表着该领域的重大突破&#xff0c;通过独特方式融合思考与非思考…...

Java 加密常用的各种算法及其选择

在数字化时代&#xff0c;数据安全至关重要&#xff0c;Java 作为广泛应用的编程语言&#xff0c;提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景&#xff0c;有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

C++中string流知识详解和示例

一、概览与类体系 C 提供三种基于内存字符串的流&#xff0c;定义在 <sstream> 中&#xff1a; std::istringstream&#xff1a;输入流&#xff0c;从已有字符串中读取并解析。std::ostringstream&#xff1a;输出流&#xff0c;向内部缓冲区写入内容&#xff0c;最终取…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...