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

在这里插入图片描述

😄 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.mzph.cn/news/607412.shtml

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

相关文章

Spark MLlib ----- ALS算法

补充 在谈ALS(Alternating Least Squares)之前首先来谈谈LS,即最小二乘法。LS算法是ALS的基础,是一种数优化技术,也是一种常用的机器学习算法,他通过最小化误差平方和寻找数据的最佳匹配,利用最小二乘法寻找最优的未知数据,保证求的数据与已知的数据误差最小。LS也被用…

Web开发:SQLsugar的安装和使用

一、安装 第一步&#xff0c;在你的项目中找到解决方案&#xff0c;右键-管理解决方案的Nuget 第二步&#xff0c;下载对应的包&#xff0c;注意你的框架是哪个就下载哪个的包&#xff0c;一个项目安装一次包即可 点击应用和确定 安装好后会显示sqlsugar的包 二、使用&#xf…

聚类分析 | Matlab实现基于RIME-DBSCAN的数据聚类可视化

聚类分析 | Matlab实现基于RIME-DBSCAN的数据聚类可视化 目录 聚类分析 | Matlab实现基于RIME-DBSCAN的数据聚类可视化效果一览基本介绍程序设计参考资料 效果一览 基本介绍 1.聚类分析 | Matlab实现基于RIME-DBSCAN的数据聚类可视化&#xff08;完整源码和数据) 2.多特征输入&…

js实现点击音频实现播放功能

html: <div class"audioDiv" id"playButton" style"width:13vw;height: 3.5vh;"><img src"./img/yuyin.png" alt"" /><p id"countdown">4:31<p><p id"bofang">播放录音&…

深度探析卷积神经网络(CNN)在图像视觉与自然语言处理领域的应用与优势

目录 前言1 CNN网络结构与工作原理1.1 输入层1.2 卷积层1.3 最大池化层1.4 全连接层 2 应用领域2.1 图像视觉领域中CNN的应用2.2 NLP领域中CNN的应用 3 CNN的限制与未来展望3.1 CNN的挑战3.2 CNN的展望 结语 前言 卷积神经网络&#xff08;CNN&#xff09;作为一种强大的深度学…

【Spring】Spring的事务管理

前言&#xff1a; package com.aqiuo.service.impl;import com.aqiuo.dao.AccountMapper; import com.aqiuo.pojo.Account; import com.aqiuo.service.AccountService; import org.springframework.jdbc.core.JdbcTemplate;import java.sql.Connection; import java.sql.SQLEx…

CentOS 8 8.5.2111 网络在线安装系统 —— 筑梦之路

之前写过一篇关于centos 8 官方停止更新维护后解决yum源问题的文章&#xff1a; CentOS 8 停止维护后换可用yum源——筑梦之路_http://ftp.iij.ad.jp/pub/linux/centos-vault/8.5.21-CSDN博客 由于centos 8 dvd的镜像比较大&#xff0c;有时候我们根本不需要去下载一个10G以上…

网络安全之文件上传

常见文件上传点 大部分的网站和应用系统都有上传功能&#xff0c;如用户头像上传&#xff0c;图片上传&#xff0c;文档上传等。 任意文件上传漏洞 定义 由于对上传文件未作过滤或过滤机制不严 (文件后缀或类型)导致恶意用户可以上传脚本文件&#xff0c;通过上传文件可达到…

MySQL 性能优化思路和优化案例

MySQL性能优化是确保数据库高效运行的关键过程。这通常涉及到多个方面&#xff0c;如查询性能、索引策略、系统配置、硬件资源等。以下是一些优化思路及其案例 优化思路 1. 查询优化 思路: 重写低效的查询&#xff0c;避免使用子查询&#xff0c;改用连接&#xff08;JOIN&…

“30天化学探索旅程”提纲

文章目录 第一部分&#xff1a;化学基础理论1. 第1天&#xff1a;化学世界的开启2. 第2天&#xff1a;元素周期表的探索之旅3. 第3天&#xff1a;原子构造的秘密揭示4. 第4天&#xff1a;化学键的魔力解析5. 第5天&#xff1a;无机化合物的世界与应用 第二部分&#xff1a;化学…

Python中无法使用Selenium,显示ValueError: Timeout value connect was ……, but it must be an int, float or None

近期重装了系统&#xff0c;需要做个爬虫&#xff0c;最初想用Selenium和Msedge模拟浏览器操作&#xff0c;但总是不成功&#xff0c;即使是用webdriver打开网页这样最简单的操作&#xff0c;也无法做到&#xff0c;总是显示ValueError: Timeout value connect was <object …

手机远程控制电脑_手机操作电脑方法

在我们的日常生活和工作中&#xff0c;有时候我们需要从外面访问家里或公司的电脑。这听起来可能很复杂&#xff0c;但实际上非常简单。今天&#xff0c;我们将分享如何使用手机远程控制电脑。 首先&#xff0c;您需要在电脑上安装KKView远程控制软件&#xff0c;该软件提供手…

PositiveSSL和Sectigo的多域名证书

首先&#xff0c;我们要知道PositiveSSL是Sectigo旗下的子品牌&#xff0c;提供多种类型的SSL数字证书&#xff0c;包括DV基础型的多域名SSL证书。Sectigo的SSL证书产品同样比较丰富&#xff0c;不仅有DV基础型多域名SSL证书&#xff0c;还有OV企业型以及EV增强型的多域名SSL证…

IO类day02

JAVA IO java io可以让我们用标准的读写操作来完成对不同设备的读写数据工作. java将IO按照方向划分为输入与输出,参照点是我们写的程序. 输入:用来读取数据的,是从外界到程序的方向,用于获取数据. 输出:用来写出数据的,是从程序到外界的方向,用于发送数据. java将IO比喻为…

Python面试题:默认参数问题

问题&#xff1a;在 Python 中&#xff0c;解释以下代码并说明输出结果&#xff1a; def foo(x, items[]):items.append(x)return itemsprint(foo(1)) print(foo(2)) print(foo(3))答案&#xff1a; 这段代码定义了一个名为 foo 的函数&#xff0c;该函数接受两个参数&#xf…

Raft 读请求性能分析

Raft保证读请求Linearizability的方法 Leader把每次读请求作为一条日志记录&#xff0c;以日志复制的形式提交&#xff0c;并应用到状态机后&#xff0c;读取状态机中的数据返回。&#xff08;一次RTT、一次磁盘写&#xff09; 使用Leader Lease&#xff0c;保证整个集群只有一…

视觉SLAM十四讲|【四】误差Jacobian推导

视觉SLAM十四讲|【四】误差Jacobian推导 预积分误差递推公式 ω 1 2 ( ( ω b k n k g − b k g ) ( w b k 1 n k 1 g − b k 1 g ) ) \omega \frac{1}{2}((\omega_b^kn_k^g-b_k^g)(w_b^{k1}n_{k1}^g-b_{k1}^g)) ω21​((ωbk​nkg​−bkg​)(wbk1​nk1g​−bk1g​)) …

LINUX基础培训三之文件和目录管理

前言、本章学习目标 了解LINUX文件类型及目录结构掌握LINUX文件的基本属性熟悉用户、用户组、其他的安全模型掌握LINUX文件和目录的常用管理 一、LINUX文件管理 1、什么是LINUX中的文件 在LINUX操作系统中有一个重要的概念&#xff1a;一切皆为文件。除了我们常说的文本文…

pytorch09:可视化工具-TensorBoard,实现卷积核和特征图可视化

目录 一、TensorBoard简介二、TensorBoard安装三、TensorBoard运行可视化四、TensorBoard详细使用4.1 SummaryWriter4.2 add_scalar()4.3 add_scalars()4.4 add_histogram()4.4.1实际项目开发使用 4.5 add_image()4.6 torchvision.utils.make_grid4.7 卷积核和特征图可视化4.7.…

Nature:物理所利用原位透射电子显微技术在分子尺度研究立方冰

冰是水在自然界中的固体形态&#xff0c;在大自然中也广泛存在&#xff0c;冰的结构及形成机理研究对云物理及低温储存物理至关重要&#xff0c;因此科学家们对冰的研究也历史久远。提到冰在较小尺度的存在形态&#xff0c;我们最容易想到的是雪花。如下图所示&#xff0c;雪花…