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

简单认识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表示只有当键不存在时才设置。
  • 示例
    • 在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("获取锁失败")
      
  • 注意事项
    • 业务逻辑执行时间如果超过了锁的过期时间,可能会出现数据不一致的情况。例如,在锁过期后,其他客户端获取了锁,然后原来的客户端完成业务逻辑并释放锁,这可能会导致新获取锁的客户端的操作受到干扰。

3. RedLock(分布式锁算法)

  • 原理
    • RedLock算法用于在多个Redis节点组成的分布式环境中获取高可靠的锁。它要求在多个(通常是奇数个)独立的Redis节点上尝试获取锁,只有当大多数节点(例如,总共5个节点,至少3个节点)成功获取锁时,才认为锁获取成功。
  • 示例流程(简化)
    • 假设有3个Redis节点node1node2node3,在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获取失败")
      
  • 优势与应用场景
    • 提供了更高的可靠性,能够抵抗单个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 - 12 redis锁

在斜体样式**redis中&#xff0c;不同的问题有不一样的解决办法&#xff0c;那么锁也有不同的锁来解决不一样的问题&#xff0c;下面将举出几个常用的redis锁。 1. SETNX锁&#xff08;简单独占锁&#xff09; 原理&#xff1a; SETNX&#xff08;SET if Not eXists&#xff…...

基于springboot+vue车辆充电桩管理系统

基于springbootvue车辆充电桩管理系统 摘 要 随着信息化时代的到来&#xff0c;管理系统都趋向于智能化、系统化&#xff0c;车辆充电桩管理系统也不例外&#xff0c;但目前国内仍都使用人工管理&#xff0c;市场规模越来越大&#xff0c;同时信息量也越来越庞大&#xff0c;…...

shodan用法(完)

声明 学习视频来自B 站up主泷羽sec&#xff0c;如涉及侵权马上删除文章。 笔记的只是方便各位师傅学习知识&#xff0c;以下网站只涉及学习内容&#xff0c;其他的都与本人无关&#xff0c;切莫逾越法律红线&#xff0c;否则后果自负。 shodan 今天&#xff0c;我们把shoda…...

【若依框架】代码生成详细教程,15分钟搭建Springboot+Vue3前后端分离项目,基于Mysql8数据库和Redis5,管理后台前端基于Vue3和Element Plus,开发小程序数据后台

今天我们来借助若依来快速的搭建一个基于springboot的Java管理后台&#xff0c;后台网页使用vue3和 Element Plus来快速搭建。这里我们可以借助若依自动生成Java和vue3代码&#xff0c;这就是若依的强大之处&#xff0c;即便你不会Java和vue开发&#xff0c;只要跟着石头哥也可…...

转子侧串级调速系统和双馈调速系统

转子侧串级调速系统和双馈调速系统是两种不同的电机调速技术&#xff0c;它们在基本原理、效率以及应用场景等方面存在区别。以下是详细的对比分析&#xff1a; 基本原理 转子侧串级调速系统&#xff1a;通过在绕线式异步电动机的转子回路中串入一个可调节的附加电势&#xff0…...

AI学习指南自然语言处理篇-Transformer模型的实践

AI学习指南自然语言处理篇 - Transformer模型的实践 目录 引言Transformer模型概述 自注意力机制编码器-解码器结构 环境准备Transformer模型的实现 编码器实现解码器实现Transformer模型整体实现 Transformer在NLP任务中的应用 文本分类机器翻译 总结与展望 引言 在过去的数…...

【LVGL速成】LVGL修改标签文本(GUI Guider生成的字库问题)

目录 前置篇章&#xff1a; 一.问题背景 二.失败方案 三.成功方案 1.Gui guider的源码结构 2.手动生成字体 3.Keil中配置相关文件 ​编辑 4.修改文字 四.字体样式函数说明 前置篇章&#xff1a; 【LVGL快速入门(二)】LVGL开源框架入门教程之框架使用(UI界面设计)_lvgl…...

C语言项目实践-贪吃蛇

⽬录&#xff1a; 1. 游戏背景 2. 游戏效果演⽰ 3. 实现的⽬标 4. 实现的定位 5. 技术要点 6. 贪吃蛇游戏设计与分析 7. 贪吃蛇游戏数据结构设计 8. 相关Win32API介绍 9. 参考代码 正文开始 1. 游戏背景 贪吃蛇是久负盛名的游戏&#xff0c;它也和俄罗斯⽅块&#xf…...

在kanzi 3.9.8里使用API创建自定义材质

1. kanzi studio设置 1.1 创建一个纹理贴图&#xff0c;起名Render Target Texture 1.2 创建一个Image节点&#xff0c;使用该贴图 2. 代码设置 2.1 创建一个自定义节点类 class mynode2d : public Node2D { public: virtual void renderOverride(Renderer3D& renderer…...

IDEA中通义灵码的使用技巧

大家好&#xff0c;我是 V 哥。在日常写代码的过程中&#xff0c;通过 AI 工具辅助开发已是当下程序员惯用的方式&#xff0c;V 哥在使用了众多的 AI 工具后&#xff0c;多数情况下&#xff0c;选择通义灵码来辅助开发&#xff0c;尤其是解释代码和生成单元测试功能甚是好用&am…...

JS中let var 和const区别

在JavaScript中&#xff0c;let、var 和 const 都是用来声明变量的关键字&#xff0c;但它们之间有几个关键的区别&#xff1a; 作用域&#xff08;Scope&#xff09;: var 声明的变量拥有函数作用域&#xff08;function scope&#xff09;&#xff0c;这意味着如果 var 变量在…...

ansible详细介绍和具体步骤

Ansible简介 1.1 Ansible的基本概念 Ansible是一款开源的自动化工具&#xff0c;旨在简化IT操作的复杂性。它由Michael DeHaan创建&#xff0c;并于2012年发布&#xff0c;随后在2015年被Red Hat收购。Ansible的核心理念是“简单即美”&#xff0c;它通过使用YAML&#xff08…...

利用LangChain与LLM打造个性化私有文档搜索系统

我们知道LLM&#xff08;大语言模型&#xff09;的底模是基于已经过期的公开数据训练出来的&#xff0c;对于新的知识或者私有化的数据LLM一般无法作答&#xff0c;此时LLM会出现“幻觉”。针对“幻觉”问题&#xff0c;一般的解决方案是采用RAG做检索增强。 但是我们不可能把…...

linux中的软、硬链接

目录 引言 简单介绍 如何理解软硬链接 链接的应用 环路问题 引言 在Linux操作系统的广阔天地中&#xff0c;文件管理是其核心功能之一。而软链接和硬链接作为Linux文件系统中的两种特殊链接方式&#xff0c;它们为用户提供了灵活的文件访问途径和高效的磁盘空间利用手段。…...

Ubuntu 系统、Docker配置、Docker的常用软件配置(下)

前言 书接上文&#xff0c;现在操作系统已经有了&#xff0c;作为程序的载体Docker也安装配置好了&#xff0c;接下来我们需要让Docker发挥它的法力了。 Docker常用软件的安装 1.Redis 缓存安装 1.1 下载 docker pull redis:7.4.1 #可改为自己需要的版本 1.2 创建本地目录存储…...

jdk,openjdk,oraclejdk

Java是开发语言&#xff0c;不是软件。JDK是软件&#xff0c;使用OpenJDK是免费的&#xff0c;一直免费。而且OpenJDK正儿巴经的Java社区推出来的JDK。 Oracle JDK主要是面向付费能力强的企业用户&#xff0c;收费已经好多年了&#xff0c;不是一两年的事&#xff0c;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赋能:优化业务价值流的实战策略与路径(上)

上篇&#xff1a;价值流引领与可视化体系构建 一、前言 在快速迭代的软件项目和产品开发生态中&#xff0c;我们始终围绕两个核心目标&#xff1a;一是确保每一项工作都能为客户创造实际价值&#xff0c;这是产品团队的核心使命&#xff1b;二是确保这些有价值的工作能够高效…...

int的取值范围

原码&#xff08;True form&#xff09;&#xff1a;原码是一种计算机中对数字的二进制表示方法&#xff0c;数码序列中最高位为符号位&#xff0c;符号位为0表示正数&#xff0c;符号位为&#xff11;表示负数&#xff1b;其余有效值部分用二进制的绝对值表示。 反码&#xf…...

图文检索(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 正则化 结论 发布时间&#xff08;2024 LREC-COLING&#xff09; 标题&#xff1a;IDC&#xff1a;通过间接和直接连接增强文本到图像的检索 摘要 本文&…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现

目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话&#xff1a; “利润不是赚出来的&#xff0c;是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业&#xff0c;很多企业看着销售不错&#xff0c;账上却没钱、利润也不见了&#xff0c;一翻库存才发现&#xff1a; 一堆卖不动的旧货…...

2025 后端自学UNIAPP【项目实战:旅游项目】6、我的收藏页面

代码框架视图 1、先添加一个获取收藏景点的列表请求 【在文件my_api.js文件中添加】 // 引入公共的请求封装 import http from ./my_http.js// 登录接口&#xff08;适配服务端返回 Token&#xff09; export const login async (code, avatar) > {const res await http…...

【git】把本地更改提交远程新分支feature_g

创建并切换新分支 git checkout -b feature_g 添加并提交更改 git add . git commit -m “实现图片上传功能” 推送到远程 git push -u origin feature_g...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

DingDing机器人群消息推送

文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人&#xff0c;点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置&#xff0c;详见说明文档 成功后&#xff0c;记录Webhook 2 API文档说明 点击设置说明 查看自…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用&#xff1a; 方法一&#xff1a;使用 Homebrew 安装 Git&#xff08;推荐&#xff09; 步骤如下&#xff1a;打开终端&#xff08;Terminal.app&#xff09; 1.安装 Homebrew…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建

【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...

c# 局部函数 定义、功能与示例

C# 局部函数&#xff1a;定义、功能与示例 1. 定义与功能 局部函数&#xff08;Local Function&#xff09;是嵌套在另一个方法内部的私有方法&#xff0c;仅在包含它的方法内可见。 • 作用&#xff1a;封装仅用于当前方法的逻辑&#xff0c;避免污染类作用域&#xff0c;提升…...