分布式锁 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

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

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

相关文章

【Excel/WPS】根据平均值,生成两列/多列指定范围的随机数/随机凑出两列数据

原理就是通过随机生成函数和平均值函数。 适用场景:在总体打分后,需要在小项中随机生成小分数 第一列:固定的平均值A2第二列: RANDBETWEEN(A2-10,A210)第三列:根据第二列用平均值函数算除 A2*2-B2这是随机值1的公式&am…

运动相机拍摄的视频打不开怎么办

3-10 GoPro和大疆DJI运动相机的特点,小巧、高清、续航长、拍摄稳定,很多人会在一些重要场合用来拍摄视频,比如可以用来拿在手里拍摄快速运动中的人等等。 但是毕竟是电子产品,有时候是会出点问题的,比如意外断电、摔重…

智能化文档开发(DI)

这个文档涉及到多模态(文本、发票、订单、语音) 对于普通的文本,我们希望对某些实体的某些属性挖空生成文档模版,并根据预设字段填空最后生成正式文件对于发票、订单,我们想提取它的字段信息,写入DB对于一些…

【轻松学C:编程小白的大冒险】--- C语言简介 02

在编程的艺术世界里,代码和灵感需要寻找到最佳的交融点,才能打造出令人为之惊叹的作品。而在这座秋知叶i博客的殿堂里,我们将共同追寻这种完美结合,为未来的世界留下属于我们的独特印记。 【轻松学C:编程小白的大冒险】…

零基础 监控数据可视化 Spring Boot 2.x(Actuator + Prometheus + Grafana手把手) (上)

一、安装Prometheus Releases prometheus/prometheus GitHubhttps://github.com/prometheus/prometheus/releases 或 https://prometheus.io/download/https://prometheus.io/download/ 1. 下载适用于 Windows 的二进制文件: 找到最新版本的发布页面&#xf…

Idea日志乱码

问题描述 前提:本人使用windows Idea运行sh文件,指定了utf-8编码,但是运行过程中还是存在中文乱码 Idea的相关配置都已经调整 字体调整为雅黑 文件编码均调整为UTF-8 调整Idea配置文件 但是还是存在乱码,既然Idea相关配置已经…

MySQL 数据表与索引设计艺术:打造高效数据存取架构

🐇明明跟你说过:个人主页 🏅个人专栏:《MySQL技术精粹》🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、什么是MySQL 2、MySQL适用场景 二、MySQL的数据存储与检索 1、数据表…

安卓硬件加速hwui

安卓硬件加速 本文基于安卓11。 从 Android 3.0 (API 级别 11) 开始,Android 2D 渲染管道支持硬件加速,这意味着在 View 的画布上执行的所有绘图操作都使用 GPU。由于启用硬件加速所需的资源增加,你的应用程序将消耗更多内存。 软件绘制&am…

海信116英寸RGB-Mini LED:一朵绽放在科技穹顶的中国花火

东方古镇的打铁花,拉斯维加斯的烟花秀,盛大的花火表演总会在岁末年初的时候,吸引世界各地人们的目光。一年一度的科技展会,也起到烟花秀一样的作用,让人们提前望见未知的精彩。 CES还没开始,CES 2025展会的…

积分漏斗模型中5个指标统计

缘起 最近遇到一个积分漏斗模型的设计,这里记录一下。以防止以后忘记了。其中毕竟关键的属性是: 获得积分可用积分已有积分 积分漏斗模型 这里随着【当前日期】也就是今天日期。随着时间一天天过去,积分也一天天过去。上面那个【填报时间】…

Ubuntu挂载Windows 磁盘,双系统

首先我们需要在终端输入这个命令,来查看磁盘分配情况 lsblk -f 找到需要挂载的磁盘,检查其类型( 我的/dev/nvme2n1p1类型是ntfs,名字叫3500winData) 然后新建一个挂载磁盘的目录,我的是/media/zeqi/3500wi…

Web渗透测试之XSS跨站脚本攻击 跨域是什么?同源机制又是什么? cors以及Jsonp是什么 一篇文章给你说明白

目录 Cookie的Httponly属性和逃过方式 浏览器同源机制 cors跨域和jsonp跨域和跨域标签 Cors跨域 - 跨源 Jsonp 跨域 jsonp跨域原理: 说明: Cookie的Httponly属性和逃过方式 Xss攻击手段 最常用的目的获取cookie Cookie中设置了 httponlyTrue 方式js操作获…

【C++】字符串的 += 和 + 运算详解

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C 文章目录 💯前言💯1. 字符串的 和 基本用法1.1 的用法1.2 的用法 💯2. 示例代码的剖析与解释代码分析 💯3. 底层实现与性能分析3.1 的实现原理3.2 的实现原理3.…

CCLINK转MODBUS-TCP协议转换网关模块应用案例

大家好,今天我们要聊的是生产管理系统中的CCLINK和MODBUS-TCP协议,它们的不同使得数据互通比较困难,但捷米特JM-CCLK-TCP网关的出现改变了这一切。 为了实现整个生产线的协同工作,需要这些设备之间能够进行有效的数据交换和指令传…

Go学习:多重赋值与匿名变量

1. 变量的多重赋值 1.1 基本语法格式 go语言中,可以将多个赋值语句 合并成 一句,比如: a : 10 b : 20 c : 30//a,b,c三个变量的赋值语句可以简练成以下格式a, b, c : 10, 20, 30 1.2 交换变量值 当需要交换两个变量的值时&#…

Spring——依赖注入之p命名空间和c命名空间

p命名空间 其实就是Set注入 只不过p命名空间写法更简洁 p可以理解为 property标签的首字母p p命名空间依赖于set方法 依赖引入 使用前需要再配置文件头文件中引入p命名空间的依赖: ** xmlns:p“http://www.springframework.org/schema/p” ** 用法 在bean标签…

【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基本命令 先…

【Vue.js 组件化】高效组件管理与自动化实践指南

文章目录 摘要引言组件命名规范与组织结构命名规范目录组织 依赖管理工具自动化组件文档生成构建自动引入和文档生成的组件化体系代码结构自动引入组件配置使用 Storybook 展示组件文档自动生成 代码详解QA 环节总结参考资料 摘要 在现代前端开发中,组件化管理是 V…

【Arthas命令实践】heapdump实现原理

🎮 作者主页:点击 🎁 完整专栏和代码:点击 🏡 博客主页:点击 文章目录 使用原理 使用 dump java heap, 类似 jmap 命令的 heap dump 功能。 【dump 到指定文件】 heapdump arthas-output/dump.hprof【只 …

继承(补充)

大家好,今天补充一下继承上执行顺序的一点知识点,(编者这两天要完成学院任务可能有点敷衍,抱歉抱歉),那么我们来看看。 [继承关系上的执行顺序] 1、父类静态代码优先于子类静态代码块执行,且是最早执行. …