[Redis]典型应用——分布式锁

什么是分布式锁?

在一个分布式系统中,也会涉及到多个节点访问同一个公共资源的情况。此时就需要通过锁来做互斥控制,避免出现类似于"线程安全"的问题

举个例子,在平时抢票时,多个用户可能会同时买票,但票数有限,现在存在多个服务器节点,都可能需要处理这个买票的逻辑:先查询指定车次的余票,如果余票>0,则设置余票值-=1 。显然,这样的情况是存在线程安全问题的,如果不加锁控制,就会导致超卖或数据错误。但是,这可能涉及到不同的机器,而不是传统的同一个线程可以加锁,不同的机器间怎么保证线程安全呢?

为了解决上述问题,我们就可以把redis作为架构中分布式锁的管理器。

分布式锁本质上就是一个架构内一台公共的服务器,用来记录加锁状态,而redis就可以完成这样的工作

工作原理 

 为了防止出现线程安全问题,我们可以在服务器操作数据库之前要先访问redis,在redis上设置一个键值对(mutex:1),如果设置成功,视为获取锁成功,就可以对数据库操作,操作完后,就把redis对应的数据删掉,视为释放锁。在这期间,如果其他服务器想操作数据库,也必须先设置同样的key,设置失败就不能访问数据库。

引入过期时间

但是上述方案还是有问题,如果设置key后,服务器宕机了怎么办?锁就永远无法释放了,所以我们就要设置key的过期时间

服务器在设置key的时候,同时设置key的过期事件,也就是说这个锁最多持有多久,过期自动释放。

注意!此处的过期时间只能使用一个命令的方式设置

如果分开多个操作,比如setnx之后,再来一个单独的expire,由于Redis的多个指令之间不存在关 联,并且即使使用了事务也不能保证这两个操作都一定成功,因此就可能出现setnx成功,但是expire 失败的情况

此时仍然会出现无法正确释放锁的问题

 引入校验id

有没有可能自己设置的锁被别人释放了呢?请看下图

可能会因为一些潜在bug或误操作,释放了别人设置的锁,就会发生很大的问题

为了解决这个问题,我们可以引入校验id

 也就是设置key时设置的value改成有意义的能表示身份的值,比如可以把客户端编号,几号客户端设置的key就把value设置成几

这样,在释放锁,也就是删除key的时候,先校验删除的key的value是不是对应当初加锁的值,如果是,再删数据

引入lua

但是上面这个操作中,先get key再del key 这两步并不是原子的,也会有线程安全问题。

为了让解锁操作原子性,可以使用redis的lua脚本功能

Lua也是一个编程语言.读作"撸啊"。是葡萄牙语中的"月亮"的意思

为什么redis会选择lua作为内嵌的脚本语言呢?因为Lua语法简单精炼,执行速度快,解释器也比较轻量,内嵌到redis中不会太过于臃肿

lua脚本可以编写成一个.lua后缀的文件,可以由 redis-cli 发送给redis,由redis服务器来执行脚本

一个lua脚本会被redis服务器以原子的方式执行

引入看门狗(watch dog)

上述方案仍然有一定问题,当我们设置过期时间(比如10s)后,如果任务还没有执行完,锁就已经过期失效了,怎么办?

那就可以引入看门狗,本质上是服务器上的一个单独的线程,通过这个线程来对锁过期时间进行"续约"

比如说,我们设置10s过期,设置看门狗每隔3s检测一次,每过3s,看门狗就去判定当前任务是否完成,如果任务完成了,就释放锁,如果任务未完成,就把过期时间重新设置成10s(续约)

值得一提的是,看门狗线程应该是业务服务器的线程,而不是redis服务器的线程

这样,不用担心锁提前过期,就算服务器挂了,看门狗线程也就挂了,就没人去续约,过期就会释放锁了

引入redlock算法

到这里,方案还是有一定问题,如果redis服务器(也就是分布式锁管理器)挂了,怎么办?那我们可以对redis服务器设计主从架构,保证redis服务器的可用性

那么就有一个问题,如果当我获取锁之后,redis主服务器挂了,从服务器变成了主服务器,但是加锁的数据还没有同步,这时候获取的锁失效了,别的服务器仍然可以获取锁

为了解决这个问题,Redis的作者提出了Redlock算法

我们引入一组Redis节点,其中每一组Redis节点都包含一个主节点和若干从节点.并且组和组之间存储的数据都是一致的,相互之间是"备份"关系

首先,获取锁

客户端依次向Redis 节点(通常是 5 个)请求加锁。每个节点使用相同的 key 和一个唯一的随机值(UUID)(校验用)。

客户端在每个节点上设置锁的过期时间(TTL),以防止锁的持有者崩溃后锁无法释放。

如果客户端无法在某个节点上设置锁(例如,实例不可用或已经被其他客户端持有锁),则立即尝试下一个节点。

其次,检查锁的有效性

客户端计算从开始尝试加锁到完成加锁操作的总时间。

如果总时间小于锁的 TTL ,且客户端至少在 N/2 + 1 个节点上成功加锁,则认为锁获取成功。如果锁获取失败(未能在足够多的节点上成功加锁),客户端应立即在所有节点上释放已获取的锁。

比如说锁过期时间为50ms,有5个redis节点,从给第一个节点加锁开始算,到最后一个节点加锁截止,如果加起来总时间小于锁的过期时间(50ms),而且至少有3个节点加锁成功,那么就获取一个锁成功(50ms)

因为如果加锁流程时间太长,比如锁过期时间是50ms,结果光去各个节点加锁就用了100ms,那肯定有部分锁都已经过期了,这时候也就不能认为加锁成功了 

最后,释放锁

客户端在所有实例上依次释放锁。释放锁时,客户端需要检查锁的值是否与自己持有的随机值一致,以确保只有持有锁的客户端才能释放锁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/380082.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ubuntu源码安装Odoo

序言:时间是我们最宝贵的财富,珍惜手上的每个时分 Odoo具有非常多的安装方式,除了我最爱用的 apt-get install,我们还可以使用git拉取Odoo源码进行安装。 本次示例于ubuntu20.04 Desktop上进行操作,理论上在ubuntu14.04之后都可以用此操作。 …

第1关 -- Linux 基础知识

闯关任务 完成SSH连接与端口映射并运行hello_world.py ​​​​ ssh -p 37367 rootssh.intern-ai.org.cn -CNg -L 7860:127.0.0.1:7860 -o StrictHostKeyCheckingno可选任务 1 将Linux基础命令在开发机上完成一遍 可选任务 2 使用 VSCODE 远程连接开发机并创建一个conda环境 …

关于c#的简单应用三题

#region 找出100以内与7有关的数并打印&#xff1a; public static void Print() { int sum 0; Console.WriteLine("100以内与7有关的数有&#xff1a;"); for (int i 1; i < 100; i) { if (i % 7 0) { sum; …

【AI教程-吴恩达讲解Prompts】第1篇 - 课程简介

文章目录 简介Prompt学习相关资源 两类大模型原则与技巧 简介 欢迎来到面向开发者的提示工程部分&#xff0c;本部分内容基于吴恩达老师的《Prompt Engineering for Developer》课程进行编写。《Prompt Engineering for Developer》课程是由吴恩达老师与 OpenAI 技术团队成员 I…

Flink HA

目录 Flink HA集群规划 环境变量配置 masters配置 flink-conf.yaml配置 测试 Flink HA集群规划 FLink HA集群规划如下&#xff1a; IP地址主机名称Flink角色ZooKeeper角色192.168.128.111bigdata111masterQuorumPeerMain192.168.128.112bigdata112worker、masterQuorumPee…

js 实现扫雷游戏,源码开放,支持npm引入使用

本人开发的js版本扫雷游戏 体验地址 | Github Minesweeper game Sponsors Install and use npm i minesweeper-gameimport {Map} from minesweeper-game;const map new Map();Reset Map map.reset();TS Statement interface IMapOptions {width?: number; // Map sizeh…

JMeter:BeanShell向JSR223迁移过程遭遇的java标准库不可用问题-如何切换JDK版本

前言 看过我前面文章的人想必记得我因使用BeanShell&#xff0c;遭遇过JMeter OOM的问题。所以想起官网频频提示的&#xff0c;性能测试中建议使用JSR223groovy来代替BeanShell。于是&#xff0c;开启BeanShell脚本向JSR223迁移之旅。 什么是JSR223 JSR223全称为Java Specif…

Python爬虫(1) --基础知识

爬虫 爬虫是什么&#xff1f; spider 是一种模仿浏览器上网过程的一种程序&#xff0c;可以获取一些网页的数据 基础知识 URL 统一资源定位符 uniform resource locator http: 超文本传输协议 HyperText Transfer Protocol 默认端口 80 https: 安全的超文本传输协议 security…

jenkins+gitlab+harbor+maven自动化容器部署

一、gitlab安装配置 1.1、安装 由于比较懒啊&#xff01;这里就直接使用docker安装了啊&#xff01; 没事先更新一个yum源&#xff1a;yum update -y 整一个gitlab镜像&#xff1a;docker pull gitlab/gitlab-ce 运行一个gitlab容器&#xff1a;docker run -d -p 8443:443 -p…

十七、【机器学习】【非监督学习】- K-均值 (K-Means)

系列文章目录 第一章 【机器学习】初识机器学习 第二章 【机器学习】【监督学习】- 逻辑回归算法 (Logistic Regression) 第三章 【机器学习】【监督学习】- 支持向量机 (SVM) 第四章【机器学习】【监督学习】- K-近邻算法 (K-NN) 第五章【机器学习】【监督学习】- 决策树…

[论文笔记] pai-megatron-patch Qwen2-CT 长文本rope改yarn

更改: # Copyright (c) 2024 Alibaba PAI and Nvidia Megatron-LM Team. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License a…

MongoDB常用命令大全,概述、备份恢复

文章目录 一、MongoDB简介二、服务启动停止、连接三、数据库相关四、集合操作五、文档操作六、数据备份与恢复/导入导出数据6.1 mongodump备份数据库6.2 mongorestore还原数据库6.3 mongoexport导出表 或 表中部分字段6.4 mongoimport导入表 或 表中部分字段 七、其他常用命令八…

怎么关闭 Windows 安全中心,手动关闭 Windows Defender 教程

Windows 安全中心&#xff08;也称为 Windows Defender Security Center&#xff09;是微软 Windows 操作系统内置的安全管理工具&#xff0c;用于监控和控制病毒防护、防火墙、应用和浏览器保护等安全功能。然而&#xff0c;在某些情况下&#xff0c;用户可能需要关闭 Windows…

深层神经网络示例

维度说明&#xff1a; A[L]、Z[L]&#xff1a;&#xff08;本层神经元个数、样本数&#xff09; W[L]&#xff1a;&#xff08;本层神经元个数、上层神经元个数&#xff09; b[L]&#xff1a;&#xff08;本层神经元个数、1&#xff09; dZ[L]&#xff1a;dA[L] * g’A&#xf…

【BUG】已解决:ModuleNotFoundError: No module named ‘PIL‘

已解决&#xff1a;ModuleNotFoundError: No module named ‘PIL‘ 目录 已解决&#xff1a;ModuleNotFoundError: No module named ‘PIL‘ 【常见模块错误】 错误原因&#xff1a; 解决办法&#xff1a; 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我…

时序数据库如何选型?详细指标总结!

工业物联网场景&#xff0c;如何判断什么才是好的时序数据库&#xff1f; 工业物联网将机器设备、控制系统与信息系统、业务过程连接起来&#xff0c;利用海量数据进行分析决策&#xff0c;是智能制造的基础设施&#xff0c;并影响整个工业价值链。工业物联网机器设备感知形成了…

《Techporters架构搭建》-Day02 集成Mybatis-plus

集成Mybatis-plus Mybatis-plus集成Mybatis-plus步骤小结 Mybatis-plus Mybatis-plus官网 MyBatisPlus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。它引入了一些新的特性&…

CSRF+XSS组合攻击实战

目录 0x01安装靶场 0x02分析功能点的请求接口&#xff0c;构造恶意请求 0x03寻找xss漏洞 0x01安装靶场 下载源码&#xff0c;解压到网站根目录 1.修改数据库配置文件 打开源码&#xff0c;进入到include目录下&#xff0c;打开数据库配置文件database.inc.php 将数据库的…

Template_C++

C模板 C提供了function template. function template&#xff1a;实际上是建立一个通用函数&#xff0c;其函数类型和形参类型不具体制定&#xff0c;用一个虚拟的类型来代表。这个通用的函数就称为函数模版。 是不是可以这样理解&#xff0c;函数模版就是给了一种功能&…

Keil开发IDE

Keil开发IDE 简述Keil C51Keil ARMMDK DFP安装 简述 Keil公司是一家业界领先的微控制器&#xff08;MCU&#xff09;软件开发工具的独立供应商。Keil公司由两家私人公司联合运营&#xff0c;分别是德国慕尼黑的Keil Elektronik GmbH和美国德克萨斯的Keil Software Inc。Keil公…