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

分布式锁 Redis vs etcd

        • 为什么要实现分布式锁?
        • 为什么需要分布式锁,分布式锁的作用是什么,哪些场景会使用到分布式锁?
        • 分布式锁的实现方式有哪些
        • 分布式锁的核心原理是什么
      • 如何实现分布式锁
        • redis(自旋锁版本)
        • etcd 的分布式锁(互斥锁(信号控制)版本)
      • 分布式锁对比
          • redis vs etcd
      • 总结

为什么要实现分布式锁?
  • 了解分布式锁的底层工作原理,以及如果在工程中应用,我们应该如何选择.
为什么需要分布式锁,分布式锁的作用是什么,哪些场景会使用到分布式锁?

为什么需要分布式锁

  • 解决分布式业务需要互斥的问题(同时只能有一次客户端的一个线程可以执行的场景),保护共享数据
  • 具体场景: 支付业务(避免多端同时支付),消息队列的消费(避免多端同时消费产生重复消费的问题),服务器的偏执业务(有些业务(数据同步)只需要一个服务器执行,不需要全部都开启,这时候可以使用分布式锁,拿到锁的执行,其他就不执行)

分布式锁的作用

  • 分布式实现线程互斥,确保只有一个线程能够执行

分布式锁的使用场景

  • 需要分布式线程互斥逻辑的场景都可以使用分布式锁
分布式锁的实现方式有哪些
  • redis 分布式锁
  • etcd 分布式锁
分布式锁的核心原理是什么
  • 互斥性:确保只有一个程序的一个线程可以获取到锁
  • 死锁预防: 如果程序意外终止会释放锁而不是持续占用锁资源,导致死锁
    • 实例自动回收(过期),客户端定时续期来实现
  • 锁的公平竞争: 避免锁被饿死

如何实现分布式锁

redis(自旋锁版本)
  • 原子性保证
    • redis 单线程本身的读写都是原子的,没有并发问题
    • 对相同的 key 使用 setnx(set not exit 只会在不存在的时候设置成功,如果存在表示锁被占用的情况则会返回 0(获取锁失败))
  • 死锁预防:
    • 使用 redis 过期机制实现
    • 加锁: 使用合成命令或者 lua 脚本保证加锁的原子性
      • 合成命令: setnx k v ex ex_time 一次性在获取锁的时候就设置完成过期时间
      • 将获取锁与设置锁关过期时间的两条 redis 命令写到一个 lua 脚本中保证锁设置的原子性
        • 可不可以将其拆分成为两步:先抢锁(setnx),在设置过期时间(setex)
          • 不可以:因为设置过期时间可能有失败的风险(比如网络问题导致失败,那么这个可以有死锁的风险
      • 续期:
        • 如果加锁成功则立即开启定时任务(ticker),定时更新过期时间,直到锁的释放(接收到 delete 信号)
        • 避免信号延迟或者丢失造成锁的自动过期导致的原子性被破坏(多个线程同时获取到锁):一个过期时间内将会发送三次续期的心跳,只要任何一个续期请求到达 redis 都可以续期成功
    • 锁的公平性:
      • 所有的锁都以自旋的方式获取锁,公平的竞争锁
        • 自旋时间间隔随自旋的次数增加而减少(每次自旋减少 1ms,最低 10ms 自旋一次),所以阻塞时间越久的线程获取到锁的概率越高,防止锁被饿死.
      • 问题,再大量并发的情况下,依旧有被饿死的风险
    • 锁的误删避免: 确保每个线程只能删除自己的锁不能删除其他线程的锁
      • 如果锁的删除命令因为网络等原因导致延迟到达(其他线程获取了锁,这时删除命令到达,会误删去他的锁,破坏锁的原子性)
      • 使用唯一 value + lua 脚本进行实现
        • 使用 lua 脚本在保证原子性的情况下删除自己的 key
          • 加锁时 value 在客户端生成唯一标识(可以使用 uuid)
          • 释放锁的时候:lua(检查 redis 中value 是否与客户端的 value 相同,如果相同就删除,如果不同证明自己已经不持有该锁,就不做任何操作)
etcd 的分布式锁(互斥锁(信号控制)版本)

etcd 没有像 redis 那样 setnx 的命令,但是他的 Revision(版本号)与 watch 机制可以实现锁

  • 原子性: 保证只有一个线程获取到锁
    • 预写: 所有获取锁的线程都会先将 k-v 写到 etcd 中,etcd 会给每个写操作都迭代一个递增的版本号(获取锁的基本原理就是所有 kv 中最小的为当前持有锁)(有问题)
    • 试加锁: 再检查自己的版本号是否是列表中最小的(如果是就获取到锁,直接返回)
    • 等待锁:等待自己前面的锁全部释放,直到自己是 kv 对中版本最小的一个
      • 使用 watch 监听自己前面的删除,直到自己前面已经没有任何 kv 对(有点问题在里面)
    • 再检查: 检查自己的kv 对是否在队列中,如果不在就不能加锁,因为不知道被谁删除了,或者过期了,就自己返回错误)(因为你的 k-v 不在 etcd 中的话,你的后面一个就会发现自己是最小的,如果你也运行程序,那么就会有两个线程同时获取到锁,破坏锁的原子性,所以要先检查再获取锁)
  • 防止死锁:
    • 租约 : etcd 有自己的租约,每一个 k-v 设置的时候就会绑定租约(与 redis 的过期时间+心跳续期的原理类似,只是这个是隐式的,在会话中实现的)
    • 当锁释放的时候就会停止续租并删除 k-v对(在后面的线程就会监听到他的删除)
  • 锁的公平性:(版本号)
    • etcd 锁是天然公平的,是通过每个 kv 的版本号控制的
    • 因为版本号是递增的,那么整个锁就形成了一个先进先出的队列模式,只有到达队头(版本号最小)的线程会获取到锁执行业务逻辑,其他线程都是阻塞等待的状态
  • 锁的误删:
    • etcd 中每个锁都只持有自己的 key,所以只能对自己的 k-v 对进行操作,不会出现误删的情况.

分布式锁对比

redis vs etcd

性能: 吞吐量

redis: 性能本身就更好,redis 有 20w 并发

redis 的性能瓶颈在网络 io,Reds 使用的 tcp 的协议,io 的性能就是 20 万

etcd 要略低只有 10 多万作用

etcd 使用的 grpc 的架构,底层是 http2 的传输协议; grpc 的性能是 15 万的 qps,所以 etcd 的性能只有 15 万左右

强一致性

Redis 分片的意外崩溃可能会导致锁的原子性被破坏

解决方法:redlock 模式

etcd 集群本身具有强一致性,不需要担心单个实例的崩溃破坏锁原子性的问题



服务器的影响:

redis 使用的自旋的形式获取锁,会消费一定的服务器 cpu

etcd 是等待信号通知的形式(watch),不需要自旋与循环,对服务器性能影响小


实例储存的数据量

Redis 一个 lock 只需要维护一个 k-v 对,储存数据少,但是 Redis 可能会处理大量自旋请求.

etcd 每一个线程的获取锁都是一个 k- v 对,储存的数据多,并且要维护所有线程的连接,开销大,不能同时接受太多获取锁的请求,否则会资源耗尽(连接)(如果并发数量高,并且有线程长期持有锁可能会导致连接的大量堆积)

总结

  1. 当我们不需要很强的一致性,但是需要比较高的性能的时候,大量并发获取锁的情景下我们可以选择 Redis 的分布式锁
  2. 如果我们需要强一致,高性能,高并发的场景的话我们可以使用 Redis 的 redlock 模式
  3. 如果我们需要强一致,但是性能不需要太高,并且并发数量并不高的情况,可以选择使用 etcd 的分布式锁

参考:
https://blog.csdn.net/qq_16399991/article/details/130732780
https://time.geekbang.org/column/article/350285
https://blog.csdn.net/boonya/article/details/117307663

相关文章:

分布式锁 Redis vs etcd

为什么要实现分布式锁?为什么需要分布式锁,分布式锁的作用是什么,哪些场景会使用到分布式锁?分布式锁的实现方式有哪些分布式锁的核心原理是什么 如何实现分布式锁redis(自旋锁版本)etcd 的分布式锁(互斥锁(信号控制)版本) 分布式锁对比redis vs etcd 总结 为什么要实现分布式…...

《深度剖析:开源与闭源模型,AI舞台上的不同角色》

在人工智能蓬勃发展的当下,模型的选择如同为一场战役挑选合适的武器,至关重要。开源模型与闭源模型作为AI领域的两大阵营,在性能和应用场景上展现出显著差异,深刻影响着开发者、企业以及整个行业的走向。 性能差异:实…...

Angular结合C#

在 Angular 2 及以上版本与 C#结合使用 REST API 的示例中,我们将分别展示前端 Angular 服务和后端 C# Web API 的实现。 一、前端:Angular 服务 生成 Angular 服务 使用 Angular CLI 生成一个新的服务,例如user.service.ts: ng…...

Spring——自动装配

假设一个场景: 一个人(Person)有一条狗(Dog)和一只猫(Cat),狗和猫都会叫,狗叫是“汪汪”,猫叫是“喵喵”,同时人还有一个自己的名字。 将上述场景 抽象出三个实体类&…...

Servlet与JSP:Java的秘密花园入口

1 Servlet概述 Servlet是Java Web应用中的一个核心组件,它是一个运行在服务器端的Java程序,可以响应客户端的请求并生成响应。Servlet为Web应用提供了一个统一的接口来处理HTTP请求。 2 Servlet的生命周期 Servlet的生命周期包括以下几个阶段&#xff…...

【Linux】Linux常见指令(上)

个人主页~ 初识Linux 一、Linux基本命令1、ls指令2、pwd命令3、cd指令4、touch指令5、mkdir指令6、rmdir指令7、rm指令8、man指令9、cp指令10、mv命令 Linux是一个开源的、稳定的、安全的、灵活的操作系统,Linux下的操作都是通过指令来实现的 一、Linux基本命令 先…...

ELFK日志采集实战

一、日志分析概述 日志分析是运维工程师解决系统故障,发现问题的主要手段 日志主要包括系统日志、应用程序日志和安全日志 系统运维和开发人员可以通过日志了解服务器软硬件信息、检查配置过程中的错误及错误发生的原因 经常分析日志可以了解服务器的负荷&#x…...

Kubernetes 使用自定义资源(CRD)扩展API

K8s CRD 即 Kubernetes CustomResourceDefinition,是 Kubernetes 提供的一种扩展机制,允许用户在 Kubernetes 集群中定义和使用自定义的资源类型。通过定义 CRD,用户可以在 Kubernetes 集群中创建、读取、更新和删除自定义资源对象&#xff0…...

用户使用LLM模型都在干什么?

Anthropic 对用户与 Claude 3.5 Sonnet 的大量匿名对话展开分析,主要发现及相关情况如下: 使用用途分布 软件开发主导:在各类使用场景中,软件开发占比最高,其中编码占 Claude 对话的 15% - 25%,网页和移动应…...

MySQL常用命令之汇总(Summary of Commonly Used Commands in MySQL)

MySQL常用命令汇总 简介 ‌MySQL是一个广泛使用的开源关系型数据库管理系统,由瑞典的MySQL AB公司开发,现属于Oracle公司。‌ MySQL支持SQL(结构化查询语言),这是数据库操作的标准语言,用户可以使用SQL进…...

六年之约day10

今日开心∶今天部门开了个颁奖大会,看着别人收获的荣誉,还真有些羡慕,什么时候,我也能拥有属于自己的荣誉啊. 今日不开心∶活没干多少,对业务也不是很懂 今日思考∶很多事情,存在即合理.工作,…...

springboot和vue配置https请求

项目场景: 代码发布到线上使用https请求需要配置ssl证书,前后端都需要修改。 问题描述 如图,我们在调用接口时报如下错误,这就是未配置ssl但是用https请求产生的问题。 解决方案: 前端:在vite.config.js文…...

selenium遇见伪元素该如何处理?

🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 问题发生 在很多前端页面中,大家会见到很多::before、::after 元素,比如【百度流量研究院】: 比如【百度疫情大数…...

慧集通(DataLinkX)iPaaS集成平台-数据质量

1.什么是数据质量 介绍: 数据质量的主要作用就是记录组件写入的数据,及执行时的相关信息,如执行的最终状态(成功,失败,进行中等),执行的时间(创建时间,修改时…...

微软发布AIOpsLab:一个开源的全面AI框架,用于AIOps代理

在当今这个云计算技术迅猛发展的时代,企业面临着前所未有的挑战与机遇。随着云基础设施的日益复杂化,它们成为了企业运营不可或缺的支柱。网站可靠性工程师(Site Reliability Engineers,简称SRE)和DevOps团队肩负着关键…...

ElasticSearch | Elasticsearch与Kibana页面查询语句实践

关注:CodingTechWork 引言 在当今大数据应用中,Elasticsearch(简称 ES)以其高效的全文检索、分布式处理能力和灵活的查询语法,广泛应用于各类日志分析、用户行为分析以及实时数据查询等场景。通过 ES,用户…...

12.C语言中的struct详解:定义、赋值、指针、嵌套与位字段

目录 1.简介2.struct 的复制3.struct 指针4.struct 的嵌套5.位字段6.弹性数组成员 1.简介 本篇原文为:C语言中的struct详解:定义、赋值、指针、嵌套与位字段。 更多C进阶、rust、python、逆向等等教程,可点击此链接查看:酷程网 …...

文件读写到SQLite数据库的方法

在 SQLite 数据库中,将文件读写到数据库的常见方法主要有以下几种: 1. 将文件以 BLOB 类型存储 BLOB(Binary Large Object) 是 SQLite 中的二进制数据类型,可以直接用来存储文件内容。 步骤: 创建表 创建一…...

springboot项目部署至linux

1.修改pom.xml 确认是否有以下代码&#xff0c;没有请进行添加&#xff0c;mainClass改成你的启动类 <plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.ve…...

使用sed命令封装自定义dos2unix脚本

使用sed命令封装自定义dos2unix脚本 创建 `dos2unix` 脚本使用自定义的 `dos2unix` 脚本注意事项要将 sed -i 封装为一个简单的 dos2unix 脚本,你可以创建一个 Bash 脚本文件,该文件接受文件名作为参数,并使用 sed 命令来删除文件中的 DOS 回车符(\r)。以下是一个基本的实…...

从WWDC看苹果产品发展的规律

WWDC 是苹果公司一年一度面向全球开发者的盛会&#xff0c;其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具&#xff0c;对过去十年 WWDC 主题演讲内容进行了系统化分析&#xff0c;形成了这份…...

聊聊 Pulsar:Producer 源码解析

一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台&#xff0c;以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中&#xff0c;Producer&#xff08;生产者&#xff09; 是连接客户端应用与消息队列的第一步。生产者…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...

Java入门学习详细版(一)

大家好&#xff0c;Java 学习是一个系统学习的过程&#xff0c;核心原则就是“理论 实践 坚持”&#xff0c;并且需循序渐进&#xff0c;不可过于着急&#xff0c;本篇文章推出的这份详细入门学习资料将带大家从零基础开始&#xff0c;逐步掌握 Java 的核心概念和编程技能。 …...

根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:

根据万维钢精英日课6的内容&#xff0c;使用AI&#xff08;2025&#xff09;可以参考以下方法&#xff1a; 四个洞见 模型已经比人聪明&#xff1a;以ChatGPT o3为代表的AI非常强大&#xff0c;能运用高级理论解释道理、引用最新学术论文&#xff0c;生成对顶尖科学家都有用的…...

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

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

MySQL 知识小结(一)

一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库&#xff0c;分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷&#xff0c;但是文件存放起来数据比较冗余&#xff0c;用二进制能够更好管理咱们M…...

Linux 中如何提取压缩文件 ?

Linux 是一种流行的开源操作系统&#xff0c;它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间&#xff0c;使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的&#xff0c;要在 …...

Ubuntu Cursor升级成v1.0

0. 当前版本低 使用当前 Cursor v0.50时 GitHub Copilot Chat 打不开&#xff0c;快捷键也不好用&#xff0c;当看到 Cursor 升级后&#xff0c;还是蛮高兴的 1. 下载 Cursor 下载地址&#xff1a;https://www.cursor.com/cn/downloads 点击下载 Linux (x64) &#xff0c;…...

Unity中的transform.up

2025年6月8日&#xff0c;周日下午 在Unity中&#xff0c;transform.up是Transform组件的一个属性&#xff0c;表示游戏对象在世界空间中的“上”方向&#xff08;Y轴正方向&#xff09;&#xff0c;且会随对象旋转动态变化。以下是关键点解析&#xff1a; 基本定义 transfor…...