内容


sanlock 原理介绍及应用

一种灵活轻量的分布式锁管理器

Comments

介绍 sanlock

在分布式系统中,我们常常需要粗粒度的分布式锁。譬如,可以用锁来保证集群的领导节点的唯一性,或者用锁来同步对共享资源的使用。在这种场景下,分布式锁一般不会频繁的获取和释放,且一旦获得了锁,就会持有较长的时间。比如,集群的领导节点直到崩溃才需要重新选举,虚拟机的共享存储直到 Guest 关机才允许其他虚拟机使用。

sanlock 是一个基于 SAN 的分布式锁管理器。集群中的每个节点都各自运行 sanlock 服务,锁的状态都被写到了共享存储上,使用 Disk Paxos 算法读写共享存储以实现对分布式锁的获取、释放和超时。一般认为 SAN 中的 LUN 的可靠性要比集群中的主机高,对主机来说,应用程序进程可能会崩溃、重启,主机的 IP 网络也可能会发生故障,而 SAN 是通过专门的光网连接的,还可以配置多路径以提高可用性和吞吐量,一个 LUN 也可能被冗余映射到阵列中的多块磁盘上,因此 SAN 服务质量很高。通过利用 Disk Paxos 算法,sanlock 服务的所有数据都保存在共享存储上,即使服务器进程崩溃也不会影响可靠性。在一个集群里,通常 SAN 都是核心,可以认为如果 SAN 出现问题,整个集群的功能都会受到严重影响,因此选择以共享存储作为 sanlock 服务的基础是合理的。sanlock 的锁还可以冗余存储在多个来自不同的磁盘阵列的 LUN 上,每个 LUN 有各自的多路径,这样能够进一步提高可靠性。

oVirt 是一个开源的虚拟数据中心管理平台,可以管理虚拟机、虚拟网络,并且实现了跨节点的存储域以存放虚拟机镜像。oVirt 使用了 sanlock 作为其存储域的分布式锁管理器。oVirt 的存储域支持各种各样的后端,如 NFS、iSCSI、FCoE、GlusterFS 等。oVirt 的存储域是分布式的,由集群共同管理的,其中有一个节点充当了领导节点,领导节点失效时能自动选举新的领导。其中 sanlock 被用来保证领导节点的唯一性,并且用来保护共享存储设备上的存储域的元数据的一致性,以及保护同一个虚拟机镜像不会被两台虚拟机同时使用。oVirt 项目的存储域的 v1 版使用的是它自己实现的集群锁,其算法和 sanlock 的 Delta Lease(后文有介绍)是一样的。之后 oVirt 就开始使用更专业的 sanlock 来作为存储域 v3 的分布式锁。libvirt 是一个流行的虚拟化管理工具,也使用了 sanlock,它的 sanlock 插件可以在虚拟机启动前为所有的磁盘请求锁保护,以防止在意外情况下有两台虚拟机使用同一个磁盘镜像。请浏览参考资料以详细了解 sanlock 在 oVirt 和 libvirt 中的应用。

sanlock 原理

为了实现一个分布式锁管理器,一种比较简单直接的架构是运行若干的服务器,专门用来维护锁的状态、处理锁的分配,并在服务器集群之间通过 IP 网络同步锁的状态。客户端需要请求一个锁时,通过 IP 网络将请求发送给其中一个锁服务器。sanlock 则采用了不同的方法,在 sanlock 集群中,不存在专门的锁服务器或节点,每一个节点上都运行 sanlock 后台服务,所有的节点都是平等的。锁的状态被保存在共享存储上,sanlock 使用的共享存储既可以是通过 SAN 访问的 LUN,也可以是 NAS(比如 NFS 中的某个文件)。所有节点都能访问共享存储,共同维护锁的状态。另外,sanlock 的锁是名义锁,并非强制锁,其语义类似 pthread 的 mutex。被 sanlock 保护的对象,即使不上锁也能直接访问,完全由程序员自由决定 sanlock 的锁保护的是何种资源,以及何时上锁和释放。

Paxos Lease 和 Delta Lease

在分布式环境中,节点和进程都可能崩溃或者出现网络故障,因此锁都有一个租期,以便持有锁的节点的崩溃时,能自动释放锁。进程从 sanlock 请求上锁之后,sanlock 会自动每隔一段时间就对锁续租,所以在 sanlock 的文档中使用的术语租约(Lease)来代称锁。在 sanlock 中有两种不同的租约:Paxos Lease 和 Delta Lease。一个 Paxos Lease 就是一个带有时间戳的锁,用来保护一项抽象的资源。应用程序从 sanlock 获取的租约就是一个 Paxos Lease 的实例。Paxos Lease 是根据 Disk Paxos 算法实现的,这个算法是 Paxos 算法在 SAN 环境下的变种,它通过对共享存储的特定的顺序的读写操作实现对租约的获取、续租和释放。一旦获取了 Paxos Lease 后,sanlock 就自动为其续租。一个 Paxos Lease 实例的结构如图 1 所示。共享存储上的 Paxos Lease 实例被划分为与 sanlock 集群节点数相同数量的块。集群中的每个节点都可以写自己 ID 对应的块,但只能读其他节点对应的块。某节点要占有一个租约,只需要将请求写入自己对应的块,然后读取所有其他节点的块,查看是否有冲突。想要知道租约的当前所有者,只需要读取所有的块,找到最后被修改过的块并解析数据就可以了。图 1 中 Host ID 为 1 的主机成功获取了 Paxos Lease 后,Host ID 为 3 的主机在读取共享存储时,就能检测到冲突,判定为获取失败。同时,按照 Disk Paxos 算法,将正确的所有者编号写入自己的专有块,并递增提案编号。而 Host ID 为 2 的主机没有获取 Paxos Lease 的意向,则不必参与到事务中。读者可以浏览参考资料以详细了解 Paxos 算法的原理。

图 1. Paxos Lease 存储结构
Paxos Lease 存储结构
Paxos Lease 存储结构

另一种租约称为 Delta Lease,只由 sanlock 内部使用,不对外暴露,主要作用是保证节点 ID 的唯一性,并提供简单的成员管理服务。Delta Lease 用来确保特定的节点 ID 只能由唯一一个节点持有,并且每个 Delta Lease 只需要一个块就能实现。Delta Lease 是基于 Gregory Chockler 和 Dahlia Malkhi 的 04 年的一篇论文实现的(详见参考资料),简单来说,其原理是在向共享存储写完数据,并等待足够长的时间后再读,如果发现数据没有被起他节点更改,就认为没有冲突并成功获取了租约的所有权。把所有的 Delta Lease 磁盘块连续的保存在一个文件或者裸磁盘设备里,就形成了一个 sanlock 的 lockspace,其结构如图 2 所示。一个 lockspace 实例就相当于定义了一个 sanlock 集群及其租约的冲突域。每个节点通过在不同的 lockspace 中获取 Delta Lease,可以加入不同的 sanlock 集群。图 2 中,主机名为 hostA 的节点,已经成功获取了 Host ID 1 的 Delta Lease 后,hostB 通过读取 Delta Lease 的磁盘块,发现租约已经被占有,就无法再次获取。

图 2. lockspace 的存储结构
lockspace 的存储结构
lockspace 的存储结构

sanlock 的两种租约算法都是基于共享存储的,也都可以用来实现分布式锁。从原来上来说,Delta Lease 的获取需要比较长的时间,但比较省空间,而 Paxos Lease 则反之,获取时间短,但是占用大量空间,并且 Paxos Lease 缺乏对集群的成员管理的支持,所以两者形成互补。

Paxos 算法本质上是对各个节点的提案在集群范围内进行统一编号,所以 Paxos 算法要求所有的编号能形成线序、递增,并且互不相同。而提案的编号是由各个节点自行决定的,要避免不同的节点生成相同的编号,常见的产生提案编号的办法是,首先为每个节点分配一个全局唯一的 host_id,然后令提案的编号等于 host_id + n * max_hosts,其中 n = 1, 2, 3 … 假设我们有 max_hosts = 100 个节点,分别分配了 host_id 为 1,2,… ,100,于是 host_id 为 2 的节点产生的提案编号就是 102,202,302 等等,host_id 为 5 的节点生成的提案编号 105,205 等等。这就要求为每个节点分配唯一的 host_id。如果恰好有两个节点使用了同一个 host_id,Paxos Lease 就会乱套,因此需要用分布式锁对 host_id 本身进行保护,这时如果再使用 Paxos Lease,就变成一个现有鸡还是先有蛋的问题了。所以 sanlock 使用比较慢的 Delta Lease 来保护 host_id。同时,一个节点为自己 host_id 获取了 Delta Lease 后,sanlock 会自动的对其续租。由于所有的 Delta Lease 信息都保存在共享存储上,每个节点都可以读取其他节点的 Delta Lease 信息,判断对方是否在正常续租或者已经崩溃,因此 Delta Lease 也就提供了最基本的成员管理功能。

值的一提的是,成员管理功能是很多集群软件的基本功能之一,由于分布式计算本质的复杂性,实现动态的成员管理并非易事。sanlock 的 Delta Lease 则用十分简单的方法实现了这个功能。sanlock 默认认为集群有 2000 个节点(可以在 sanlock 集群启动之前配置),sanlock 会一口气直接在共享存储上开辟足够 2000 个节点使用 lockspace 所需要的空间。如果实际运行的集群不足 2000 个节点,那部分空间就浪费了,而且无法区分一个 host_id 不再被使用还是它对应的节点崩溃了。所以 Delta Lease 的成员管理功能实际上是非常简单的。前文提到 Paxos 算法是让所有节点发起提案并投票,而一个投票是需要半数以上成员通过才能生效的,使用 Delta Lease,无法区分一个 host_id 是没被使用还是其节点崩溃,所以也就无法计算总的成员数目,进而也无法得知多少个节点才算是半数。对于 Paxos 算法来说,这是一个绕不过去的坎,Paxos 算法的可靠性是建立在有过半数节点在线这个前提上。Disk Paxos 是 Paxos 算法的变种。Disk Paxos 算法把共享存储当作多个节点之间共享的白板,无所谓有多少个节点在线,只要共享存储在线就行了,并且可以为 Disk Paxos 配置多个冗余的共享存储,如图 3 所示。只要过半数的共享存储设备在线,Disk Paxos 就能继续运行。因此基于 Disk Paxos 算法的 Paxos Lease 可以利用 Delta Lease 提供的 host_id 唯一性作为保证,同时也不受制于 Delta Lease 的成员管理功能不足。

图 3. 为 sanlock 配置冗余存储和数据链路
为 sanlock 配置冗余存储和数据链路
为 sanlock 配置冗余存储和数据链路

sanlock 和 Persistent Reservations 的对比

SCSI-3 标准引入了 Persistent Reservations 功能,如果 iSCSI Target 存储设备支持 Persistent Reservations,就可以实现和 sanlock 类似的以 SAN 为中心的锁服务。相比起来,sanlock 的好处是对后端存储没有任何特殊的要求,既支持 SAN,也只是 NAS,也就是说既可以将锁数据保存在 LUN 上,也可以保存在一个 NFS 导出的某个文件上。sanlock 的所有功能都是纯软件的实现,使用起来也很简单,既适用于拥有专业存储设备的数据中心,也适合低成本的小集群。另外,sanlock 虽然使用的是以节点为所有者为分配单位的 Disk Paxos 算法,但是在同一台主机上的进程的锁请求都是通过 sanlock 服务进程来同步的,因此 sanlock 可以跟踪某一个锁是否已经被分配,进而禁止多次分配同一个锁,所以 sanlock 是以进程为单位分配锁的。在虚拟化的数据中心中,每个虚拟机都是主机上的一个进程,应用服务也是运行在虚拟机里的进程。使用 sanlock,既可以以虚拟机为单位,也可以以应用服务进程为单位分配锁,灵活性比 Persistent Reservations 高。Persistent Reservations 一般由存储控制器通过 SCSI 指令实现,运行效率高,且其实现的锁是强制锁,而 sanlock 的锁仅仅是建议锁。Persistent Reservations 和 sanlock 各有千秋,应该在理清上层应用所需要的灵活性、成本、可靠性之后选择最恰当的方案。要详细了解 Persistent Reservations 在 IBM 存储产品中的应用,可以浏览参考资料

wdmd 和 Fence

wdmd 的全称是 watchdog multiplexing daemon,是 sanlock 项目中的一个子项目,功能是复用系统的 watchdog 设备。watchdog 设备是主机上的硬件设备,如果没有安装硬件,也可以加载软件实现的 softdog 内核模块。watchdog 设备准备好后,内核会生成/dev/watchdog 设备节点。打开/dev/watchdog 设备节点后,一个进程可以定时向 watchdog 设备发送保活心跳,如果太长时间没有发送保活心跳,watchdog 设备就会判断进程或者主机本身出了问题,将主机重启。不便的是 watchdog 设备只有一个,而需要监控的主机健康条件可能却有多个。而如果有多个服务器进程需要向 watchdog 设备发送心跳,它们可以打开 wdmd 的 Unix socket,向 wdmd 服务进程发送心跳,而实际的 watchdog 设备由 wdmd 守护进程负责操作。只要有一个 wdmd 连接超时,wdmd 就会停止向系统 watchdog 设备发送心跳,导致系统重启。要了解 watchdog 的相关详细信息,可以浏览参考资料

sanlock 在启动后会打开一个 wdmd 连接,定时发送保活心跳。sanlock 同时会监视获取了 Paxos Lease 的进程,如果进程崩溃了,sanlock 就会自动将 Paxos Lease 释放。如果由于某种原因导致 sanlock 无法访问共享存储,sanlock 就无法续租,这时 sanlock 会自动向持有 Paxos Lease 的进程发 SIGTERM 或者 SIGKILL。也可以配置 sanlock 的 killpath 参数,在无法续租的时候,让 sanlock 调用 killpath 指向的程序。如果由于种种原因,sanlock 无法关闭持有 Paxos Lease 的进程,sanlock 就不会再向 wdmd 发送保活更新,于是 watchdog 设备会在系统保活更新超时后,重启整台主机。有了 wdmd 的配合,sanlock 就能对有问题的节点或进程进行自我 fence。

fence 是高可用的集群的一项必备功能。我们总是为高可用的服务配备多个主机,在其中一个主机崩溃或者失去联系时,集群会自动在另外的主机上启动相同的服务进程。但是我们在实践中一般很难区分“节点太忙以致联络超时”、“网络故障以致联络超时”、“节点崩溃以致联络超时”、“集群网络出现分区”等几种情况。如果只是暂时联络超时,而这个主机的服务还是在继续运行,集群在新的节点上启动同一个服务的话,可能会出现两个相同服务的不同实例使用同一个共享资源(比如同一个数据库文件)的情况,导致共享资源损坏。因此当一个节点发现自己有故障之后,应该能够自我 fence,通过将自己重启来退出并重新加入集群。我们可以认为 sanlock 在连接不上存储时的重启行为看成是自我 fence。

集群控制逻辑也会主动将有问题的节点 fence 出集群,可以将其 SAN 链路关闭,或者通过电源管理硬件将有问题的节点重启。最近 sanlock 项目中增加了新功能 fence_sanlock,支持通过竞争 Paxos Lease 对某台主机主动 fence,这样就可以在现有的集群管理软件(譬如 cman)里把 sanlock 当作 fence agent 使用,相当于为 fencing 提供了一种新的渠道。

fence_sanlock 的工作流程如图 4 所示。首先每台主机上都运行 fence_sanlockd 和 sanlock,fence_sanlockd 会向 sanlock 租用一个用于保护“hX”的 Paxos Lease,其中“X”是节点的 ID,并且打开一个 wdmd 连接。当集群控制软件需要主动将某个问题节点 fence 出去时,可以在任意的主机上通过 fence_sanlock 尝试获取代表目标节点的名为“hX”的 Paxos Lease,当然,如果目标节点还在运行,Paxos Lease 是无法成功获取的(图 4 中的步骤 1 到 3)。但是目标节点的 sanlock 在续租的时候,会发现该 Paxos Lease 被其他节点尝试请求过一次,于是 sanlock 就向 fence_sanlockd 发送信号 SIGUSR1(图 4 中的步骤 4 和 5)。fence_sanlockd 收到信号后,知道自己变成了 victim 节点,于是就不再向 wdmd 发送心跳,最终导致 watchdog 设备将主机重启(图 4 中的步骤 6 和 7)。被隔离的主机重启后,不再续组其对应的 Paxos Lease,其他主机上的 fence_sanlock 就能成功获取此 Paxos Lease,并判定为隔离成功(图 4 中的步骤 8 和 9)。如果读者想试试这种 fence 方式,可以查看 fence_sanlock 的帮助手册,里面包含了配置 cman 的所需要的步骤。

图 4. 使用 fence_sanlock 隔离节点
使用 fence_sanlock 隔离节点
使用 fence_sanlock 隔离节点

例子:使用 sanlock 建立简单的 HA 服务

通过之前的讨论,我们对 sanlock 的功能和限制都有了一定了解。本节将利用 sanlock 建立一个非常简单的高可用服务 simpleHA。simpleHA 的目的是示范 sanlock 的用法,不适用于生产系统。

假设我们有一个应用服务,需要有高可用性保证。在集群范围内该应用只需要一个实例,当该应用崩溃后,应该能由 simpleHA 自动重新启动,当其所运行的节点崩溃后,其他节点应能够自动再启动该服务的实例。我们的思路是,在 sanlock 中建立一个代表该应用的租约,在所有的节点上都运行 simpleHA。simpleHA 首先请求这个租约,如果能成功获得租约,就运行一个应用的实例,如果不能获得租约,就休眠一段实现然后继续尝试。

配置共享存储

sanlock 的使用的共享存储既可以是块设备(比如 iSCSI 和 FC 的 LUN),也可以是文件(比如 NFS 上的一个文件),出于配置的简单性考虑,本例子使用 NFS。那么我们首先建立一个 NFS 导出点,然后在两台不同的主机上,挂载这个 NFS 导出点,命令如清单 1(假设 192.168.133.0/24 是我们的集群的内网)。如果希望导出点能够在系统启动时自动挂载,可以把这个挂载点加入/etc/fstab。

清单 1. 挂载共享存储
mount -t nfs 192.168.133.1:/nfs /mnt/sanlock_share/

接着运行清单 2 中的命令,在两台主机上都安装 sanlock 和 sanlock-python 软件包。sanlock-python 是 sanlock 客户端程序库的 Python 绑定,能够让 Python 程序请求 sanlock 的租约。在 Debian 和 Ubuntu 的官方软件仓库上,sanlock 的版本比较老,读者可以到作者的 PPA 上下载新版本 sanlock 的 deb 软件包,详见参考资料

清单 2. 安装 sanlock
yum install sanlock sanlock-python

接着,初始化 sanlock 的 lockspace。前文提到过,所谓 lockspace,其实就是保存所有对 host_id 的 Delta Lease 数据的一块存储区域。一个 lockspace 就是一个 sanlock 集群的实例。在其中一台主机上运行清单 3 中的命令。

清单 3. 初始化 lockspace
dd if=/dev/zero bs=1048576 count=1 of=/mnt/sanlock_share/idLease
sanlock direct init -s LS:0:/mnt/sanlock_share/idLease:0
chown sanlock:sanlock /mnt/sanlock_share/idLease

接着,初始化我们用来保护 HA 服务的租约。在其中一台主机上运行清单 4 中的命令。

清单 4. 初始化资源租约
dd if=/dev/zero bs=1048576 count=1 of=/mnt/sanlock_share/leaderLease
sanlock direct init -r LS:leader:/mnt/sanlock_share/leaderLease:0
chown sanlock:sanlock /mnt/sanlock_share/leaderLease

高可用服务的编写和运行

现在 sanlock 需要的后端存储已经准备好了,让我们来看看 simpleHA 的代码,如清单 5,用 Python 语言编写。

清单 5. simpleHA.py 的源代码
#!/usr/bin/python
import sys
import time
from multiprocessing import Process

import sanlock


# simpleHA 主程序,加入 sanlock 集群并尝试获取 Paxos Lease
def serviceMain(hostId, lockspacePath, leasePath):
    sfd = sanlock.register()  # 把本进程注册到 sanlock 服务上
    while True:
        try:
            # 若尚未加入 sanlock 集群,则尝试获取对 hostId 的 Delta Lease
            # 并尝试加入 sanlock 集群
            if not sanlock.inq_lockspace("LS", hostId, lockspacePath):
                print "Try to acquire host id LS:%s:%s:0" % (hostId,
                                                             lockspacePath)
                sanlock.add_lockspace("LS", hostId, lockspacePath)

            # 尝试获取 Delta Lease
            print "Try to acquire leader lease LS:leader:%s:0" % leasePath
            sanlock.acquire("LS", "leader", [(leasePath, 0)], sfd)
        except sanlock.SanlockException:
            # 无法加入集群,或无法获取 Delta Lease
            # 10 秒后重试
            print "Failed to acquire leases, try again in 10s."
            time.sleep(10)
        else:
            break  # 成功获取 Paxos Lease,不再重试

    # 成功加入了 sanlock 集群并获取了 Paxos Lease
    # 执行实际的应用服务
    serve()

# 假想的应用服务程序,一段时间后自行崩溃
def serve():
    for i in range(6):
        print time.strftime("%Y %m %Z %H:%M:%S"), "Service is running"
        time.sleep(10)

    print time.strftime("%Y %m %Z %H:%M:%S"), "Service crashed"

if __name__ == "__main__":
    try:
        hostId = int(sys.argv[1])
        lockspacePath = sys.argv[2]
        leasePath = sys.argv[3]
    except Exception:
        sys.stderr.write(
            "Usage: %s host_id lockspace_path lease_path\n" % sys.argv[0])
        exit(1)

    # 每隔 15 秒就尝试启动新进程并运行一次 serviceMain 主程序
    while True:
        p = Process(target=serviceMain,
                    args=(hostId, lockspacePath, leasePath))
        p.start()
        p.join()
        time.sleep(15)

simpleHA.py 接受 3 个参数,分别是 host_id,lockspace 的路径和 Paxos lease 的路径。simpleHA 在启动后,首先尝试在 lockspace 中为其 host_id 获取一个 Delta Lease,这是通过调用 sanlock.add_lockspace() 实现的。在获取了 Delta Lease 之后,sanlock 会自动为我们续约,因此我们不必每次都重新获取,只需要检查一下 Delta Lease 是否正常就行了,这是通过调用sanlock.inq_lockspace()实现的。对同一个 host_id,sanlock.add_lockspace()只会在一台主机上成功。

拿到了 host_id 的 Delata Lease 之后,我们调用 sanlock.acquire()尝试获取一个 Paxos Lease。sanlock.acquire()只会在一台主机的一个进程上成功,所以只要 sanlock.acquire()成功了,我们就可以运行实际的服务了,在例子中我们是调用了 serve()函数。serve 函数运行一个假想的关键服务,为了模拟在真正的 HA 场景下服务崩溃的情况,我们让 serve()运行 1 分钟后自行退出。serve()退出后,sanlock 就自动释放了其对应的 Paxos Lease,于是其他节点便有机会获取到这个 Paxos Lease 并且启动后备的serve()服务。

我们在两台主机 A 和 B 上,分别执行清单 6 中的命令。其中命令参数“1”和“2”分别是我们为主机 A 和 B 指定的节点 ID。这样我们的 simpleHA 就在两台主机上都启动了。

清单 6. 启动 simpleHA
机器 A
./simpleHA.py 1 /mnt/sanlock_share/idLease /mnt/sanlock_share/leaderLease
机器 B
./simpleHA.py 2 /mnt/sanlock_share/idLease /mnt/sanlock_share/leaderLease

主机 A 的输出类似于清单 7。

清单 7. 主机 A 成功占有租约并运行服务
Try to acquire host id LS:1:/mnt/sanlock_share/idLease:0
Try to acquire leader lease LS:leader:/mnt/sanlock_share/leaderLease:0
2013 11 CST 01:14:48 Service is running
2013 11 CST 01:14:58 Service is running
2013 11 CST 01:15:08 Service is running

输出表明主机 A 的 simpleHA.py 成功获得了 host_id = 1 和 Paxos Lease,运行了我们的serve()应用。

同时,主机 B 上的输出类似于清单 8。

清单 8. 主机 B 不断尝试获取租约
Try to acquire host id LS:2:/mnt/sanlock_share/idLease:0
Try to acquire leader lease LS:leader:/mnt/sanlock_share/leaderLease:0
Failed to acquire leases, try again in 10s.
Try to acquire leader lease LS:leader:/mnt/sanlock_share/leaderLease:0
Failed to acquire leases, try again in 10s.
Try to acquire leader lease LS:leader:/mnt/sanlock_share/leaderLease:0

输出表明主机 B 的 simpleHA.py 获得了 host_id = 2,但是没有获得 Paxos Lease,于是它便一直重试。

一分钟后,我们的serve()就应该自行崩溃了,于是我们看到主机 A 在清单 9 中的输出。

清单 9. 主机 A 上模拟服务崩溃
2013 11 CST 01:15:48 Service crashed
Try to acquire leader lease LS:leader:/mnt/sanlock_share/leaderLease:0
Failed to acquire leases, try again in 10s.
Try to acquire leader lease LS:leader:/mnt/sanlock_share/leaderLease:0
Failed to acquire leases, try again in 10s.
Try to acquire leader lease LS:leader:/mnt/sanlock_share/leaderLease:0

同时,主机 B 输出清单 10 中的内容。

清单 10. 主机 B 自动重新启动服务
2013 11 CST 01:15:48 Service is running
2013 11 CST 01:15:58 Service is running
2013 11 CST 01:16:08 Service is running

这表明主机 A 的 serve()崩溃后,sanlock 释放了 Paxos Lease,于是主机 B 的 simpleHA.py 成功获取了 Paxos Lease 并启动了后备的 serve()应用。

我们还可以在更多的机器上运行 simpleHA.py,也可以随时在让新的节点上启动 simpleHA.py,或者在原有节点上关闭 simpleHA.py,不会对 serve()造成 10 秒以上的中断,也不需要特别的成员管理。借助于 sanlock,我们使用五十多行 Python 代码就实现了一个简单的高可用应用的骨架。

小结

sanlock 是一个基于 Disk Paxos 算法的分布式锁管理器,配置和使用十分简单,既可以被高级的集群软件用来实现 fence 功能,也可以直接使用它实现简单的 HA 功能。oVirt 的新特性 hosted Engine 就是使用 sanlock 实现的 HA。sanlock 的优点是灵活可靠,支持多种后端存储,对硬件没有很高的要求,可以通过配置多个后端来提高可靠性,有简单的成员管理功能。本文介绍了 sanlock 的原理和特性,并举例实现了一个基于 sanlock 的 HA 服务框架。


相关主题


评论

添加或订阅评论,请先登录注册

static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=10
Zone=Linux
ArticleID=968294
ArticleTitle=sanlock 原理介绍及应用
publish-date=04172014