深度解析分布式锁及实现方案

在这里插入图片描述

😄 19年之后由于某些原因断更了三年,23年重新扬帆起航,推出更多优质博文,希望大家多多支持~
🌷 古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
🎐 个人CSND主页——Micro麦可乐的博客
🐥《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
🌺《RabbitMQ》本专栏主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
🌸《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~

深度解析分布式锁及实现方案

  • 引言
  • 什么是分布式锁?
  • 分布式锁的应用场景
  • 分布式锁的设计原则
  • 分布式锁的实现方案
      • 基于数据库的实现
      • 基于缓存的实现
      • 基于ZooKeeper的实现
  • 分布式锁的注意事项
  • 结语

引言

在分布式系统中,分布式锁是协调多个节点对共享资源进行互斥访问的关键技术。本文将深入研究分布式锁的概念、应用场景,并详细介绍三种常见的实现方案,包括基于数据库、基于缓存(以Redis为例)和基于ZooKeeper的实现。

什么是分布式锁?

分布式锁是一种在分布式系统中实现协同访问共享资源的机制,目的是确保在分布式环境中对共享资源的互斥访问,避免数据不一致性、并发冲突等问题。

分布式锁的应用场景

  • 避免重复任务: 确保在分布式系统中某个任务只被执行一次,防止重复执行。

  • 资源竞争控制: 协调多个节点对共享资源的访问,保证资源访问的互斥性。

  • 分布式事务: 在分布式事务中,用于协调多个参与者对资源的访问,确保事务的一致性。

分布式锁的设计原则

Redis的官网在新窗口打开上对使用分布式锁提出至少需要满足如下三个要求:

  • 互斥(属于安全性):在任何给定时刻,只有一个客户端可以持有锁。
  • 无死锁(属于有效性):即使锁定资源的客户端崩溃或被分区,也总是可以获得锁;通常通过超时机制实现。
  • 容错性(属于有效性):只要大多数 Redis 节点都启动,客户端就可以获取和释放锁。

除此之外,分布式锁的设计中还可以/需要考虑:

加锁解锁的同源性:A加的锁,不能被B解锁
获取锁是非阻塞的:如果获取不到锁,不能无限期等待;
高性能:加锁解锁是高性能的

分布式锁的实现方案

下面介绍几种我们日常工作中常见的分布式锁的实现方案

1、基于数据库实现分布式锁

  • 基于数据库表(锁表,很少使用)
  • 乐观锁(基于版本号)
  • 悲观锁(基于排它锁)

2、基于 redis 实现分布式锁

  • 单个Redis实例:setnx(key,当前时间+过期时间) + Lua
  • Redis集群模式:Redlock

3、基于 zookeeper实现分布式锁

  • 临时有序节点来实现的分布式锁,Curator

基于数据库的实现

通过数据库的事务特性来实现分布式锁,使用数据库行级锁或唯一索引。

详细代码示例(使用PostgreSQL):

// 加锁
public boolean tryLock(String lockKey, String clientId, int expireTime) {
    try (Connection connection = dataSource.getConnection()) {
        connection.setAutoCommit(false);
        try (PreparedStatement preparedStatement = connection.prepareStatement(
                "INSERT INTO distributed_lock (lock_key, client_id, expire_time) VALUES (?, ?, ?) ON CONFLICT (lock_key) DO NOTHING")) {
            preparedStatement.setString(1, lockKey);
            preparedStatement.setString(2, clientId);
            preparedStatement.setTimestamp(3, new Timestamp(System.currentTimeMillis() + expireTime));
            int affectedRows = preparedStatement.executeUpdate();
            if (affectedRows > 0) {
                connection.commit();
                return true;
            } else {
                connection.rollback();
                return false;
            }
        }
    } catch (SQLException e) {
        // 处理异常
        return false;
    }
}

// 解锁
public void unlock(String lockKey, String clientId) {
    try (Connection connection = dataSource.getConnection()) {
        try (PreparedStatement preparedStatement = connection.prepareStatement(
                "DELETE FROM distributed_lock WHERE lock_key = ? AND client_id = ?")) {
            preparedStatement.setString(1, lockKey);
            preparedStatement.setString(2, clientId);
            preparedStatement.executeUpdate();
        }
    } catch (SQLException e) {
        // 处理异常
    }
}

基于缓存的实现

利用分布式缓存系统(以Redis为例),通过其原子性操作来实现分布式锁。

详细代码示例(使用Redis):

// 加锁
public boolean tryLock(String lockKey, String clientId, int expireTime) {
    try (Jedis jedis = jedisPool.getResource()) {
        String result = jedis.set(lockKey, clientId, "NX", "PX", expireTime);
        return "OK".equals(result);
    }
}

// 解锁
public void unlock(String lockKey, String clientId) {
    try (Jedis jedis = jedisPool.getResource()) {
        jedis.del(lockKey);
    }
}

基于ZooKeeper的实现

利用ZooKeeper的临时有序节点特性,实现分布式锁。

public boolean tryLock(String lockKey, String clientId, int expireTime) {
    try {
        String lockPath = zooKeeper.create(lockKey + "/", clientId.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL);
        List<String> children = zooKeeper.getChildren(lockKey, false);
        Collections.sort(children);
        if (clientId.equals(children.get(0))) {
            return true;
        } else {
            zooKeeper.delete(lockPath, -1);
            return false;
        }
    } catch (Exception e) {
        // 处理异常
        return false;
    }
}

public void unlock(String lockKey, String clientId) {
    try {
        List<String> children = zooKeeper.getChildren(lockKey, false);
        for (String child : children) {
            if (child.startsWith(clientId)) {
                zooKeeper.delete(lockKey + "/" + child, -1);
            }
        }
    } catch (Exception e) {
        // 处理异常
    }
}

分布式锁的注意事项

死锁和宕机

考虑在获取锁的过程中可能发生的节点宕机和死锁情况,确保系统的可用性。

锁的释放

确保锁在适当的时候被释放,防止出现死锁或者长时间占用锁的情况。

锁粒度

合理选择锁的粒度,过大的粒度可能导致性能问题,而过小的粒度可能导致锁争用。

结语

分布式锁是分布式系统中常用的同步机制,通过对共享资源的互斥访问,确保系统的一致性。在选择实现方案时,需要根据实际场景和系统要求综合考虑,保证分布式锁的性能、可靠性和可维护性。在实际应用中,可以根据业务需求选择适当的实现方案。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

赠送葡萄酒:为别人选择合适的葡萄酒

葡萄酒可以在许多不同的场合成为很好的礼物&#xff0c;因为它可以用来庆祝许多不同的事情。当被邀请去别人家时&#xff0c;你可以带酒去吃饭。葡萄酒可以用来纪念婚礼、出生、毕业和各种纪念日&#xff0c;来自云仓酒庄品牌雷盛红酒分享这是一个非常合适的专业礼物。但是你怎…

LeetCode 2125. 银行中的激光束数量【数组,遍历】1280

本文属于「征服LeetCode」系列文章之一&#xff0c;这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁&#xff0c;本系列将至少持续到刷完所有无锁题之日为止&#xff1b;由于LeetCode还在不断地创建新题&#xff0c;本系列的终止日期可能是永远。在这一系列刷题文章…

基于共享储能电站的工业用户日前优化经济调度【复现】

文章提出一种基于共享储能电站的工业用户日前优化经济调度方法。首先提出共享储能电站的概念&#xff0c;分析其 商业运营模式。然后将共享储能电站应用到工业用户经济优化调度中&#xff0c;通过协调各用户使用共享储能电站进行充电和 放电的功率&#xff0c;实现用户群日运行…

数据湖存储解决方案之Iceberg

1.Iceberg是什么&#xff1f; Apache Iceberg 是由 Netflix 开发开源的&#xff0c;其于2018年11月16日进入 Apache 孵化器&#xff0c;是 Netflix 公司数据仓库基础。Apache Iceberg设计初衷是为了解决Hive离线数仓计算慢的问题&#xff0c;经过多年迭代已经发展成为构建数据…

【NextChat】手把手教您如何在群晖上部署chatgpt-next-web

文章目录 📖 介绍 📖🏡 环境 🏡📒 配置方法 📒📝 群晖部署📝 Vercel/Dokcer/其他环境部署⚓️ 相关链接 ⚓️📖 介绍 📖 chatgpt-next-web项目又叫NextChat,是一个支持一键免费部署你的私人GPT 的网页应用,支持 GPT3、 GPT4 & Gemini Pro 等模型,本…

STM32——高级定时器输出指定个数PWM波原理及实战

1.高级定时器简介&#xff08;TIM8、TIM1&#xff09; 相比于通用定时器特性&#xff1a; 1&#xff09;重复计数器 2&#xff09;死区时间带可编程的互补输出 3&#xff09;断路输入&#xff0c;用于将定时器的输出信号置于用户可选的安全配置中 2.高级定时器框图 3.重复计数…

SSM(spring+springmvc+mybatis)整合

spring与SpringMvc的常用注解 一、spring常用注解&#xff1a; Component&#xff1a;实现bean的注入&#xff08;不过获取bean需要用bean的类型来获取&#xff08;即class文件&#xff09;&#xff09; controller、Service、Repository的作用等同于Component注解的作用&…

TS中的类

目录 ES6的类 类的概念 类的构成 类的创建 声明 构造函数 定义内容 创建实例 TS中的类 类声明 构造函数 属性和方法 实例化类 继承 访问修饰符 public private protected 成员访问修饰符的使用原则 访问器 只读成员与静态成员 readonly static 修饰符总…

remote-ssh如何离线下载历史版本

remote-ssh离线下载任意历史版本方法&#xff0c;简单有效 很多小伙伴都会遇到这样的问题&#xff0c;由于内网服务器中安装的vs code版本较低&#xff0c;比如1.62.0版本&#xff0c;官网发布的version history 只展示最新的五个版本&#xff0c;还是太高了&#xff0c;导致下…

TypeScript 和 jsdom 库创建爬虫程序示例

TypeScript 简介 TypeScript 是一种由微软开发的自由和开源的编程语言。它是 JavaScript 的一个超集&#xff0c;可以编译生成纯 JavaScript 代码。TypeScript 增加了可选的静态类型和针对对象的编程功能&#xff0c;使得开发更加大规模的应用容易。 jsdom 简介 jsdom 是一个…

VS中打开ui文件闪退

解决办法&#xff1a; 依次点击《扩展》-> 《Qt vs tools》-> 《options》-> 《Qt》-> 《general》 -> 《Qt Designer》 -> 《run in detached window》 -> true

用Java编写图书网站信息采集程序教程

目录 一、准备工作 二、分析目标网站结构 三、选择信息采集方式 四、安装Jsoup库 五、编写信息采集程序 六、注意事项 总结&#xff1a; 编写图书网站信息采集程序需要掌握HTML、CSS、JavaScript、Java等前端和后端技术。下面是一个简单的教程&#xff0c;介绍如何使用…

游戏开发中,你的游戏图片压缩格式使用ASTC了吗

文章目录 ASTC原理&#xff1a;使用要求 ASTC&#xff08;Adaptive Scalable Texture Compression&#xff0c;自适应可伸缩纹理压缩&#xff09;是一种高级的纹理压缩技术&#xff0c;由ARM公司开发并推广。它在图形处理领域中因其出色的压缩效率和灵活性而受到广泛关注。 AST…

上门洗衣洗鞋小程序多门店管理模式是怎么样的

做干洗店和洗鞋店的老板们很多都不止一个门店&#xff0c;多门店的管理模式下&#xff0c;去做一个上门洗衣洗鞋小程序&#xff0c;需要有哪些必要的功能才能让不同的门店管理起来不乱呢。首先需要先确定一下不同门店的管理都会面临哪些经营场景和需求。 第一&#xff0c;加盟店…

【前端素材】bootstrap4实现服装鞋饰电商平台Doron

一、需求分析 一个服装鞋饰电子商务页面是一个在线平台&#xff0c;用于展示和销售各种服装、鞋子和配饰产品。它通常具有以下功能&#xff1a; 产品展示&#xff1a;服装鞋饰电子商务页面会展示各种服装、鞋子和配饰产品的图片、描述和价格。这些产品可以按照不同的分类&#…

FreeRTOS学习总结(二)FreeRTOS任务创建和删除API函数

实现动态创建任务流程 任务控制块结构体成员介绍 typedef struct tskTaskControlBlock {volatile StackType_t * pxTopOfStack; /* 任务栈栈顶&#xff0c;必须为TCB第一个成员 */ListItem_t xStateListItem; /* 任务状态列表项 */ Li…

免费IDEA插件推荐:Apipost-Helper

IDEA插件市场中的API调试插件不是收费&#xff08;Fast Request &#xff09;就是不好用&#xff08;apidoc、apidocx等等&#xff09;今天给大家介绍一款国产的API调试插件&#xff1a;Apipost-Helper&#xff0c;完全免费且好看好用&#xff01; 这款插件由Apipost团队开发的…

llama.cpp模型推理之界面篇

目录 前言 一、llama.cpp 目录结构 二、llama.cpp 之 server 学习 1. 介绍 2. 编译部署 3. 启动服务 4、扩展或构建其他的 Web 前端 5、其他 前言 在《基于llama.cpp学习开源LLM本地部署》这篇中介绍了基于llama.cpp学习开源LLM本地部署。在最后简单介绍了API 的调用方…

什么是API网关代理?

带有API网关的代理服务显着增强了用户体验和性能。特别是对于那些使用需要频繁创建和轮换代理的工具的人来说&#xff0c;使用 API 可以节省大量时间并提高效率。 了解API API&#xff08;即应用程序编程接口&#xff09;充当服务提供商和用户之间的连接网关。通过 API 连接&a…

【仙丹秘法】如何炼制一颗稳定的仙丹

提示词始终保持不变 1&#xff1a;收集素材 制作lora_v1 2: 制作lora_v1 产生 1个人物 含 你想要的服装 导入 pose_1 到 control 1 生成人物 (white_background:1.1),front view,1boy,blue sleeveless t-shirt,blue shorts,detailed eyes,best quality,masterpiece,high res…
最新文章