美文网首页
分布式锁简介

分布式锁简介

作者: rhuanhuan | 来源:发表于2020-09-21 10:37 被阅读0次

本文的代码: github地址

摘要

现实中经常遇到并发写问题。并发下的程序有可见性、原子性、有序性的问题。如果不能保证,执行结果可能会不可控。
对于单体结构有硬件、操作系统、程序内存模型等同步机制,来对并发写进行控制;分布式系统就得自己来控制了。
逻辑本质上都是一样的,

  1. 有一个能在分布式系统里面共享的标记作为锁
  2. 对这个锁的添加要是原子操作,包括判断是否已经有锁,再来决定是否加锁的过程
    就可以实现分布式锁了。
    不同的实现方式在性能、一致性上有不同的保证,可以根据项目实际情况来选取。
    其他的各种边界细节问题,比如如何保证加锁各种操作的原子性,如何避免死锁,如何保证可重入性,等等,因此通常借用成熟的框架来解决问题。

问题?

现实中难免遇到并发写问题。并发下的程序有可见性、原子性、有序性的问题。如果不能保证,执行结果可能会不可控。

例如以简单的秒杀场景为例,通常的操作是:

  1. 读库存
  2. 减库存
  3. 写库存
    如果不同机器上的线程T1和线程T2都在秒杀,并且读库存时候读到了同一个初始库存 initInventory;
    那么当他们两都买完之后, 商家实际卖了2个,但写进去的库存initInventory - 1,相当于库存只减了一份,就会导致超卖;

对于单体结构还好,以Java为例,有硬件、操作系统、JVM内存模型等同步机制,来对并发写进行控制;
如果在多个机器上(分布式)的时候,就得自己来控制了。

如何实现?

程序在并发控制时候,通过各种锁机制,来保障可见性、原子性、有序性的问题。
因此,可以预料到实现的过程,类似于Java并发的流程控制, 也是通过类似地锁机制来实现。

实现方案

简单地说,当遇到并发写问题的时候,给共享变量上锁,只让一个线程占有锁来执行操作,就可以避免并发写问题。


分布式锁流程

基于以上逻辑,如果

  1. 有一个能在分布式系统里面共享的标记作为锁
  2. 并且对这个锁的添加要是原子操作,包括判断是否已经有锁,再来决定是否加锁的过程
    • 这样才不会遇到加锁解锁操作的并发写问题,从而陷入鸡生蛋蛋生鸡的循环;
    • 加锁这个过程其实就是一个CAS操作, 逻辑细节就不赘述了;
      就可以实现分布式锁了。

因此,业内有很多实现方案,比如基于数据库MySQL的,基于Redis的,基于Zookeeper的,等等。
Redis作为一个内存数据库有着不错的性能,以及虚假的强一致性,因此采用比较多;
Zookeeper作为一个真正的强一致性保证的产品,性能相对Redis没那么高,但是在对一致性要求高的时候,是首选项。

Redis实现

主要指令:

  1. setnx; Set if not Exist. 原子操作。key 不存在返回1, key 存在了就返回 0。能够保证加锁的原子性
  2. expire; 设置过期时间, 给分布式锁设置过期时间, 保证程序崩溃也能释放锁,避免一直锁着
  3. getset; 原子的。获取key并设置新值, 返回之前的值。(不存在的话就是null)
    这些指令也就像上面说的,保证加锁解锁过程的原子性。

那么加锁之后有没有其他问题呢?

问题1: SETNX 之后,还没设置 EXPIRE 程序就挂了,就会产生一个死锁

使用SETNX 自带的 EXPIRE 原子操作。很老的redis(2.8版本之前)不支持,稍微新一点的redis就可以了。

问题2: 设置 EXPIRE 之后,线程A因为一些原因还没执行完,锁就被解除了,从而线程B开始执行,又导致了并发写,以及线程A后面可能解锁线程B加的锁

问题流程如下:


误解除锁

对于超时时间到了,程序还没执行完的问题,一般有两种方式解决该问题:

  1. 将过期时间设置足够长,确保代码逻辑在锁释放之前能够执行完成。
  2. 增加额外的线程。获得锁的线程开启一个守护线程,用来给快要过期的锁“续航”。。

对于线程B可以解锁线程A的锁的问题:
通过在 value 中设置当前线程加锁的标识, 例如生成一个 UUID 标识当前线程,在删除之前验证 key 对应的 value 判断锁是否是当前线程持有。

问题3: 线程重入的问题

使用getset 来计数

使用 Redission 框架

上面提到了分布式锁的很多细节问题,如果自己来维护就会很麻烦,因此通常可以借用成熟的框架来,比如Redission
Redission具体使用起来的接口就跟Reentranlock很像了,使用起来很方便,直接lock,unlock就行。可以直接参考代码库里面的用法或者官方文档。

参考文献:

  1. Redission分布式锁和同步器

相关文章

网友评论

      本文标题:分布式锁简介

      本文链接:https://www.haomeiwen.com/subject/dixvyktx.html