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

如何开发一个支持海量分布式锁的应用库

分布式锁是一种用于控制分布式系统中资源访问的同步机制,确保在任意时刻只有一个客户端能够获取到锁,并对共享资源进行操作。
作用

1.保证数据一致性:在多个节点并发执行的情况下,分布式锁可以防止同时修改同一份数据,从而避免数据不一致的问题。

2.协调任务执行:确保特定的任务不会被重复执行,特别是在需要幂等性(idempotent)保证的时候。

应用场景例如

库存扣减:在电商系统中,当用户下单时需要扣减库存,为了避免超卖现象,必须确保每次扣减操作都是原子性的。

定时任务调度:在分布式环境中,确保同一个定时任务只在一个节点上运行,防止重复执行。

缓存更新:当多个服务实例试图更新同一个缓存项时,使用分布式锁可以确保更新过程的线程安全。

秒杀活动:对于高并发的抢购活动,如秒杀,使用分布式锁来控制对有限商品资源的访问是至关重要的。

文件上传:在分布式文件系统中,确保同一文件不会被多次上传或覆盖。

常见实现方式

•基于数据库:可以使用数据库的唯一索引来实现简单的分布式锁,也可以通过for update等机制来实现分布式锁。例如,在尝试获取锁时插入一条记录,如果插入成功则表示获取到锁;如果违反了唯一索引约束,则说明锁已经被其他客户端持有。这种方法简单直接,但性能可能不如其他专门设计的解决方案,并且需要处理死锁和锁的自动释放等问题。

•基于Redis:Redis是一个内存中的键值存储系统,它提供了原子性的SETNX(Set if Not Exists)命令来设置一个键,只有当该键不存在时才会成功。结合EXPIRE或PEXPIRE命令,可以为锁设置一个过期时间,防止死锁的发生。

•基于Zookeeper:Zookeeper支持临时顺序节点,这使得它可以实现复杂的分布式锁逻辑,如公平锁、重入锁以及读写锁。客户端创建一个临时顺序节点作为锁对象,然后检查自己创建的节点是否是最小编号的节点,以此判断是否获得锁。

•基于Etcd:Etcd是一个高可用的分布式键值存储系统,它也能够提供分布式锁功能。与Zookeeper类似,etcd使用临时键和租约机制来实现锁。

•基于Consul:同样可以用来实现分布式锁。Consul利用KV存储和会话机制,可以方便地构建出分布式锁的应用。

本文将利用raftx,用简单的方法,编写一个分布式锁的应用库,它的特点是:

•使用方式简单并且可用性强

•支持海量创建分布式锁,可以同时创建几十万甚至上百万个分布式锁

•占用极少量的系统资源

•无自旋阻塞策略,不占用CPU资源

•抢占式获取锁

•支持TTL(time to live), 防止集群节点宕机造成死锁

raftx的分布式易失性数据扩展模块实现分布式锁 有比常见分布式锁的实现较为明显的特点

1.高效,它基于内存。获取与释放分布式锁过程更快

2.可以创建海量分布式锁。如果系统需要创建海量分布式锁,比如售票系统,电商秒杀活动等, 对于Zookeeper,Etcd,redis等,在创建海量分布式锁时,可能面临大量日志与大量触发机制,导致系统负载过大的问题。而raftx则不会有这个问题。可以通过以下的Lockx的实现过程,详细了解。


什么是Raftx

raftx 是一种对经典 Raft 协议的扩展,结合了 Multi-Paxos、ZAB(Zookeeper Atomic Broadcast)和 Raft 协议的优势。RaftX 具备快速选举、并发提案、数据同步、数据回滚以及易失性数据同步等特性,适用于高并发和大规模分布式系统场景。

raftx wiki

Lockx 分布式锁应用库,支持创建海量分布式锁

Lockx是依赖raftx实现的一个分布式锁应用库,实现方式简单,代码量少,100行左右代码,但是它的功能却十分强大,主要表现在:

•高效性与及时性

•资源占用极少

•支持海量创建分布式锁

•API使用简单方便

Lockx 支持一次性创建成千上万,甚至数十万或数百万个分布式锁,它的实现机制保证了它不会大量占用CPU资源和内存资源;它的锁动作变更触发机制针对的是锁资源,而非分布式对象锁本身,也就是说,即使节点中有100万个锁竞争一个锁资源,每次也只会触发一次锁的释放与竞争的指令;比如锁资源"lockmux",那么在分布式系统中,当资源 “lockmux”被释放时,它将触发节点中的 “lockmux”绑定事件一次,并让等待的资源随机发送一条竞争锁的指令竞争该资源锁,而不是触发100万个等待中的锁对象竞争事件。

Lockx 实现方式

lockx主要依赖raftx的易失性数据API实现,它的特点是高效,强一致性,并且可以绑定键值的增删改的触发事件;利用这些特性,可以轻松实现分布式锁的逻辑。

	m.raft.MemWatch([]byte(lockstr), func(key, value []byte, watchType raft.WatchType) {//获取锁成功与否if watchType == raft.ADD {if mb, ok := m.mp.Get(util.BytesToInt64(value)); ok {m.del(string(key), util.BytesToInt64(value))close(mb.ctx)}}//锁释放,阻塞代码再次重新获取分布式锁if watchType == raft.DELETE {m.mux.Lock()defer m.mux.Unlock()if ids, b := m.rmap[string(key)]; b {for k := range ids {m.raft.MemCommand(key, util.Int64ToBytes(k), timeout, raft.MEM_PUT)break}}}//TryLock获取锁失败触发if watchType == raft.UPDATE {if mb, ok := m.mp.Get(util.BytesToInt64(value)); ok {if mb.isTry {m.del(string(key), util.BytesToInt64(value))mb.ctx <- trueclose(mb.ctx)}}}}, false, raft.ADD, raft.DELETE, raft.UPDATE)
这是lockx实现的核心代码,主要通过监听raftx易失性数据主键的增删改事件来实现资源锁的锁定与释放

•raft.ADD 这是资源锁新增的触发事件,通过它判断哪个对象获取到分布式锁,同时关闭相应阻塞的通道,让获取锁的程序继续执行。

•raft.DELETE 这是资源锁删除的触发事件,同时它将再次发送获取资源锁的指令,抢占资源锁

•raft.UPDATE 这是资源锁更新的触发事件,它表示资源锁获取失败,用于TryLock,同时关闭相应阻塞的通道并返回false

Lockx 使用方式

Lockx 的使用非常简单,并且它可以支持大量创建分布式锁,它一共有3个方法

Lock(string,int) 获取指定资源的分布式锁并设置过期时间,阻塞

TryLock(string,int)bool 获取指定资源的分布式锁并设置过期时间,若获取不到返回false,不阻塞

UnLock(string) 释放指定资源的分布式锁

以下模拟3个集群节点

//节点1,创建分布式锁管理器 mutex1
mutex1 = NewMutex(":20001", []string{"127.0.0.1:20001", "127.0.0.1:20002", "127.0.0.1:20003"})//节点2,创建分布式锁管理器 mutex2
mutex2 = NewMutex(":20002", []string{"127.0.0.1:20001", "127.0.0.1:20002", "127.0.0.1:20003"})//节点3,创建分布式锁管理器 mutex3
mutex3 = NewMutex(":20003", []string{"127.0.0.1:20001", "127.0.0.1:20002", "127.0.0.1:20003"})

•第一个参数 raftx服务地址

•第二个参数是所有集群节点都相同的,为所有节点的访问地址 []string{"127.0.0.1:20001", "127.0.0.1:20002", "127.0.0.1:20003"}

这样就完成了分布式锁管理器的创建,并可以直接获取各个自定义资源的分布式锁,这里的资源指的是字符串,比如 “test”

示例

//节点1
func lock1(i int) {logger.Debugf("mutex1 lock%d lock.....", i)mutex1.Lock("test", 10)logger.Debugf("mutex1 lock%d get lock successful", i)time.Sleep(2 * time.Second)mutex1.Unlock("test")logger.Debugf("mutex1 lock%d unlock", i)
}//节点2
func lock2(i int) {logger.Debugf("mutex2 lock%d lock.....", i)mutex2.Lock("test", 10)logger.Debugf("mutex2 lock%d get lock successful", i)
}//节点3
func lock3(i int) {logger.Debugf("mutex3 lock%d lock.....", i)mutex3.Lock("test", 10)logger.Debugf("mutex3 lock%d get lock successful", i)time.Sleep(2 * time.Second)mutex3.Unlock("test")logger.Debugf("mutex3 lock%d unlock", i)
}

测试调用

func Test_lock(t *testing.T) {go lock1(1)go lock2(2)go lock3(3)select {}
}

执行结果:

可以看到:

2024/12/31 22:34:35 三个节点的同时抢占分布式锁

•节点mutex2获取到了锁,由于mutex2没有主动释放锁,mutex2.Lock("test", 10) 这里表示10秒后 ,集群自动释放锁

2024/12/31 22:34:45 mutex2持有的分布式锁被服务自动释放,同时mutex1节点获取到分布式锁

2024/12/31 22:34:47 mutex1在2秒后显式调用UnLock释放锁,同时mutex3节点获取到分布式锁

2024/12/31 22:34:49 mutex3在2秒后显式调用UnLock释放锁


Lockx 可以海量创建分布式锁,如:
func Test_multi_lock(t *testing.T) {for i := 1; i < 1<<15; i++ {  //mutex1节点创建32768个并发任务go lock1(i)}for i := 1; i < 1<<15; i++ { //mutex2节点创建32768个并发任务go lock2(i)}for i := 1; i < 1<<15; i++ { //mutex3节点创建32768个并发任务go lock3(i)}select {}
}

每个节点同时并发创建32768个分布式锁对象

执行结果:

可以看到,每2秒有一个对象获取到分布式锁,按顺序依次执行获取分布式锁与解锁。

(注意:mutex2增加了2秒后释放锁,否则mutex2节点获取锁后,将等待10秒后有raftx集群释放锁)


Lockx 的源码地址

可以直接将其当成第三方分布式锁库在工程中使用

程序中调用示例

import "github.com/donnie4w/lockx"//创建分布式锁管理器 mutex1
var mutex1 = lockx.NewMutex(":20001", []string{"127.0.0.1:20001", "127.0.0.1:20002", "127.0.0.1:20003"})

结论

Lockx 利用了 raftx 的高效特性和易失性数据存储能力,提供了一种简洁而强大的分布式锁解决方案。它不仅适合常规的分布式锁需求,还能够在高并发环境下保持性能优势,确保系统的稳定性和可靠性。

如果你考虑在项目中引入这样的分布式锁库,可以参考上述信息进行评估和集成。此外,也可以根据自己的具体需求调整 Lockx 的实现,例如实现更复杂的锁行为(如公平锁等)。

相关文章:

如何开发一个支持海量分布式锁的应用库

分布式锁是一种用于控制分布式系统中资源访问的同步机制&#xff0c;确保在任意时刻只有一个客户端能够获取到锁&#xff0c;并对共享资源进行操作。 作用 1.保证数据一致性&#xff1a;在多个节点并发执行的情况下&#xff0c;分布式锁可以防止同时修改同一份数据&#xff0c…...

JavaScript系列(17)--类型系统模拟

JavaScript类型系统模拟 &#x1f3ad; 今天&#xff0c;让我们深入探讨JavaScript中的类型系统模拟。虽然JavaScript是一门动态类型语言&#xff0c;但我们可以通过各种方式来实现类型检查和验证。 类型系统基础 &#x1f31f; &#x1f4a1; 小知识&#xff1a;JavaScript是…...

openssl编译

关于windows下&#xff0c;openssl编译 环境准备 安装 perl:https://djvniu.jb51.net/200906/tools/ActivePerl5_64.rar安装nasm&#xff1a;https://www.nasm.us/pub/nasm/releasebuilds/2.13.01/win64/nasm-2.13.01-installer-x64.exe下载opensll源码&#xff1a;https://o…...

校园网络综合布线系统设计与实践

校园网络综合布线系统设计与实践 摘要&#xff1a;随着信息时代的发展&#xff0c;网络综合布线显得更加重要。综合布线技术也日益引起人的重视。综合布线管理系统是一个实用性十分强的系统工程&#xff0c;同样又是现代社区信息化建设的基础与必要产品&#xff0c;是对多用途…...

如果商品信息更新,爬虫会失效吗?

当商品信息更新时&#xff0c;爬虫是否失效取决于更新的具体内容。以下是一些可能影响爬虫的因素&#xff1a; 可能导致爬虫失效的情况 HTML结构变化&#xff1a;如果 yiwugo 平台更新了商品详情页面的 HTML 结构&#xff0c;比如改变了元素的标签、类名或 ID&#xff0c;那么…...

【UE5 C++课程系列笔记】27——多线程基础——ControlFlow插件的基本使用

目录 步骤 一、搭建基本同步框架 二、添加委托 三、添加蓝图互动框架 四、修改为异步框架 完整代码 通过一个游戏初始化流程的示例来介绍“ControlFlows”的基本使用。 步骤 一、搭建基本同步框架 1. 勾选“ControlFlows”插件 2. 新建一个空白C类&#xff0c;这里…...

有收到腾讯委托律师事务所向AppStore投诉带有【水印相机】主标题名称App的开发者吗

近期&#xff0c;有多名开发者反馈&#xff0c;收到来自腾讯科技 (深圳) 有限公司委托北京的一家**诚律师事务所卞&#xff0c;写给AppStore的投诉邮件。 邮件内容主要说的是&#xff0c;腾讯注册了【水印相机】这四个字的商标&#xff0c;所以你们这些在AppStore上的app&…...

标定 3

标定场景与对应的方式 标定板标定主要应用场景: (1)无法获取到执行机构物理坐标值,比如相机固定,执行机构为传送带等 (2)相机存在畸变等非线性标定情况,需要进行畸变校正 (3)标定单像素精度 (4)获取两个相机之间的坐标系关系 标定板操作步骤: (1)确定好拍…...

用 C# 绘制谢尔宾斯基垫片

谢尔宾斯基垫片是一个三角形&#xff0c;分解成多个小三角形&#xff0c;如右图所示。有几种方法可以生成这种垫片。这里展示的方法是其中一种比较令人惊讶的方法。 程序从三个点开始&#xff08;图中圆圈所示&#xff09;。“当前位置”从其中一个点开始。为了生成后续点&…...

java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter

今天在朋友机子上运行代码&#xff0c;在生成token的时候&#xff0c;遇到了这样一个问题&#xff1a; Caused by: java.lang.NoClassDefFoundError: javax/xml/bind/DatatypeConverter at io.jsonwebtoken.impl.Base64Codec.decode(Base64Codec.java:26) ~[jjwt-0.9.1.jar:0.…...

双因素身份验证技术在NPI区域邮件安全管控上的解决思路

在制造业中&#xff0c;NPI&#xff08;New Product Introduction&#xff0c;新产品导入&#xff09;区域是指专门负责新产品从概念到市场推出全过程的部门或团队。NPI 的目标是确保新产品能够高效、高质量地投入生产&#xff0c;并顺利满足市场需求。在支撑企业持续创新和竞争…...

java后端对接飞书登陆

java后端对接飞书登陆 项目要求对接第三方登陆&#xff0c;飞书登陆&#xff0c;次笔记仅针对java后端&#xff0c;在看本笔记前&#xff0c;默认已在飞书开发方已建立了应用&#xff0c;并获取到了appid和appsecret。后端要做的其实很简单&#xff0c;基本都是前端做的&…...

记录一次Android Studio的下载、安装、配置

目录 一、下载和安装 Android Studio 1、搜索下载Android studio ​2、下载成功后点击安装包进行安装&#xff1a; 3、这里不用打勾&#xff0c;直接点击安装 &#xff1a; 4、完成安装&#xff1a; 5、这里点击Cancel就可以了 6、接下来 7、点击自定义安装&#xff1a…...

直流无刷电机控制(FOC):电流模式

目录 概述 1 系统框架结构 1.1 硬件模块介绍 1.2 硬件实物图 1.3 引脚接口定义 2 代码实现 2.1 软件架构 2.2 电流检测函数 3 电流环功能实现 3.1 代码实现 3.2 测试代码实现 4 测试 概述 本文主要介绍基于DengFOC的库函数&#xff0c;实现直流无刷电机控制&#x…...

73.矩阵置零 python

矩阵置零 题目题目描述示例 1&#xff1a;示例 2&#xff1a;提示&#xff1a; 题解思路分析Python 实现代码代码解释提交结果 题目 题目描述 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例…...

垃圾收集算法

分代收集理论 分代收集理论&#xff0c;建立在两个分代假说之上。 弱分代假说&#xff1a;绝大多数对象都是朝圣夕灭的。 强分代假说&#xff1a;熬过越多次垃圾收集的过程的对象就越难以消亡。 这两个分代假说奠定了垃圾收集器的一致设计原则&#xff1a;收集器应该将Java…...

SQL-leetcode-262. 行程和用户

262. 行程和用户 表&#xff1a;Trips --------------------- | Column Name | Type | --------------------- | id | int | | client_id | int | | driver_id | int | | city_id | int | | status | enum | | request_at | varchar | --------------------- id 是这张表的主键…...

太原理工大学软件设计与体系结构 --javaEE

这个是简答题的内容 选择题的一些老师会给你们题库&#xff0c;一些注意的点我会做出文档在这个网址 项目目录预览 - TYUT复习资料:复习资料 - GitCode 希望大家可以给我一些打赏 什么是Spring的IOC和DI IOC 是一种设计思想&#xff0c;它将对象的创建和对象之间的依赖关系…...

Leetcode 139. 单词拆分 动态规划

原题链接&#xff1a;Leetcode 139. 单词拆分 递归&#xff0c;超时 class Solution { public:bool isfind(string s,map<string,int>& mp){for(auto x:mp){string wordx.first;if(sword) return true;int nword.size();if(n>s.size()) continue;string s1s.subs…...

python异常机制

异常是什么&#xff1f; 软件程序在运行过程中&#xff0c;非常可能遇到刚刚提到的这些问题&#xff0c;我们称之为异常&#xff0c;英文是Exception&#xff0c;意思是例外。遇到这些例外情况&#xff0c;或者交异常&#xff0c;我们怎么让写的程序做出合理的处理&#xff0c…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

椭圆曲线密码学(ECC)

一、ECC算法概述 椭圆曲线密码学&#xff08;Elliptic Curve Cryptography&#xff09;是基于椭圆曲线数学理论的公钥密码系统&#xff0c;由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA&#xff0c;ECC在相同安全强度下密钥更短&#xff08;256位ECC ≈ 3072位RSA…...

微软PowerBI考试 PL300-选择 Power BI 模型框架【附练习数据】

微软PowerBI考试 PL300-选择 Power BI 模型框架 20 多年来&#xff0c;Microsoft 持续对企业商业智能 (BI) 进行大量投资。 Azure Analysis Services (AAS) 和 SQL Server Analysis Services (SSAS) 基于无数企业使用的成熟的 BI 数据建模技术。 同样的技术也是 Power BI 数据…...

前端导出带有合并单元格的列表

// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

2024年赣州旅游投资集团社会招聘笔试真

2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

多模态商品数据接口:融合图像、语音与文字的下一代商品详情体验

一、多模态商品数据接口的技术架构 &#xff08;一&#xff09;多模态数据融合引擎 跨模态语义对齐 通过Transformer架构实现图像、语音、文字的语义关联。例如&#xff0c;当用户上传一张“蓝色连衣裙”的图片时&#xff0c;接口可自动提取图像中的颜色&#xff08;RGB值&…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

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

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

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...