分布式技术原理与算法解析之分布式锁 学习笔记 (6)

分布式锁与分布式互斥的关系:

分布式互斥是在分布式系统中存在多个节点共享某个资源或临界区,任何时刻只允许一个进程访问资源或执行临界区,而分布式锁正好是解决分布式互斥的一种方法。

  • 问题定义:

一句话版:锁是实现多线程同时访问同一共享资源,保证在同一时刻只有一个线程可访问资源所做的一种标记。(锁的本质就是一个标记,通俗点是一个变量)

详细版本:(1)单机锁是多个线程共享的某个变量,操作共享资源前,需要先看这个变量是否为某个值,表示加锁或解锁。(2)分布式锁是多个进程共享的某个变量,其他的和单机锁类似,锁被存在公共存储中,以确保多个进程能看见锁,确保数据的一致性。

**说明:**当然,操作系统如果挂了,单机也就完全不可用了,如果操作系统没挂,多线程共享某个变量的控制通常是非常健壮的,分布式系统的特点是不会整个集群不可用,不过某台机器不可用的概率非常大,同时网络通信也是不可靠的,所以,分布式锁的可靠性就不好保证了,为了保证他的可靠性就需要引入集群,这样复杂性又会增多了。

设计分布式锁要考虑的问题:

(1)互斥性,一个资源在同一时间只能被同一机器的线程/进程操作。

(2)具备锁失效机制,防止死锁。

(3)可重入性,即进程未释放锁,可多次访问临界资源。

(4)高可用的获取锁和释放锁的功能,且性能要好。

  • 如何实现分布式锁?

基于关系型数据库实现分布式锁

创建一张锁表,通过操作该表的数据来实现,具体是为申请者在锁表建立一条记录,记录成功则获得锁,消除记录则释放锁。

  • 优点:简单。
  • 缺点:(1)单点故障:数据库完蛋,一切都完蛋。(2)死锁问题:数据库锁没有失效时间,若出现故障,其他进程无法获得锁。(3)频繁读写在硬盘上的数据库导致IO开销大。
  • 适用场景:并发量低,性能要求低。
    image.png
    基于缓存实现分布式锁

由于数据库的性能(硬盘上)限制了业务的并发量,而基于缓存实现分布式锁的方式,把数据存放在计算机内存中,不需要写入磁盘,减少了 IO 读写。

以 Redis 为例:(Redis通过队列来维持进程访问共享资源的先后顺序

Redis 通常可以使用 setnx(key, value) 函数来实现分布式锁,其中 key 表示锁 id,value = currentTime + timeOut(当前时间 + 超时时间),若某个进程获得 key 这把锁后,若在 value 的时间内未释放锁,系统就会主动释放锁。

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

返回 1,说明该服务器获得锁,setnx 将 key 对应的 value 设置为当前时间 + 锁的有效时间。

返回 0,说明其他服务器已经获得了锁,进程不能进入临界区。该服务器可以不断尝试 setnx 操作,以获得锁。

  • 优点:(1)性能更好;(2)缓存可跨集群部署;(3)易于实现。
  • 缺点:(1)锁失效的时间的控制不稳定。(2)可靠性不如ZooKeeper。
    基于ZooKeeper实现分布式锁

基于树形数据存储结构实现分布式锁,解决多个进程同时访问同一临界资源时,数据的一致性问题。

  1. 持久节点。这是默认的节点类型,一直存在于 ZooKeeper 中。
  1. 持久顺序节点。在创建节点时,ZooKeeper 根据节点创建时间顺序对节点编号。
  1. 临时节点。与持久节点不同,当客户端与 ZooKeeper 断开连接后,该进程创建的临时节点就会被删除。
  1. 临时顺序节点,就是按时间顺序编号的临时节点。
  • 流程:
    • 在与该方法对应的持久节点 shared_lock 的目录下,为每个进程创建一个临时顺序节点。如下图所示,吹风机就是一个拥有 shared_lock 的目录,当有人买吹风机时,会为他创建一个临时顺序节点。
    • 每个进程获取 shared_lock 目录下的所有临时节点列表,注册子节点变更的 Watcher,并监听节点。
    • 每个节点确定自己的编号是否是 shared_lock 下所有子节点中最小的,若最小,则获得锁。例如,用户 A 的订单最先到服务器,因此创建了编号为 1 的临时顺序节点 LockNode1。该节点的编号是持久节点目录下最小的,因此获取到分布式锁,可以访问临界资源,从而可以购买吹风机。
    • 若本进程对应的临时节点编号不是最小的,则分为两种情况:
      • a. 本进程为读请求,如果比自己序号小的节点中有写请求,则等待;
      • b. 本进程为写请求,如果比自己序号小的节点中有读请求,则等待。
        image.png
  • 优点:(1)无单点故障(2)可靠性高(3)易于实现(4)解决了数据库/缓存式锁的不足
  • 缺点:(1)性能没有缓存式分布式锁好(2)不易理解
  • 三种方式的比较
    image.png