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以了解更多信息。
如果您有任何意见,我们希望收到您的来信,我们也欢迎任何改进。
快乐分布式锁定!