分布式锁的作用及实现(Redis)

分布式锁:场景和使用方法(通俗讲解) 对于锁大家肯定不会陌生,比如 synchronized 关键字 和 ReentrantLock 可重入锁,一般我们用其在多线程环境中控制对资源的并发访问。但是随着业务的发展,分布式的概念逐渐出现在我们系统中,我们在开发的过程中经常需要进行多个系统之间的交互,于是上面的加锁方法就会失去作用。于是在分布式锁就自然而然的诞生了,接下来我们来聊一聊分布式锁实现的几种方式。 阅读详情

一、什么是分布式锁?

要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。

线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。

进程锁:为了控制同一操作系统中多个进程访问某个共享资源,因为进程具有独立性,各个进程无法访问其他进程的资源,因此无法通过synchronized等线程锁实现进程锁。

分布式锁:当多个进程不在同一个系统中,用分布式锁控制多个进程对资源的访问。

二、分布式锁的使用场景。

线程间并发问题和进程间并发问题都是可以通过分布式锁解决的,但是强烈不建议这样做!因为采用分布式锁解决这些小问题是非常消耗资源的!分布式锁应该用来解决分布式情况下的多进程并发问题才是最合适的。

有这样一个情境,线程A和线程B都共享某个变量X。

如果是单机情况下(单JVM),线程之间共享内存,只要使用线程锁就可以解决并发问题。

如果是分布式情况下(多JVM),线程A和线程B很可能不是在同一JVM中,这样线程锁就无法起到作用了,这时候就要用到分布式锁来解决。

三、分布式锁的实现(Redis)

分布式锁实现的关键是在分布式的应用服务器外,搭建一个存储服务器,存储锁信息,这时候我们很容易就想到了Redis。首先我们要搭建一个Redis服务器,用Redis服务器来存储锁信息。

在实现的时候要注意的几个关键点:

1、锁信息必须是会过期超时的,不能让一个线程长期占有一个锁而导致死锁;

2、同一时刻只能有一个线程获取到锁。

几个要用到的redis命令:

setnx(key, value):“set if not exits”,若该key-value不存在,则成功加入缓存并且返回1,否则返回0。

get(key):获得key对应的value值,若不存在则返回nil。

getset(key, value):先获取key对应的value值,若不存在则返回nil,然后将旧的value更新为新的value。

expire(key, seconds):设置key-value的有效期为seconds秒。

看一下流程图:


在这个流程下,不会导致死锁。

我采用Jedis作为Redis客户端的api,下面来看一下具体实现的代码。

(1)首先要创建一个Redis连接池。

public class RedisPool {

    private static JedisPool pool;//jedis连接池

    private static int maxTotal = 20;//最大连接数

    private static int maxIdle = 10;//最大空闲连接数

    private static int minIdle = 5;//最小空闲连接数

    private static boolean testOnBorrow = true;//在取连接时测试连接的可用性

    private static boolean testOnReturn = false;//再还连接时不测试连接的可用性

    static {
        initPool();//初始化连接池
    }

    public static Jedis getJedis(){
        return pool.getResource();
    }

    public static void close(Jedis jedis){
        jedis.close();
    }

    private static void initPool(){
        JedisPoolConfig config = new JedisPoolConfig();
        config.setMaxTotal(maxTotal);
        config.setMaxIdle(maxIdle);
        config.setMinIdle(minIdle);
        config.setTestOnBorrow(testOnBorrow);
        config.setTestOnReturn(testOnReturn);
        config.setBlockWhenExhausted(true);
        pool = new JedisPool(config, "127.0.0.1", 6379, 5000, "liqiyao");
    }
}

(2)对Jedis的api进行封装,封装一些实现分布式锁需要用到的操作。

public class RedisPoolUtil {

    private RedisPoolUtil(){}

    private static RedisPool redisPool;

    public static String get(String key){
        Jedis jedis = null;
        String result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.get(key);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static Long setnx(String key, String value){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.setnx(key, value);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static String getSet(String key, String value){
        Jedis jedis = null;
        String result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.getSet(key, value);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static Long expire(String key, int seconds){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.expire(key, seconds);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }

    public static Long del(String key){
        Jedis jedis = null;
        Long result = null;
        try {
            jedis = RedisPool.getJedis();
            result = jedis.del(key);
        } catch (Exception e){
            e.printStackTrace();
        } finally {
            if (jedis != null) {
                jedis.close();
            }
            return result;
        }
    }
}

(3)分布式锁工具类

public class DistributedLockUtil {

    private DistributedLockUtil(){
    }

    public static boolean lock(String lockName){//lockName可以为共享变量名,也可以为方法名,主要是用于模拟锁信息
        System.out.println(Thread.currentThread() + "开始尝试加锁!");
        Long result = RedisPoolUtil.setnx(lockName, String.valueOf(System.currentTimeMillis() + 5000));
        if (result != null && result.intValue() == 1){
            System.out.println(Thread.currentThread() + "加锁成功!");
            RedisPoolUtil.expire(lockName, 5);
            System.out.println(Thread.currentThread() + "执行业务逻辑!");
            RedisPoolUtil.del(lockName);
            return true;
        } else {
            String lockValueA = RedisPoolUtil.get(lockName);
            if (lockValueA != null && Long.parseLong(lockValueA) >= System.currentTimeMillis()){
                String lockValueB = RedisPoolUtil.getSet(lockName, String.valueOf(System.currentTimeMillis() + 5000));
                if (lockValueB == null || lockValueB.equals(lockValueA)){
                    System.out.println(Thread.currentThread() + "加锁成功!");
                    RedisPoolUtil.expire(lockName, 5);
                    System.out.println(Thread.currentThread() + "执行业务逻辑!");
                    RedisPoolUtil.del(lockName);
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
    }
}

深入理解Redis分布式锁 背景 项目中有个场景是做数据分析,然后将目标数据保存在db,有个要求是将同类型的目标数据值保存一次,因此每次保存时需要判断之前是否已经存在了,由于qps较高,之前使用redis来缓存已经保存的数据,来抵挡对db的大部分流量,最近业务拓展同类型目标数据的qps可能超大(极限时达到20Wqps以上),此时由于在分布式场景下redis查询未加锁,可能多个线程同时查询redis得到的结果为并未保存,此时问题发生了,可能同时有多个线程执行保存到db操作,虽然db做了unique Key的限制,但担心到db qps过高 阅读详情

相关推荐

Redis实现分布式锁的核心原理以及利弊

文章目录INFO一、关键点1、原子性2、过期时间3、锁续期4、释放锁二、Redis实现分布式锁的几种方式1、单机2、哨兵3、集群4、红锁三、Redis实现分布式锁的利弊1、优点2、缺点四、总结 INFO 作者: 编程界的小学生 日期: 2021/09/06 修订: 初版,未修订。2021/09/06 版权: 内部资料,切勿泄漏,违者必究。 一、关键点 原子性 过期时间 释放锁 锁续期 1、原子性 比如如下就不具有原子性,就是错误的代码: boolean lockStatus = stringRedisT

【原】编程界的小学生 1717

看完这篇分布式锁,再也不迷惑了

分布式锁介绍

weixin_46906359的博客 1372

使用PackStack工具自动化部署OpenStack

搭建 OpenStack 环境,每个组件的安装和配置都需要熟悉其特定的依赖关系、参数设置等,对于初学者来说容易出错。PackStack 工具通过集成一系列脚本和配置文件,便于快速搭建OpenStack练习环境。CPU:支持 Intel VT - x 或 AMD - V 硬件虚拟化技术,并且要在 BIOS 里开启此功能。内存:16GB以上存储:200GB以上可用空间(2)VMware WorkStation16.0以上版本(3)远程连接工具(如Xshell、MobaXterm)

2301_80440447的博客 4093

什么是分布式锁,分布式锁有什么作用?

为了防止分布式系统中的多个进程之间相互干扰,我们需要一种分布式协调技术来对这些进程进行调度。而这个分布式协调技术的核心就是来实现这个分布式锁。

记得微笑的博客 5926

网络设备心跳线带宽高导致虚拟化平台不稳定的问题处理

本文记录了网络设备心跳线带宽高导致虚拟化平台不稳定的问题处理一例。

forestqq的博客 2226

一个固定翼飞机仿真程序带你系统性上手如何实现配平(工具箱+脚本)

老规矩,该博客所用的模型和脚本已上传至百度网盘,名字为“固定翼配平训练例子”,自己自取。

zouxu634866的博客 2566

Redis 分布式锁深度解析:setnx 命令的核心作用与实现

Redis 分布式锁的核心是通过SET NX PX命令实现原子性的 "抢锁",并通过 Lua 脚本保证释放锁的安全性。SETNX(或SET NX)是实现锁的基础,解决了并发抢锁的原子性问题必须给锁设置过期时间,避免死锁释放锁时需通过唯一标识 + Lua 脚本,防止误删其他客户端的锁实际应用中需考虑超时、可重入性、集群一致性等进阶问题掌握这些原理后,再去阅读 Redisson 等框架的源码,就能更清晰地理解其设计思路。

java_beautiful的博客 1104

从零开始:使用Verilog在FPGA上实现8051微控制器的完整指南

8051微控制器是一种8位微控制器,由Intel在1980年代初推出。它包括一个CPU、一些RAM和ROM、I/O端口、定时器和串行通信接口。由于其简单的架构和强大的功能,8051已经成为了嵌入式系统设计的首选。FPGA是一种集成电路,设计师可以按照自己的需求进行编程。与传统的ASIC(应用特定集成电路)相比,FPGA提供了更高的灵活性,允许在硬件级别进行快速原型设计和迭代。这里,我们定义了一些基本的输入/输出端口,如时钟clk、复位reset、数据输入/输出和地址输入/输出。

qq_38334677的博客 1330

Redis中的SETNX命令有什么作用?如何使用它来实现分布式锁?

但是,为了确保安全地释放锁,通常会检查锁是否是由当前客户端设置的,只有当确认无误时才删除键。请注意,即使使用了这些技术,分布式锁仍然可能遇到一些边缘情况,比如时钟漂移、网络延迟等,所以在实际应用中可能还需要考虑更多的细节来确保系统的可靠性。分布式锁的作用是在多个客户端之间同步对共享资源的访问,确保同一时间只有一个客户端可以修改该资源。如果持有锁的客户端崩溃或忘记释放锁,那么其他客户端可以在锁超时后重新获取锁。尝试设置一个唯一的锁标识(例如,一个随机生成的 UUID 或者客户端 ID)。

qq_33240556的博客 1368

【Matlab】从零开始掌握 MATLAB 安装激活:从环境搭建到问题解决全指南

打开 MATLAB,点击 “主页 - 设置路径”;点击 “添加文件夹”,选择自定义的工作文件夹,点击 “保存”,重启 MATLAB 生效。MATLAB R2024a 的安装与激活是开启 MATLAB 学习的第一步,也是构建稳定学习环境的基础。本文从安装前准备、分步操作、验证测试、问题解决到环境优化,完整覆盖了新手所需的所有知识点 —— 核心要点在于:确认系统兼容、使用合法授权、选择纯英文安装路径、完成功能验证。

unber的博客 595

cesium单向流动线效果

在学材质的路上一去不复返了属实是,难也难在这。还请各位大佬多多指教~

就zhei? 687

redis分布式锁的作用及实现

一、什么是分布式锁?要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synchronized是共享对象头,显示锁Lock是共享某个变量(state)。进程锁:为了控制同一操作系统中多个进程访问某...

ntotl的博客 6292

串口通信的性能瓶颈分析:如何提高数据吞吐量和降低延迟

摘要: 串口通信在高频或大数据场景下存在吞吐量不足、延迟高、丢帧等问题,主要瓶颈包括波特率限制、缓冲区不足、CPU轮询延迟等。优化策略包括:提升波特率至硬件上限、增大缓冲区、采用异步I/O(如ReadAsync)减少线程切换,使用二进制协议降低解析开销。实时性方面需启用硬件流控、批量发送数据,并优化线程优先级。跨平台适配需区分Windows/Linux的缓冲区设置与异步机制。性能测试可通过吞吐量、延迟及回环测试验证优化效果,核心原则是硬件匹配、异步处理、协议优化与跨平台适配。(150字)

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 979

分布式锁的作用及实现(Redis,RedisReentrantLock)

https://blog.youkuaiyun.com/l_bestcoder/article/details/79336986一、什么是分布式锁?要介绍分布式锁,首先要提到与分布式锁相对应的是线程锁、进程锁。线程锁:主要用来给方法、代码块加锁。当某个方法或代码使用锁,在同一时刻仅有一个线程执行该方法或该代码段。线程锁只在同一JVM中有效果,因为线程锁的实现在根本上是依靠线程之间共享内存实现的,比如synch...

$firecat利白的代码足迹$ 4481

在群辉(NAS)中安装虚拟机套件(Virtual Machine Manager)

一、在群辉中下载虚拟机套件Virtual Machine Manager ①启用Open vSwitch(网络-->管理--启用Open vSwitch) ②打开“套件中心” ③查找到Virtual Machine Manager套件点击“安装套件” 二、安装虚拟机套件(Virtual Machine Manager) ①打开虚拟机套件运行设置向导 ②选择存储空间...

提供C#相关开发 、云计算、运维测试、网络安全相关技术分享与服务,有意向可联系。 2万+

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

【Big Data 每日一题20181109】分布式锁的作用及实现(Redis)

前言 分布式锁一般有三种实现方式:1. 数据库乐观锁;2. 基于Redis的分布式锁;3. 基于ZooKeeper的分布式锁。本篇博客将介绍第二种方式,基于Redis实现分布式锁。虽然网上已经有各种介绍Redis分布式锁实现的博客,然而他们的实现却有着各种各样的问题,为了避免误人子弟,本篇博客将详细介绍如何正确地实现Redis分布式锁。 可靠性 首先,为了确保分布式锁可用,我们至少要确保锁的...

tianyeshiye 190

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

redis实现分布式锁

通过流程图也可以看到,若要使用redis实现分布式锁,会存在一些性能问题,因为在等待锁的过程中会一直自旋,周而复始的去判断是否有锁资源,如果要用高性能的分布式锁,还是需要用zookeeper,因为zookeeper天生就是用来做分布式锁的;

叶新东老师的博客 843

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

VB摄像头监控

该VB模块可对摄像头捕获的画面进行录像等,可在创建的窗口进行控制

六.Redis极简入门-Redis实现分布式锁原理

老鸟飞过,学习使用,欢迎交流 理解分布式锁 为什么要分布式锁 在并发场景中,我们可以使用加锁的手段来保证业务方法或代码的原子性操作,从而防止数据被并发修改引发安全问题,在单体应用中我们可以使用互斥锁如: synchronized 同步代码块 或者 Lock锁来实现,如图: 但是在集群/分布式应用中单纯的互斥锁是不能保证多个节点中对同一个数据的原性操作的,如图: 集群模式中,每个服务都加了锁但是只能锁住自己,每个服务做库存做扣减操作,当库存都剩1的时候,三个服务并发减库存可能会导致库存减到 -2 出现线程

墨家巨子@俏如来 1万+

Redis-实现分布式锁

如实使用Redis实现分布式锁

qq_36481984的博客 1012

分布式锁:Zookeeper 和 Redis 实现方案对比分析

在分布式系统开发中,分布式锁是一个至关重要的概念,也是经常被讨论的技术点。尤其是在处理多个进程或线程同时访问共享资源的场景时,选择合适的分布式锁实现方案显得尤为关键。今天我们就来深入探讨一下实现分布式锁的两种常见方案:Zookeeper 和 Redis,并分析它们各自的优缺点。

m0_57836225的博客 1466

在 Go 语言中使用 Redis 实现分布式锁

定义一个分布式锁结构体,包含 Redis 客户端、锁的键名、过期时间等字段。import ("time"key string在 Go 语言中,可以使用 Redis 的 SETNX 命令和 EXPIRE 命令来实现分布式锁。通过定义分布式锁结构体,并实现获取锁和释放锁的方法,可以方便地在分布式系统中使用分布式锁。在使用分布式锁时,需要注意锁的过期时间、错误处理和分布式环境下的时钟同步等问题。

m0_57836225的博客 1050

Redis分布式锁

分布式锁是一种在分布式系统中用于确保多个节点或进程在任何给定时间点,只有一个能够执行特定资源或任务的同步机制。在分布式系统中,不同的节点可能需要访问共享资源,为了防止多个节点同时修改资源造成数据不一致或冲突,就需要使用分布式锁来保证在任一时刻,只有一个节点可以访问该资源。简单来说就是满足分布式系统或者集群模式下多进程可见并互斥的锁分布式锁的特性:互斥性:在任意时刻,只有一个进程可以持有锁。安全性:持有锁的进程能够保证在它释放锁之前,其他进程不能获取同一把锁高性能。

m0_73598900的博客 843
上一篇: 最容易理解的Consistent Hashing讲解(一致性哈希算法使用场景及原理)
下一篇: 设计模式集锦
LiQiyaoo
博客等级 码龄11年 337粉丝 206原创
评论 50
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值