(面试高频)分布式锁

什么是锁

普通的锁,即在单机多线程环境下,当多个线程需要访问同一个变量或代码片段时,被访问的变量或代码片段叫做临界区域,我们需要控制线程一个一个的顺序执行,否则会出现并发问题。
如何控制呢?就是设置一个各个线程都能看的见的标志。然后,每个线程想访问临界区域时,都要先查看标志,如果标志没有被占用,则说明目前没有线程在访问临界区域。如果标志被占用了,则说明目前有线程正在访问临界区域,则当前线程需要等待。
这个标志,就是
在单机多线程的java程序中,我们可以使用堆内存中的变量作为标志,因为多线程是共享堆内存的,堆内存中的变量对于各个线程都是可见的。

分布式锁

在分布式环境下,即多台计算机,每个计算机上会启动jvm执行程序的运行环境下,如果不同计算机上的线程想访问临界区域时,该怎么办呢?
前面普通锁的使用堆内存中的变量的方式肯定不适用了。因为在多机环境下,某台计算机上的堆内存中的变量对于其他计算机上的线程肯定是不可见的。那么,根据锁的本质和原理,我们就要找到另外的对于多机上的线程都可见的标志,以它来作为锁,就可以了。这样的锁,就是分布式锁。
当然,这里只是解释了什么是分布式锁,至于分布式锁该如何实现,其实有多重方式,关键在于要保证锁对多机上的程序是可见的即可。

分布式锁应该具备哪些条件?

1. 在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行;
2. 高可用的获取锁与释放锁;
3. 高性能的获取锁与释放锁;
4. 具备可重入特性;
5. 具备锁失效机制,防止死锁;
6、具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败。

场景描述

现实生活中一种常见的场景,抢票。抢票系统一般为适应高并发性,会将服务部署多套(以承载瞬间的大并发场景),分布式锁控制不好,往往会出现超买情况。

那么我们分以下三种方案来分析分布式锁的设计:

1. 数据库乐观锁

  • 适用于中小型系统
  • 实现方式有:主键、唯一性索引、版本等等
  • 需要考虑某个分布式系统抢到锁之后,自己挂了,会造成锁无法释放,即死锁。则在库中为该锁设置有效时长
  • 接上场景需要考虑抢到锁的分布式系统,其执行的时间长,可能会比锁的有效期长,即锁过期,任务还未执行完毕。则使用守护线程为锁续时长(看门狗)

2. Redis

  • 适用于千万级系统

2.1. setnx
直接利用setnx,执行完业务逻辑后调用del释放锁,简单粗暴
缺点:如果setnx成功,还没来得及释放,服务挂了,那么这个key永远都不会被获取到,从而造成死锁

2.2. setnx设置一个过期时间
为了改正2.1。的缺陷,我们用setnx获取锁,然后用expire对其设置一个过期时间,如果服务挂了,到了过期时间自动释放
缺点:
①setnx和expire是两个方法,不能保证原子性,如果在setnx之后,还没来得及expire,服务挂了,还是会出现锁不释放的问题;
②还会导致当前的线程释放其他线程占有的锁;

2.3. set k v ex tm nx
redis官方为了解决2.2.存在的缺点,在v2.8版本为set指令添加了扩展参数nx和ex,保证了setnx+expire的原子性,使用方法:
set key value ex 5 nx
缺点:
①如果在过期时间内,事务还没有执行完,锁提前被自动释放,其他的线程还是可以拿到锁,出现超卖;
可以通过看门狗,定时续时长来解决

2.4. 加一个事务id
对于2.2.中的第二个缺点,可以理解为当前线程有可能会释放其他线程的锁,那么问题就转换为保证线程只能释放当前线程持有的锁,即setnx的时候将value设为任务的唯一id,释放的时候先get key比较一下value是否与当前的id相同,是则释放,否则抛异常回滚
缺点:get key和将value与id比较是两个步骤,不能保证原子性

2.5. Redis集群(主从)
会出现系统刚获得分布式锁,此时主Redis宕机(数据还未同步到从节点),也会出现超卖,一次Redis的创始人提出了RedLock算法。

2.6. RedLock
这个场景是假设有一个 redis cluster,有 5 个 redis master 实例(一定是奇数个,他们之间无主从关系,都是相互独立的)。然后执行如下步骤获取一把锁:

a. 获取当前时间戳,单位是毫秒;
b. 轮流尝试在每个 master 节点上创建锁,过期时间较短,一般就几十毫秒;
c. 尝试在大多数节点上建立一个锁,比如 5 个节点就要求是 3 个节点` n / 2 + 1`;
d. 客户端计算建立好锁的时间,如果建立锁的时间小于超时时间,就算建立成功了(设置一个请求过期时间re和锁的过期时间le,同时re必须小于le);
e. 要是锁建立失败了,那么就依次之前建立过的锁删除;
f. 只要别人建立了一把分布式锁,你就得不断轮询去尝试获取锁。

缺点:RedLock原图链接

RedLock.png

3. ZooKeeper

  • 利用临时节点特性
    zookeeper的临时节点有两个特性,一是节点名称不能重复,二是会随着客户端退出而销毁,因此直接将key作为节点名称,能够成功创建的客户端则获取成功,失败的客户端监听成功的节点的删除事件
    缺点:所有客户端监听同一个节点,但是同时只有一个节点的事件触发是有效的,造成资源的无效调度
  • 利用顺序临时节点特性
    zookeeper的顺序临时节点拥有临时节点的特性,同时,在一个父节点下创建创建的子临时顺序节点,会根据节点创建的先后顺序,用一个32位的数字作为后缀,我们可以用key创建一个根节点,然后每次申请锁的时候在其下创建顺序节点,接着获取根节点下所有的顺序节点并排序,获取顺序最小的节点,如果该节点的名称与当前添加的名称相同,则表示能够获取锁,否则监听根节点下面的处于当前节点之前的节点的删除事件,如果监听生效,则回到上一步重新判断顺序,直到获取锁。
  • ZK也难以逃脱Full GC的宿命(超出心跳时间,也就释放锁,即出现超卖)

总结

  • 基于jdk的并发工具自己实现的锁
    优点:不需要引入中间件,架构简单
    缺点:编写一个可靠、高可用、高效率的分布式锁服务,难度较大
  • redis set px nx + 唯一id + lua脚本
    优点:redis本身的读写性能很高,因此基于redis的分布式锁效率比较高
    缺点:依赖中间件,分布式环境下可能会有节点数据同步问题,可靠性有一定的影响,如果发生则需要人工介入。分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能
  • 基于redis的redlock
    优点:可以解决redis集群的同步可用性问题
    缺点:依赖中间件,并没有被广泛验证,维护成本高,需要多个独立的master节点;需要同时对多个节点申请锁,降低了一些效率
  • 基于zookeeper的分布式锁
    优点:分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小
    缺点:依赖中间件

没有绝对完美的实现方式,具体要选择哪一种分布式锁,需要结合每一种锁的优缺点和业务特点而定。
忘记在哪里看到过一句话:过度追求设计完美,是一种心理疾病

参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容