minio / dsync:Go的分布式锁定和同步包

minio / dsync:Go的分布式锁定和同步包

minio / dsync是一个软件包,用于在n个节点的网络上进行分布式锁定它在设计时考虑了简单性,并提供了有限的可伸缩性(n <= 16)。每个节点都连接到所有其他节点,并且来自任何节点的锁定请求将广播到所有连接的节点。如果n / 2 + 1个节点的响应为正,则该节点将成功获得锁如果获得了锁,则可以将其保留只要客户需要的时间,然后需要将其释放。这将导致向所有节点广播解锁消息,此后锁定将再次变为可用。

动机

该软件包是为Minio Object Storage的分布式服务器版本开发的为此,我们需要一种简单可靠的分布式锁定机制,用于最多16台服务器,每台服务器都将运行minio服务器锁定机制本身应该是读取器/写入器互斥锁,这意味着它可以由单个写入器或任意数量的读取器持有。

对于minio,分布式版本的启动如下(例如,对于6服务器系统):

$ minio server server1/disk server2/disk server3/disk server4/disk server5/disk server6/disk

(请注意,应该在服务器server1到server6上运行相同的命令)

设计目标

  • 设计简单:通过保持设计简单,可以避免许多棘手的边缘情况。

  • 没有主节点:没有主节点的概念,如果使用主节点而主节点将关闭,则该主节点将导致锁定完全停止。(除非您的设计带有从属节点,但这会增加更多的复杂性。)

  • 弹性的:如果一个或多个节点发生故障,则其他节点不应受到影响,并且可以继续获取锁(假设不超过n / 2–1个节点发生故障)。

  • 可直接替换sync.RWMutex,并支持sync.Locker界面。

  • 自动重新连接到(重新启动)节点。

用法示例

下面是一个简单的示例,显示了如何使用dsync保护单个资源

import (
    "github.com/minio/dsync"
)

func lockSameResource() {

    // Create distributed mutex to protect resource 'test'
    dm := dsync.NewDRWMutex("test")

    dm.Lock()
    log.Println("first lock granted")

    // Release 1st lock after 5 seconds
    go func() {
        time.Sleep(5 * time.Second)
        log.Println("first lock unlocked")
        dm.Unlock()
    }()

    // Acquire lock again, will block until initial lock is released
    log.Println("about to lock same resource again...")
    dm.Lock()
    log.Println("second lock granted")

    time.Sleep(2 * time.Second)
    dm.Unlock()
}

运行时将提供以下输出:

2016/09/02 14:50:00 first lock granted
2016/09/02 14:50:00 about to lock same resource again...
2016/09/02 14:50:05 first lock unlocked
2016/09/02 14:50:05 second lock granted

(请注意,将其分布在多台计算机上运行会更有趣)。

除了写锁,dsync还支持多个读锁。请参阅此处的示例。

性能

对于同步包,性能当然是最重要的,因为它通常是相当频繁的操作。由于dsync自然涉及网络通信,因此性能将受到每秒可以交换的消息(或称为远程过程调用RPC的数量的限制

根据参与分布式锁定过程的节点数量,需要发送更多消息。例如,在8台服务器系统上,每次锁定和随后的解锁操作总共交换16条消息,而在16台服务器系统上,总共32条消息。

同样,由于同步机制是对(分布式)系统实际功能的补充操作,因此它不应消耗过多的CPU能力。

minio / dsync最多支持:

  • 在功能强大的服务器硬件上的16个节点(以10%的CPU使用率/服务器),每秒7500个锁

更多性能数字可以在这里找到

过时的锁和已知的缺陷

在分布式系统中,失效锁是实际上不再处于活动状态的节点上的锁。这可能是由于例如服务器崩溃或网络暂时不可用(部分网络中断)而导致的,例如,无法再发送解锁消息。

陈旧的锁通常不容易检测,并且它们可能通过阻止对资源的新锁而引起问题。minio / dsync具有失效锁定检测机制,该机制在某些条件下会自动删除失效锁定(有关更多详细信息,请参见此处)。

另一个潜在的问题是在资源上允许多个独占(写入)锁(因为多次并发写入可能导致数据损坏)。默认情况下,minio / dsync需要最少n / 2 + 1个基本锁的法定数量才能授予锁(通常,正常情况下,有更多或所有处于正常运行状态的服务器)。

但是,即使n / 2 + 1个节点的最小仲裁仅支持一个锁,也需要关闭两个节点才能允许授予对同一资源的另一个锁(前提是所有关闭的节点都是重新启动)。根据节点的数量,发生这种情况的机会会越来越小,因此虽然并非不可能,但极不可能发生这种情况。

这是一个更详细的示例,其中还包括一个表格,该表格列出了需要关闭或崩溃才能发生这种不良影响的节点总数。

更多要说的

当然,还有更多关于实现细节,扩展和其他潜在用例,与其他技术和解决方案的比较,限制等方面的信息。请访问github上的minio / dsync以了解更多信息。

如果您有任何意见,我们希望收到您的来信,我们也欢迎任何改进。

快乐分布式锁定!

上一篇 下一篇