草庐IT

《分布式技术原理与算法解析》学习笔记Day07

技术修行者 2023-04-17 原文

分布式锁

什么是分布式锁?

为了实现分布式互斥,我们需要在某个地方做个标记,这个标记是每个线程都可以看到,当标记不存在时可以设置该标记,当标记被设置后,其他线程只能等待拥有该标记的线程执行完成,并释放该标记后,才能去设置该标记和访问共享资源。这里的标记就是我们讨论的锁。

锁就是在多线程同时访问同一资源的场景下,为了让线程互不干扰地访问共享资源,从而保证操作的有效性和正确性的一种标记。

分布式锁是指在分布式环境下,系统部署在多个机器中,实现多进程分布式互斥的一种锁。为了保证多个进程都可以看到锁,锁需要通过公共存储来管理,这样才能实现多个进程并发访问同一个临界资源,同一个时刻只有一个进程可访问共享资源,确保数据的一致性。

我们在设计分布式锁时要考虑的因素有哪些?

以下几点需要考虑:

  1. 互斥性,对于某一共享资源,需要保证在同一时间只能有一个线程或进程对该资源进行操作。
  2. 具备锁失效机制,防止死锁。
  3. 可重入性,即进程未释放锁时,可以多次访问临界资源。
  4. 有高可用的获取锁和释放锁的功能,且性能要好。

常见的分布式锁实现方法有哪些?

实现分布式锁有3种主流的方法:

  • 基于数据库实现分布式锁
  • 基于缓存实现分布式锁
  • 基于ZooKeeper实现分布式锁

基于数据库实现分布式锁

基于数据库实现分布式锁比较简单,主要在于创建一张锁表,为申请者在锁表中建立一条记录,记录建立成功则获得锁,消除记录则释放锁。

因为需要频繁访问磁盘,IO开销会比较大,因此这种方式适用于并发量低、对性能要求低的场景。

这种方式有两个缺点:

  1. 单点故障问题,一旦数据库不可用,会导致整个系统崩溃。
  2. 死锁问题,数据库锁没有失效时间,未获得锁的进程只能一致等待已获得锁的进程主动释放锁,如果已获得共享资源访问权限的进程忽然挂了,或者解锁操作失败,那么锁记录会一直存储在数据库中,无法删除,而其他进程也无法获得锁,从而造成死锁。

基于缓存实现分布式锁

所谓基于缓存,也就是说把数据存放在计算机内存中,不需要写入磁盘,减少IO读写。

我们经常使用Redis来作为缓存方案,使用setnx(key, value)函数实现分布式锁。key和value就是基于缓存的分布式锁的两个属性,其中key表示锁id,value=currentTime + timeOut,表示当前时间+超时时间。

setnx函数的返回值有0和1:

  • 返回1,说明该服务器获得锁,setnx将key对应的value设置为当前时间+锁的有效时间
  • 返回0,说明其他服务已经获得锁,进程不能进入临界区

Redis通过碎裂来维持进程访问共享资源的先后顺序,Redis锁主要基于setnx函数实现分布式锁,当进程通过setnx<key,value>函数返回1时,表示已经获得锁。排在后面的进程只能等待前面的进程主动释放锁,或者等到时间超时才能获得锁。

这种方案的优点在于:

  1. 性能更好,访问内存要比访问磁盘快很多。
  2. 可以集群部署,避免了单点故障问题。
  3. 使用方便,很多缓存服务都提供了可以用来实现分布式锁的方法。
  4. 可以直接设置超时时间来控制锁的释放。

这种方案的缺点是通过超时时间来控制锁的失效时间并不是十分可靠,因为一个进程执行时间可能比较长,或受系统进程做内存回收等影响,导致时间超时,从而不正确的释放了锁。

这种方案适用于高并发、对性能要求高的场景。

基于ZooKeeper的分布式锁

ZooKeeper的树形数据存储结构主要由4种节点构成:

  • 持久节点,默认节点类型。
  • 持久顺序节点,在创建节点时,ZooKeeper根据节点创建的时间顺序对节点进行编号处理。
  • 临时节点,当客户端与ZooKeeper断开连接后,对应进程创建的临时节点就会被删除。
  • 临时顺序节点,按时间顺序编号的临时节点。

ZooKeeper基于临时顺序节点实现了分布锁。

ZooKeeper实现分布式锁的流程:

  1. 在持久节点shared_lock目录下,为每个进程创建一个临时顺序节点。
  2. 每个进程获取shared_lock目录下的所有临时节点列表,注册Watcher,用于监听子节点变更的信息。当监听到自己的临时节点是顺序最小的,则可以使用共享资源。
  3. 每个节点确定自己的编号是否是shared_lock下所有子节点中最小的,如果是最小的,就能获得锁。
  4. 如果进程对应的临时节点编号不是最小的,那么有两种情况:
    • 本进程为读请求,如果比自己序号小的节点中有写请求,则等待。
    • 本进程为写请求,如果比自己序号小的节点中有请求,则等待。

使用ZooKeeper实现的分布式锁,可以解决前两种方法提到的各种问题,比如单点故障、不可重入、死锁等,但是该方法实现比较复杂,且需要频繁的添加和删除节点,所以性能不如基于缓存实现的分布式锁。

这种方案适用于大部分分布式场景,但是不适用于对性能要求极高的场景。

三种不同的分布式锁,详细的区别如下表所示。

分布式锁中的羊群效应

所谓羊群效应,就是在整个ZooKeeper分布式锁的竞争过程中,大量的进程都想要获得锁去使用共享资源。每个进程都有自己的Watcher来通知节点消息,都会获取整个子节点列表,使得信息冗余,资源浪费。

当共享资源被解锁后,ZooKeeper会通知所有监听的进程,这些进程都会尝试争取锁,但最终只能有一个进程获得锁,使得其他进程产生了大量的不必要的请求,造成了巨大的通信开销,造成网络阻塞,性能下降。

如何解决?分为三步:

  1. 在与该方法对应的持久节点目录下,为每个进程创建一个临时顺序节点。
  2. 每个进程获取所有临时节点列表,对比自己的编号是否最小,如最小,则获得锁。
  3. 若本进程对应的临时节点编号不是最小的,则注册Watcher,监听自己的上一个临时顺序节点,当监听到该节点释放锁后,则获取锁。

有关《分布式技术原理与算法解析》学习笔记Day07的更多相关文章

  1. ruby - 分布式事务和队列,ruby,erlang,scala - 2

    我有一个涉及多台机器、消息队列和事务的问题。因此,例如用户点击网页,点击将消息发送到另一台机器,该机器将付款添加到用户的帐户。每秒可能有数千次点击。事务的所有方面都应该是容错的。我以前从未遇到过这样的事情,但一些阅读表明这是一个众所周知的问题。所以我的问题。我假设安全的方法是使用两阶段提交,但协议(protocol)是阻塞的,所以我不会获得所需的性能,我是否正确?我通常写Ruby,但似乎Redis之类的数据库和Rescue、RabbitMQ等消息队列系统对我的帮助不大——即使我实现某种两阶段提交,如果Redis崩溃,数据也会丢失,因为它本质上只是内存。所有这些让我开始关注erlang和

  2. 区块链之加解密算法&数字证书 - 2

    目录一.加解密算法数字签名对称加密DES(DataEncryptionStandard)3DES(TripleDES)AES(AdvancedEncryptionStandard)RSA加密法DSA(DigitalSignatureAlgorithm)ECC(EllipticCurvesCryptography)非对称加密签名与加密过程非对称加密的应用对称加密与非对称加密的结合二.数字证书图解一.加解密算法加密简单而言就是通过一种算法将明文信息转换成密文信息,信息的的接收方能够通过密钥对密文信息进行解密获得明文信息的过程。根据加解密的密钥是否相同,算法可以分为对称加密、非对称加密、对称加密和非

  3. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  4. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  5. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

  6. MIMO-OFDM无线通信技术及MATLAB实现(1)无线信道:传播和衰落 - 2

     MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO

  7. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

  8. ruby - 我正在学习编程并选择了 Ruby。我应该升级到 Ruby 1.9 吗? - 2

    我完全不是程序员,正在学习使用Ruby和Rails框架进行编程。我目前正在使用Ruby1.8.7和Rails3.0.3,但我想知道我是否应该升级到Ruby1.9,因为我真的没有任何升级的“遗留”成本。缺点是什么?我是否会遇到与普通gem的兼容性问题,或者甚至其他我不太了解甚至无法预料的问题? 最佳答案 你应该升级。不要坚持从1.8.7开始。如果您发现不支持1.9.2的gem,请避免使用它们(因为它们很可能不被维护)。如果您对gem是否兼容1.9.2有任何疑问,您可以在以下位置查看:http://www.railsplugins.or

  9. ruby - 我如何学习 ruby​​ 的正则表达式? - 2

    如何学习ruby​​的正则表达式?(对于假人) 最佳答案 http://www.rubular.com/在Ruby中使用正则表达式时是一个很棒的工具,因为它可以立即将结果可视化。 关于ruby-我如何学习ruby​​的正则表达式?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/1881231/

  10. ruby-on-rails - 用于门户的 Ruby 技术 - 2

    我刚刚看到whitehouse.gov正在使用drupal作为CMS和门户技术。drupal的优点之一似乎是很容易添加插件,而且编程最少,即重新发明轮子最少。这实际上正是Ruby-on-Rails的DRY理念。所以:drupal的缺点是什么?Rails或其他基于Ruby的技术有哪些不符合whitehouse.org(或其他CMS门户)门户技术的资格? 最佳答案 Whatarethedrawbacksofdrupal?对于Ruby和Rails,这确实是一个相当主观的问题。Drupal是一个可靠的内容管理选项,非常适合面向社区的站点。它

随机推荐