07|分布式锁:所有的分布式锁都是错误的?

2022-02-11 陈现麟
《深入浅出分布式技术原理》
课程介绍


讲述:张浩

时长:大小14.28M


你好,我是陈现麟。
通过学习“配置中心”的内容,你已经理解了在分布式系统中,为什么需要配置中心,以及怎么去实现一个设计良好的配置中心,现在,你终于不用再为管理极客时间后端各种服务的配置而烦恼了,这是一件值得高兴的事情。
但是,在极客时间后端系统快速迭代的过程中,你发现了一个服务中的代码逻辑问题:在有些场景下,你并不想让所有的实例都一起运行,只需要一个实例运行就够了,比如在用户生日当天,给用户发的祝福短信等类似定时通知的情况。
目前同一个服务的所有实例都是对等的,只能每一个实例都运行。如果将这个服务运行的实例修改为一个,虽然能解决刚才讨论的问题,但是这个实例就变成了一个单点,会面临性能瓶颈和单点故障的风险。
这真是一个两难的问题,我们应该如何解决呢?其实,这个问题的本质在于,我们希望同一个服务的多个实例,按照一定的逻辑来进行协同,比如刚才讨论的定时任务的逻辑。那么多个实例在同一时刻只能有一个实例运行,它就是一个典型的分布式锁的场景。
所以,在本节课中,我们将从“为什么需要分布式锁”,“怎...

展开全文
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。

精选留言

  • 啊树
    2022-02-13
    建议老师结合目前主流组件介绍哪些组件如何运用这些知识点,不然有点懵,不知道能干嘛

    作者回复: 我觉得学习技术可以分两个维度: 
1、一个原理论上或者广度上的,通过了解技术的业务场景、解决问题的原理和方案,以及这个技术需要注意和思辨的地方来掌握这个技术,这样在我们碰到这个业务场景是,能立即明白这是什么问题,应该怎么解决,难度和注意点是什么。一般来说,一些技术上不正确的决策,都是由于这些知识盲区导致的。 2、另一个是实践上或者深度上的,在业务上确定需要这个技术的时候,依据之前的理论知识,对开源项目进行选型或者选择自研都可以。这一部分可以在有需要的时候再做,现在可以先快速拓宽知识的边界。 一般理论上的知识会比较稳定,不容易过时,而具体项目的实现,首先项目本身会迭代而改变,另外后面也会有其他新的项目出来,是会快速改变的。所以这个专栏主要是对技术原理上的讨论,这个部分是需要对这个方向有一定经验的人来总结的,如果你对某一个知识点非常感兴趣,那么在学习好技术原理后,可以对你感兴趣的一个或几个项目来做具体的分析,一定会受益匪浅。

    
    18
  • Jxin
    2022-02-25
    1.大部分时候控制好超时间隔,防止删除别人的锁,满足可重入和嵌套锁其实就好了。其他的概率靠对账去兜,roi问题。 2.有现成资源,无脑redis。有特殊性能要求,可以基于db走乐观锁。 3.懂的听起来没难度,不懂的可能有点抽象。而且这块东西感觉听懂了具体实现也就理解了上面提炼的所有思路。反而直接理解思路对新手可能会难些。对于幼儿,身体和意识是一体的。怎么讲取决于人群,和理解效率。分布式锁这个其实可以拿具体存储在多场景的实现方式的利弊来讲。抽象的知识依赖具象的实例来呈现。
    
    5
  • 刘章
    2022-03-06
    高可用我会选zookeeper,要求不高,选Redis

    作者回复: 👍👍

    
    2
  • 葡萄糖sugar
    2022-02-11
    “但是因为响应超时,客户端以为自己没有获取锁的情况发生。这样一来,依然会在一定程度上,影响锁的互斥语义的正确性”。老师,这段我不是很理解,为什么会影响到锁的互斥?客户端以为自己没有获得过锁,然后另一个竞争锁的客户端会尝试获得锁,此时并不会出现同时拥有同一个锁的问题,那为什么还会影响锁的互斥呢?

    作者回复: 这里的意思是指互斥语义是一定能保证同一时刻有一个客户端能获取锁的,但是现在的情况是所有的客户端都不能获取到锁。

    
    1
  • 魏颖琪
    2022-02-11
    心跳+超时机制的方式,提到“因为响应超时,客户端以为自己没有获取锁的情况发生。”这会在超时时间内,浪费了锁,但不认为会“影响锁的互斥语义的正确性”,请问老师,这具体怎么理解,怎么会影响锁的互斥语义的正确性?

    作者回复: 这里的意思是指互斥语义是一定能保证同一时刻有一个客户端能获取锁的,但是现在的情况是所有的客户端都不能获取到锁。

    共 3 条评论
    1
  • 李二木
    2022-05-23
    可以总结下zk和redis锁的优缺点和如何选择吗?现在网上的说发版本太多了。
    
    
  • 面试官问
    2022-04-26
    https://github.com/baomidou/lock4j 这个开源的分布式锁组件还不错。
    
    1
  • 约书亚
    2022-04-13
    当初看martin kleppmann与antirez的争论,学到了不少东西

    作者回复: 👍

    
    
  • GaryYu
    2022-04-10
    什么情况会发生 响应超时客户端以为没获取锁 但锁服务已经颁发锁 若响应超时客户端不会返回error给锁服务让这次获取锁失败吗?

    作者回复: 比如 锁服务 的逻辑颁发锁成功,但是通过网络到客户端的时候发生丢包,还没有重试的时候,客户端已经超时了,或者是客户端已经收到锁,但是响应发送到锁服务的时候超时了。 对于锁服务来说,它不能区分超时是发生在客户端收到锁之前还是锁之后。

    
    
  • 好好学习,跳槽大厂
    2022-03-23
    “但是因为响应超时,客户端以为自己没有获取锁的情况发生。这样一来,依然会在一定程度上,影响锁的互斥语义的正确性” 对于可重入锁这个问题有什么好的解决办法吗? 是不是可以在获取锁之前先查询自身是否拥有锁已经重入的次数,获取超时后需要再查询重入次数,如果+1了就相当于已经获得锁了,否则继续获取锁。

    作者回复: 可重入锁是锁的实现,业务层可以不关心是否重入了。

    
    
  • 好好学习,跳槽大厂
    2022-03-23
    “但是因为响应超时,客户端以为自己没有获取锁的情况发生。这样一来,依然会在一定程度上,影响锁的互斥语义的正确性”
    
    
  • 处女座♍️
    2022-03-17
    结合业务实践,项目初步阶段用redis作为分布式锁,业务量上来后考虑安全可用会改成zk,不过目前redis能满足80%业务。。

    作者回复: 几乎不是要求非常高正确性的场景,都可以用Redis,不过业务量上来后,换成zk要好好评估,zk的性能比Redis要差了一个数量级。 比较好的方式还是以性能和正确性来选择分布式锁,课程中有讨论。

    
    
  • 王子凡kerry
    2022-02-21
    老师,如果etcd作为分布式锁,我能想到的是网络分区时,少数节点会有问题。还有其他方面的问题吗?

    作者回复: etcd做分布式锁,在存储上的选择是没有问题,已经是一致性最好的存储了。 文章讨论的是分布式锁的正确性问题:一般在这种情况下,锁服务在进程加锁成功后,会设置一个超时时间,如果进程持有锁超时后,将锁再颁发给其他的进程,就会导致一把锁被两个进程持有的情况出现,使锁的互斥语义被破坏。

    
    
  • HappyHasson
    2022-02-16
    请教老师: “在单机情况下,我们可以非常方便地通过操作系统提供的机制,来正确判断一个进程是否存活,比如,父进程在获得进程挂掉的信号后,可以去查看当前挂掉的进程是否持有锁,如果持有就进行释放” ----老师能否举个例子,我没在实际项目中见到过这种实现。父进程需要知道子进程的具体逻辑才能帮忙释放锁吧?

    作者回复: 可以在加锁成功的时候,写入当前获得锁的进程ID,这样父进程在子进程崩溃的时候,去检查一下当前锁是否为挂掉的子进程持有的,如果是的,就释放锁。

    
    
  • 陈阳
    2022-02-15
    老师 对于这些问题,如果我们获得锁是为了写一个共享存储,那么有一种方案可以解决上面的问题,那就是在获得锁的时候,锁服务生成一个全局递增的版本号,在写数据的时候,需要带上版本号。共享存储在写入数据的时候,会检查版本号,如果版本号回退了,就说明当前锁的互斥语义出现了问题,那么就拒绝当前请求的写入,如果版本号相同或者增加了,就写入数据和当前操作的版本号。 什么情况下会出现版本号回退?

    作者回复: 比如 a 操作或者锁了,并且版本号为 1,但是由于 GC 等原因,操作被挂起了。在 a 操作挂起的时候,锁过期了,b操作又获得了锁,版本号为 2,并且写入成功。这个时候,a 操作已经恢复了,再进行写入操作的时候,就会出现版本回退的问题。

    
    
  • bearlu
    2022-02-14
    老师,现在分布式锁有什么开源解决项目?

    作者回复: 可以在 github 上搜索 “distributed lock”,上面有不少项目,不过没有见到特别知名的,可能的原因有: 1、一般的框架中都集成了分布式锁,不需要单独引入; 2、不同的分布式锁的实现的性能差别非常大,并且这些差别主要是存储系统的选择上面,和实现逻辑关系不大; 3、实现的代码量也不大,很多时候大家也不想因为分布式锁再引入一个项目

    共 2 条评论
    
  • shuff1e
    2022-02-13
    请教老师: 所以,我认为对于在共享存储中写入数据等等,完全不能容忍分布式锁互斥语义失败的情况,不应该借助分布式锁从外部来实现,而是应该在共享存储内部来解决。 在共享存储内部解决什么问题?和文章中所说的fencing token有什么关系?
    展开

    作者回复: 我们往共享存储中写入数据的正确性: 一种是从外部通过 fencing token 来保证,其实是一种抽象泄漏。 另一种是由共享存储自身来保证,所有的分布式数据库都是这样做的,这样的抽象对使用者更友好。

    
    
  • peter
    2022-02-11
    请教老师两个问题: Q1:不同的服务会有分布式锁的问题吗? 文章中从相同服务的不同实例提出分布式锁的问题,那么,不同服务之间是否也有分布式锁的问题? Q2:锁的可重入性,是指获得锁的线程还在处理,没有释放锁之前再次获得锁吗?如果是这样,算不算是代码的错误呢?因为获得锁的线程并没有处理完,不应该去再次获取锁。

    作者回复: Q1:分布式锁是解决分布式场景下的临界区互斥的问题,不同的服务也可能会出现这样的情况的,只不过在实际工作中很少出进行这样的设计,因为这样会导致这些服务之间紧耦合。 Q2:是同一个线程是没有问题的,当然能避免这样的情况会让代码的可读性更强。

    
    
  • 陈迪
    2022-02-11
    思考题,存储系统需要1 强一致 2 容忍部分结点失败,来保障还不错的可用性

    作者回复: 对的,对于分布式锁我们需要尽可能提高它的正确性,所以存储系统的强一致性是必须的,容忍部分结点失败,来保障还不错的可用性也是必须的

    
    