简单认识redis - 12 redis锁
在斜体样式**redis中,不同的问题有不一样的解决办法,那么锁也有不同的锁来解决不一样的问题,下面将举出几个常用的redis锁。
1. SETNX锁(简单独占锁)
- 原理:
- SETNX(SET if Not eXists)是Redis实现简单锁的命令。它的操作是原子性的,当尝试设置一个键值对时,如果键不存在,则设置成功并返回1,表示获取锁成功;如果键已经存在,则返回0,表示锁已被其他客户端占用。
- 示例:
- 假设使用
lock_key作为锁的键,locked_value作为锁的值,在Java中可以这样实现:import redis.clients.jedis.Jedis;public class SimpleRedisLock {public static void main(String[] args) {Jedis jedis = new Jedis("localhost", 6379);String lock_key = "my_lock";String locked_value = "locked";long result = jedis.setnx(lock_key, locked_value);if (result == 1) {System.out.println("获取锁成功");// 执行业务逻辑try {// 模拟业务逻辑执行时间Thread.sleep(5000);} catch (InterruptedException e) {e.printStackTrace();}// 释放锁,这里简单地删除键jedis.del(lock_key);} else {System.out.println("获取锁失败");}jedis.close();} }
- 假设使用
- 局限性:
- 没有自动释放机制。如果获取锁的客户端崩溃或者出现异常没有执行释放锁的操作,这个锁将一直被占用,导致死锁。
2. 带有过期时间的SET锁
- 原理:
- Redis的SET命令可以在设置键值对的同时设置过期时间,并且这个操作是原子性的。例如,
SET key value EX seconds NX这样的命令格式,其中EX seconds表示设置过期时间为seconds秒,NX表示只有当键不存在时才设置。
- Redis的SET命令可以在设置键值对的同时设置过期时间,并且这个操作是原子性的。例如,
- 示例:
- 在Python中,可以这样实现:
import redis import timer = redis.Redis(host='localhost', port=6379) lock_key = "my_lock" locked_value = "locked" expire_time = 10 result = r.set(lock_key, locked_value, ex=expire_time, nx=True) if result:print("获取锁成功")try:# 执行业务逻辑time.sleep(7)finally:# 不需要手动删除锁,过期后自动释放pass else:print("获取锁失败")
- 在Python中,可以这样实现:
- 注意事项:
- 业务逻辑执行时间如果超过了锁的过期时间,可能会出现数据不一致的情况。例如,在锁过期后,其他客户端获取了锁,然后原来的客户端完成业务逻辑并释放锁,这可能会导致新获取锁的客户端的操作受到干扰。
3. RedLock(分布式锁算法)
- 原理:
- RedLock算法用于在多个Redis节点组成的分布式环境中获取高可靠的锁。它要求在多个(通常是奇数个)独立的Redis节点上尝试获取锁,只有当大多数节点(例如,总共5个节点,至少3个节点)成功获取锁时,才认为锁获取成功。
- 示例流程(简化):
- 假设有3个Redis节点
node1、node2、node3,在Python中实现RedLock的基本步骤如下:import redis import time# 定义Redis节点列表 redis_nodes = [redis.Redis(host='node1', port=6379),redis.Redis(host='node2', port=6379),redis.Redis(host='node3', port=6379) ]lock_key = "my_redlock" locked_value = "unique_client_id" expire_time = 10 quorum = len(redis_nodes) // 2 + 1 acquired_locks = 0# 尝试在多个节点上获取锁 for node in redis_nodes:try:result = node.set(lock_key, locked_value, ex=expire_time, nx=True)if result:acquired_locks += 1except:pass if acquired_locks >= quorum:print("RedLock获取成功")try:# 执行业务逻辑time.sleep(7)finally:# 释放锁,需要向所有节点发送释放请求for node in redis_nodes:try:node.delete(lock_key)except:pass else:print("RedLock获取失败")
- 假设有3个Redis节点
- 优势与应用场景:
- 提供了更高的可靠性,能够抵抗单个Redis节点故障、网络分区等问题,适用于对数据一致性要求极高的分布式系统,如金融交易系统、分布式任务调度系统等。
4. 基于Lua脚本实现的复杂锁(如可重入锁)
- 原理:
- Lua脚本在Redis中可以原子地执行多个命令,通过编写Lua脚本可以实现复杂的锁逻辑。例如,实现可重入锁时,可以在脚本中检查锁的持有者是否为当前客户端,如果是,则增加重入次数;如果不是,则判断是否可以获取锁。
- 示例(简单的可重入锁检查脚本):
- 以下是一个简单的Redis Lua脚本用于检查可重入锁(假设锁的信息存储在一个哈希表中,键为
lock_key,字段owner存储持有者,count存储重入次数):-- 检查锁是否存在且持有者是当前客户端 local lock_key = KEYS[1] local client_id = ARGV[1] local lock_info = redis.call('hgetall', lock_key) if #lock_info == 0 then-- 锁不存在,设置持有者为当前客户端,重入次数为1redis.call('hmset', lock_key, 'owner', client_id, 'count', 1)return 1 elseif lock_info[2] == client_id then-- 持有者是当前客户端,增加重入次数redis.call('hincrby', lock_key, 'count', 1)return 1 elsereturn 0 end - 在Java中调用这个Lua脚本可以这样实现:
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.jedis.Response; import redis.clients.jedis.ScriptingCommands;public class ReentrantRedisLock {private static final String LUA_SCRIPT = "local lock_key = KEYS[1]\n" +"local client_id = ARGV[1]\n" +"local lock_info = redis.call('hgetall', lock_key)\n" +"if #lock_info == 0 then\n" +" -- 锁不存在,设置持有者为当前客户端,重入次数为1\n" +" redis.call('hmset', lock_key, 'owner', client_id, 'count', 1)\n" +" return 1\n" +"elseif lock_info[2] == client_id then\n" +" -- 持有者是当前客户端,增加重入次数\n" +" redis.call('hincrby', lock_key, 'count', 1)\n" +" return 1\n" +"else\n" +" return 0\n" +"end";private JedisPool jedisPool;public ReentrantRedisLock() {JedisPoolConfig poolConfig = new JedisPoolConfig();jedisPool = new JedisPool(poolConfig, "localhost", 6379);}public boolean tryLock(String lock_key, String client_id) {try (Jedis jedis = jedisPool.getResource()) {ScriptingCommands scriptingCommands = jedis.scriptingCommands();Response<Long> response = scriptingCommands.evalsha(scriptingCommands.scriptLoad(LUA_SCRIPT), 1, lock_key, client_id);return response.get() == 1;}}public void unlock(String lock_key, String client_id) {try (Jedis jedis = jedisPool.getResource()) {// 这里还需要编写释放锁的Lua脚本,此处省略// 基本思路是检查重入次数,减1后如果为0则删除锁的记录}} }
- 以下是一个简单的Redis Lua脚本用于检查可重入锁(假设锁的信息存储在一个哈希表中,键为
- 优势与应用场景:
- 可以实现更灵活、复杂的锁机制,如可重入锁、公平锁等,满足特定业务场景下对锁的高级需求,如在递归调用函数中需要获取同一把锁,或者需要按照请求顺序公平地获取锁的场景。
相关文章:
简单认识redis - 12 redis锁
在斜体样式**redis中,不同的问题有不一样的解决办法,那么锁也有不同的锁来解决不一样的问题,下面将举出几个常用的redis锁。 1. SETNX锁(简单独占锁) 原理: SETNX(SET if Not eXistsÿ…...
基于springboot+vue车辆充电桩管理系统
基于springbootvue车辆充电桩管理系统 摘 要 随着信息化时代的到来,管理系统都趋向于智能化、系统化,车辆充电桩管理系统也不例外,但目前国内仍都使用人工管理,市场规模越来越大,同时信息量也越来越庞大,…...
shodan用法(完)
声明 学习视频来自B 站up主泷羽sec,如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负。 shodan 今天,我们把shoda…...
【若依框架】代码生成详细教程,15分钟搭建Springboot+Vue3前后端分离项目,基于Mysql8数据库和Redis5,管理后台前端基于Vue3和Element Plus,开发小程序数据后台
今天我们来借助若依来快速的搭建一个基于springboot的Java管理后台,后台网页使用vue3和 Element Plus来快速搭建。这里我们可以借助若依自动生成Java和vue3代码,这就是若依的强大之处,即便你不会Java和vue开发,只要跟着石头哥也可…...
转子侧串级调速系统和双馈调速系统
转子侧串级调速系统和双馈调速系统是两种不同的电机调速技术,它们在基本原理、效率以及应用场景等方面存在区别。以下是详细的对比分析: 基本原理 转子侧串级调速系统:通过在绕线式异步电动机的转子回路中串入一个可调节的附加电势࿰…...
AI学习指南自然语言处理篇-Transformer模型的实践
AI学习指南自然语言处理篇 - Transformer模型的实践 目录 引言Transformer模型概述 自注意力机制编码器-解码器结构 环境准备Transformer模型的实现 编码器实现解码器实现Transformer模型整体实现 Transformer在NLP任务中的应用 文本分类机器翻译 总结与展望 引言 在过去的数…...
【LVGL速成】LVGL修改标签文本(GUI Guider生成的字库问题)
目录 前置篇章: 一.问题背景 二.失败方案 三.成功方案 1.Gui guider的源码结构 2.手动生成字体 3.Keil中配置相关文件 编辑 4.修改文字 四.字体样式函数说明 前置篇章: 【LVGL快速入门(二)】LVGL开源框架入门教程之框架使用(UI界面设计)_lvgl…...
C语言项目实践-贪吃蛇
⽬录: 1. 游戏背景 2. 游戏效果演⽰ 3. 实现的⽬标 4. 实现的定位 5. 技术要点 6. 贪吃蛇游戏设计与分析 7. 贪吃蛇游戏数据结构设计 8. 相关Win32API介绍 9. 参考代码 正文开始 1. 游戏背景 贪吃蛇是久负盛名的游戏,它也和俄罗斯⽅块…...
在kanzi 3.9.8里使用API创建自定义材质
1. kanzi studio设置 1.1 创建一个纹理贴图,起名Render Target Texture 1.2 创建一个Image节点,使用该贴图 2. 代码设置 2.1 创建一个自定义节点类 class mynode2d : public Node2D { public: virtual void renderOverride(Renderer3D& renderer…...
IDEA中通义灵码的使用技巧
大家好,我是 V 哥。在日常写代码的过程中,通过 AI 工具辅助开发已是当下程序员惯用的方式,V 哥在使用了众多的 AI 工具后,多数情况下,选择通义灵码来辅助开发,尤其是解释代码和生成单元测试功能甚是好用&am…...
JS中let var 和const区别
在JavaScript中,let、var 和 const 都是用来声明变量的关键字,但它们之间有几个关键的区别: 作用域(Scope): var 声明的变量拥有函数作用域(function scope),这意味着如果 var 变量在…...
ansible详细介绍和具体步骤
Ansible简介 1.1 Ansible的基本概念 Ansible是一款开源的自动化工具,旨在简化IT操作的复杂性。它由Michael DeHaan创建,并于2012年发布,随后在2015年被Red Hat收购。Ansible的核心理念是“简单即美”,它通过使用YAML(…...
利用LangChain与LLM打造个性化私有文档搜索系统
我们知道LLM(大语言模型)的底模是基于已经过期的公开数据训练出来的,对于新的知识或者私有化的数据LLM一般无法作答,此时LLM会出现“幻觉”。针对“幻觉”问题,一般的解决方案是采用RAG做检索增强。 但是我们不可能把…...
linux中的软、硬链接
目录 引言 简单介绍 如何理解软硬链接 链接的应用 环路问题 引言 在Linux操作系统的广阔天地中,文件管理是其核心功能之一。而软链接和硬链接作为Linux文件系统中的两种特殊链接方式,它们为用户提供了灵活的文件访问途径和高效的磁盘空间利用手段。…...
Ubuntu 系统、Docker配置、Docker的常用软件配置(下)
前言 书接上文,现在操作系统已经有了,作为程序的载体Docker也安装配置好了,接下来我们需要让Docker发挥它的法力了。 Docker常用软件的安装 1.Redis 缓存安装 1.1 下载 docker pull redis:7.4.1 #可改为自己需要的版本 1.2 创建本地目录存储…...
jdk,openjdk,oraclejdk
Java是开发语言,不是软件。JDK是软件,使用OpenJDK是免费的,一直免费。而且OpenJDK正儿巴经的Java社区推出来的JDK。 Oracle JDK主要是面向付费能力强的企业用户,收费已经好多年了,不是一两年的事,JDK8是JDK…...
Docker Hub 镜像加速器
零、参考资料 https://gist.github.com/y0ngb1n/7e8f16af3242c7815e7ca2f0833d3ea6Daemon proxy configuration | Docker Docs 一、解决方案 1、问题现象 Error response from daemon: Get "https://index.docker.io/v1/search?qcarlasim%2Fcarla&n25": dia…...
DevOps赋能:优化业务价值流的实战策略与路径(上)
上篇:价值流引领与可视化体系构建 一、前言 在快速迭代的软件项目和产品开发生态中,我们始终围绕两个核心目标:一是确保每一项工作都能为客户创造实际价值,这是产品团队的核心使命;二是确保这些有价值的工作能够高效…...
int的取值范围
原码(True form):原码是一种计算机中对数字的二进制表示方法,数码序列中最高位为符号位,符号位为0表示正数,符号位为1表示负数;其余有效值部分用二进制的绝对值表示。 反码…...
图文检索(16):IDC: Boost Text-to-Image Retrieval via Indirect and Direct Connections
IDC: Boost Text-to-Image Retrieval via Indirect and Direct Connections 摘要3 方法3.1 直接连接3.2 间接连接3.3 DLB 正则化 结论 发布时间(2024 LREC-COLING) 标题:IDC:通过间接和直接连接增强文本到图像的检索 摘要 本文&…...
测试微信模版消息推送
进入“开发接口管理”--“公众平台测试账号”,无需申请公众账号、可在测试账号中体验并测试微信公众平台所有高级接口。 获取access_token: 自定义模版消息: 关注测试号:扫二维码关注测试号。 发送模版消息: import requests da…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...
全志A40i android7.1 调试信息打印串口由uart0改为uart3
一,概述 1. 目的 将调试信息打印串口由uart0改为uart3。 2. 版本信息 Uboot版本:2014.07; Kernel版本:Linux-3.10; 二,Uboot 1. sys_config.fex改动 使能uart3(TX:PH00 RX:PH01),并让boo…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
Java编程之桥接模式
定义 桥接模式(Bridge Pattern)属于结构型设计模式,它的核心意图是将抽象部分与实现部分分离,使它们可以独立地变化。这种模式通过组合关系来替代继承关系,从而降低了抽象和实现这两个可变维度之间的耦合度。 用例子…...
人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...
