Redisson分布式锁的概念和使用

news2024/11/6 3:00:09

Redisson分布式锁的概念和使用

    • 一 简介
      • 1.1 什么是分布式锁?
      • 1.2 Redisson分布式锁的原理
      • 1.3 Redisson分布式锁的优势
      • 1.4 Redisson分布式锁的应用场景
    • 二 案例
      • 2.1 锁竞争案例
      • 2.2 看门狗案例
      • 2.3 参考文章

前言
这是我在这个网站整理的笔记,有错误的地方请指出,关注我,接下来还会持续更新。

作者:神的孩子都在歌唱

一 简介

1.1 什么是分布式锁?

在分布式系统中,多个服务实例或进程可能会同时访问共享资源(例如数据库、文件等)。为了防止数据竞争或一致性问题,我们需要一种机制来确保在同一时间,只有一个进程能够访问这些资源。这种机制就是分布式锁。

Redisson 是一个支持 Redis 的 Java 客户端,它不仅能提供简单的 Redis 连接,还包括了许多高级功能,如分布式锁、异步任务执行、限流等。Redisson 基于 Redis 来实现分布式锁,具备高效、可靠的特性。

1.2 Redisson分布式锁的原理

Redisson 的分布式锁主要依赖 Redis 的 SETNXEXPIRE 命令来实现。流程如下:

  1. 获取锁:客户端通过 SETNX(SET if Not eXists)命令尝试在 Redis 中设置一个键。如果该键不存在,表示没有其他进程持有锁,当前进程即可成功获取锁。

  2. 锁过期时间:为了避免某个持有锁的进程崩溃而导致锁无法释放,通常会为锁设置一个过期时间(如10秒)。如果超过这个时间锁还没有被释放,Redis 将自动删除该锁,允许其他进程获取。

  3. 释放锁:当任务完成后,进程会通过 DEL 命令来释放锁,其他进程就可以重新获取锁。

  4. 可重入锁:Redisson 提供了可重入锁,即同一个线程可以多次获取锁,而不会被锁定阻塞。只有当线程完全释放锁后,其他线程才能获取该锁。

1.3 Redisson分布式锁的优势

  • 高效:Redis 基于内存操作,具有极快的响应速度。Redisson 使用 Lua 脚本将获取和释放锁的操作进行原子化操作,避免并发问题。
  • 可靠性:Redisson 通过 Redis 的过期机制和 Watchdog(看门狗)机制,确保锁可以自动释放,防止因进程异常退出导致的死锁问题。
  • 可扩展性:Redisson 支持 Redis 集群、哨兵模式等多种模式,适用于不同规模的分布式系统。

1.4 Redisson分布式锁的应用场景

  1. 库存扣减:在电商系统中,当用户发起购买请求时,需要确保在多个并发请求中,库存只能被扣减一次,避免超卖现象。

  2. 任务调度:在分布式任务调度系统中,需要保证同一时间只有一个服务实例执行某个任务,防止重复执行。

  3. 分布式事务:在分布式事务中,确保在多个服务之间的一致性操作,分布式锁能够确保只有一个服务能修改某个共享资源。

二 案例

2.1 锁竞争案例

假设我有两个节点可以执行同一种业务,我需求是节点1执行的时候,节点2不能执行。那么就可以使用分布式锁实现,代码如下

引入redisson的依赖

        <dependency>
            <groupId>org.redisson</groupId>
            <artifactId>redisson</artifactId>
            <version>3.35.0</version>
        </dependency>

编一个redisson客户端

public class RedissonConfig {

    public RedissonClient redissonClient() {
        Config config = new Config();
        config.useSingleServer().setAddress("redis://192.168.1.47:6379").setPassword("xxxx");
        return Redisson.create(config);
    }
}

节点1

package org.example.demo;
import org.example.tool.RedissonConfig;
import org.redisson.api.RKeys;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
 * @Author chenyunzhi
 * @DATE 2024/9/3 10:01
 * @Description:
 */
public class demo1 {
    public static void main(String[] args) throws InterruptedException {
        RedissonConfig redissonConfig = new RedissonConfig();
        RedissonClient redissonClient = redissonConfig.redissonClient();
        int i = 0;
        Thread.sleep(2000);
        while (i < 5) {
            try {
                Date currentDate = new Date();
                System.out.println("当前时间: " + currentDate);
                RLock testLock = redissonClient.getLock("testLock");
                //尝试获取锁   waitTime(重试等待时间),leaseTime(过期时间),TimeUnit(时间单位)
                boolean b = testLock.tryLock(1, 5, TimeUnit.SECONDS);
                i++;
                if (b) {
                    try {
                        Thread.sleep(2000);
                        System.out.println("执行业务" +  i + "次 节点1");
                    } finally {
                        testLock.unlock();
                    }
                } else {
                    System.out.println("获取锁失败  节点1");
                }
            } catch (Exception e) {
                System.out.println("锁中断 节点1" + e.getMessage());
            }
        }
    }
}

节点1完成业务的速度大约2秒钟,循环执行5次任务,如果获取锁失败就不执行,进入下一次执行

节点2

package org.example.demo;
import org.example.tool.RedissonConfig;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
 * @Author chenyunzhi
 * @DATE 2024/9/3 10:01
 * @Description:
 */
public class demo2 {
    public static void main(String[] args) throws InterruptedException {
        RedissonConfig redissonConfig = new RedissonConfig();
        RedissonClient redissonClient = redissonConfig.redissonClient();
        int i = 0;
        while (i < 5) {
            try {
                Date currentDate = new Date();
                System.out.println("当前时间: " + currentDate);
                RLock testLock = redissonClient.getLock("testLock");
                //尝试获取锁   waitTime(重试等待时间),leaseTime(过期时间),TimeUnit(时间单位)
                boolean b = testLock.tryLock(1, 10, TimeUnit.SECONDS);
                i++;
                if (b) {
                    try {
                        Thread.sleep(1000);
                        System.out.println("执行业务" +  i + "次 节点2");
                    } finally {
                        testLock.unlock();
                    }
                } else {
                    System.out.println("获取锁失败  节点2");
                }
            } catch (Exception e) {
                System.out.println("锁中断 节点2" + e.getMessage());
            }
        }
    }
}

节点2完成业务的速度大约1秒钟,循环执行5次任务,如果获取锁失败就不执行,进入下一次执行

然后我们同时允许两个节点行测试

image-20240921112219730

image-20240921112248761

通过上面测试可以发现,在节点1执行业务的时候,节点2获取锁失败了,然后无法执行业务,反之也是如此

2.2 看门狗案例

上面的案例我们为了防止任务死锁,都会给锁都设定了有效时间,可是我们不确定这个任务要执行多久,就会导致任务还没执行完成,锁就先过期了。watchDog(看门狗)的作用是可以确保等待某个节点任务完全执行完成后才去释放锁。

redisson的看门狗底层使用的是setnx加lua脚本实现的,会定期给锁续约,默认是每隔10s续期一次,一次续约30s,其他线程在最大等待时间内自旋,不断尝试获取锁,超过最大等待时间则获取锁失败,设置默认加锁时间的参数是 lockWatchdogTimeout,会和主线程一起销毁。。

注意

  1. 看门狗只会在锁没设定过期时间的时候才有效
  2. 如果任务一直阻塞,那么锁就会一直续期,得不到释放

image-20240921155226569

package org.example.demo;

import org.example.tool.RedissonConfig;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;

import java.util.concurrent.TimeUnit;

/**
 * @Author chenyunzhi
 * @DATE 2024/9/21 11:26
 * @Description:
 */
public class demo3 {
    public static void main(String[] args) {
        RedissonConfig redissonConfig = new RedissonConfig();
        RedissonClient redissonClient = redissonConfig.redissonClient();
        RLock myLock = redissonClient.getLock("myLock");
        if (myLock.tryLock()) {
            try {
                // 模拟任务执行
                System.out.println("执行任务");
                Thread.sleep(50000); // 模拟50秒的任务
                System.out.println("任务完成");

            } catch (InterruptedException e) {
                e.printStackTrace();
            } finally {
                //判断当前线程是否持有锁  isHeldByCurrentThread
                if (myLock.isHeldByCurrentThread()) {
                    myLock.unlock();
                    System.out.println("释放锁");
                }
            }
        }
        redissonClient.shutdown();
    }
}

使用myLock.tryLock()不设置过期时间,那么看门狗会默认启动,然后会默认设置30秒的过期时间,每10秒刷新一次过期时间。

2.3 参考文章

github: https://github.com/redisson/redisson/wiki/8.-distributed-locks-and-synchronizers

redisson中的看门狗机制总结

Redis的分布式锁

redisson watchdog 使用和原理

作者:神的孩子都在歌唱

本人博客:https://blog.csdn.net/weixin_46654114

转载说明:务必注明来源,附带本人博客连接。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

maven报错:Unresolved plugin ‘org.apache.maven.pluginsmaven-resources-plugin‘

maven报错&#xff1a;Unresolved plugin: ‘org.apache.maven.plugins:maven-resources-plugin‘ 最近初学java&#xff0c;这里记录一下报错出现的原因以及解决办法 问题示例 如图所示&#xff0c;就是在创建一个项目之后对应插件的部分有爆红 问题出现的原因 简单来说就…

Pygame中Sprite实现逃亡游戏3

在《Pygame中Sprite实现逃亡游戏2》中实现了飞龙和飞火的显示。接下来实现玩家跳跃效果&#xff0c;如图1所示。 图1 玩家跳跃效果 1 按键响应 当玩家按下键盘中空格按键后&#xff0c;游戏中的玩家就会跳跃&#xff0c;用于躲避飞火。在while True循环判断按键的代码中&…

开放原子开源基金会网站上的开源项目EasyBaaS存在内存泄露缺陷

今天我仍然发布一个开放原子开源基金会网站上的开源项目EasyBaaS&#xff0c;这个开源项目的捐赠主体是招商银行股份有限公司。该项目的是一个基于Linux环境的区块链节点管理工具&#xff0c;提供一键部署节点、实时监控及管理运维等功能&#xff0c;从搭建节点、启停节点、节点…

Python | Leetcode Python题解之第436题寻找右区间

题目&#xff1a; 题解&#xff1a; class Solution:def findRightInterval(self, intervals: List[List[int]]) -> List[int]:n len(intervals)starts, ends list(zip(*intervals))starts sorted(zip(starts, range(n)))ends sorted(zip(ends, range(n)))ans, j [-1]…

Qt网络编程——QTcpServer和QTcpSocket

文章目录 核心APITCP回显服务器TCP回显客户端 核心API QTcpServer用于监听端口和获取客户端连接 名称类型说明对标原生APIlisten(const QHostAddress&, quint16 port)方法绑定指定的地址和端口号&#xff0c;并开始监听bind和listennextPendingConnection()方法从系统中获…

【2024/9/25更新】最新版植物大战僵尸V2.5.1发布啦

下载链接⬇️⬇️ 最新版V2.5.1下载 点击下载 历史版本下载 点击下载 更新公告 2.5.1版本更新公告: 关卡阅整 两面夹击关卡系列关卡降低出怪倍率 两面夹击关卡出怪种类调整 两面夹击部分关卡初始阳光调整 两面夹击关卡中可使用投手类植物- 两面夹击关卡中的脑子血量…

远程升级频频失败?原因竟然是…

最近有客户反馈在乡村里频繁出现掉线的情况。 赶紧排查原因&#xff01; 通过换货、换SIM卡对比排查测试&#xff0c;发现只有去年采购的那批模块在客户环境附近会出现掉线的情况&#xff0c;而今年采购的模块批次就不会掉线。。。 继续追究原因&#xff0c;联系对应的销售工…

基于springboot vue 大学生竞赛管理系统设计与实现

博主介绍&#xff1a;专注于Java vue .net php phython 小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不然下次找不到哟 我的博客空间发布了1000毕设题目 方便大家学习使用 感兴趣的…

路径报错问题

项目场景&#xff1a; 假设这是我的项目结构&#xff0c;我现在需要在aa.js文件中引入并使用aa.geojson文件&#xff0c; 问题&#xff1a; 当我引入路径是const filePath ../geo/aa.geojson&#xff1b;的时候&#xff0c;系统报错 "aa.geojson is not Found",找不…

【WRF数据介绍第二期】气象驱动场数据介绍及下载

WRF数据介绍第二期&#xff1a;气象驱动场数据介绍及下载 WRF官网-Free Data数据下载 EAR5数据数据下载 参考 WRF运行流程如下&#xff0c;所需的外部数据源包括静态地理数据&#xff08;Static Geography Data&#xff09;和网格气象数据&#xff08;Gridded Meteorological D…

基于AI网关的智慧煤矿安全监测应用

煤矿安全一直是矿业管理的重中之重。由于煤矿环境的恶劣与复杂性&#xff0c;例如工作中间环节多、设施设备多样且集中、空间狭小、环境闭塞、有害气体隐患、粉尘聚集等&#xff0c;针对煤矿的安全监测和防范时常面临着极大的挑战。 随着AI技术的发展与普及&#xff0c;依托AI实…

关于前端框架的对比和选择

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///C爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于【前端框架的对比和选择】相关内容&…

力扣 中等 275.H指数

文章目录 题目介绍题解 题目介绍 题解 h指数不一定都满足citations[mid] n - mid&#xff0c;例如[0,1,4,5,6]的h指数是3。 题目说了用对数时间复杂度来实现&#xff0c;说明一定是用二分法&#xff0c;草纸上推导一下即可得出以下代码。 class Solution {public int hInde…

MySQL自动测试框架Test Framework工具实践

导读 之前的文章&#xff08;《MySQL自动测试框架Test Framework浅析》&#xff09;从源码级别对MySQL自动测试框架Test Framework进行了简要分析&#xff0c;本文接下来从实践的角度介绍Test Framework工具的使用方法。 1 简介 Test Framework主要应用于MySQL等相关数据库项…

Docker 容器技术:颠覆传统,重塑软件世界的新势力

一、Docker简介 什么是docker Docker 是一种开源的容器化平台&#xff0c;它可以让开发者将应用程序及其所有的依赖项打包成一个标准化的容器&#xff0c;从而实现快速部署、可移植性和一致性。 从功能角度来看&#xff0c;Docker 主要有以下几个重要特点&#xff1a; 轻量…

用Python实现运筹学——Day 3: 线性规划模型构建

一、学习内容 线性规划模型构建的步骤与技巧 线性规划&#xff08;Linear Programming, LP&#xff09;模型构建是运筹学中的核心内容&#xff0c;通常用于求解资源的最优分配问题。要从实际问题中提取出一个线性规划模型&#xff0c;需要按照以下步骤进行&#xff1a; 问题描…

JavaWeb——Vue组件库Element(1/6):快速入门(什么是Element,安装,引入ElementUI组件库,复制组件代码,启动项目 )

目录 什么是Element 快速入门 安装 引入ElementUI组件库 访问官网&#xff0c;复制组件代码 启动项目 小结 了解完前端的工程化之后&#xff0c;接下来了解一门新的前端技术&#xff1a;Vue 的组件库 Element。 学习完 Element 之后&#xff0c;即使作为一名 Java 后…

VMware 如何上网

需求 在PC window中下载了VMware&#xff0c;并且加载的是Ubuntu系统。PC电脑连接的是手机热点。 可以看出WLAN连接的名称是&#xff1a;Wi-Fi 6 AX201 16MHz 如何让Ubuntu系统也能够上网。并且更新库&#xff0c;能够sudo apt-get install xxx相关库。 目前虚拟机中的Ubun…

PMP--二模--解题--121-130

文章目录 9.资源管理&#xff01;团建不是万能的121、 [单选] 项目团队中一些经验丰富的成员抱怨项目经理。这些高级项目团队成员觉得项目经理在事无巨细地管理他们&#xff0c;阻碍他们完成工作。当项目经理意识到这些问题时&#xff0c;应该怎么做&#xff1f; 14.敏捷--组织…

深度学习之开发环境(CUDA、Conda、Pytorch)准备(4)

目录 1.CUDA 介绍 1.1 CUDA 的基本概念 1.2 CUDA 的工作原理 1.3 CUDA 的应用领域 2. 安装CUDA 2.1 查看GPU版本 2.2 升级驱动&#xff08;可选&#xff09; 2.3 查看CUDA版本驱动对应的支持的CUDA ToolKit工具包 2.4 下载Toolkit 2.5 安装&#xff08;省略&#xff0…