1. 程式人生 > >用Etcd實現分散式鎖和選主

用Etcd實現分散式鎖和選主

Etcd的v3版本官方client裡有一個concurrency的包,裡面實現了分散式鎖和選主。本文分析一下它是如何實現的。

在code中註釋介紹了具體的實現。

//m.pfx是字首,比如"service/lock/"
//s.Lease()是一個64位的整數值,etcd v3引入了lease(租約)的概念,concurrency包基於lease封裝了session,每一個客戶端都有自己的lease,也就是說每個客戶端都有一個唯一的64位整形值
//m.myKey類似於"service/lock/12345"
m.myKey = fmt.Sprintf("%s%x", m.pfx, s.Lease())


//etcdv3新引入的多鍵條件事務,替代了v2中Compare-And
-put操作。etcdv3的多鍵條件事務的語意是先做一個比較(compare)操作,如果比較成立則執行一系列操作,如果比較不成立則執行另外一系列操作。有類似於C語言中的條件表示式。 //接下來的這部分實現瞭如果不存在這個key,則將這個key寫入到etcd,如果存在則讀取這個key的值這樣的功能。 //下面這一句,是構建了一個compare的條件,比較的是key的createRevision,如果revision是0,則存入一個key,如果revision不為0,則讀取這個key。 //revision是etcd一個全域性的序列號,每一個對etcd儲存進行改動都會分配一個這個序號,在v2中叫index,createRevision是表示這個key建立時被分配的這個序號。當key不存在時,createRivision是0
。 cmp := v3.Compare(v3.CreateRevision(m.myKey), "=", 0) put := v3.OpPut(m.myKey, "", v3.WithLease(s.Lease())) get := v3.OpGet(m.myKey) resp, err := client.Txn(ctx).If(cmp).Then(put).Else(get).Commit() if err != nil { return err } m.myRev = resp.Header.Revision if !resp.Succeeded { m.myRev = resp.Responses
[0].GetResponseRange().Kvs[0].CreateRevision } //如果上面的code操作成功了,則myRev是當前客戶端建立的key的revision值。 //waitDeletes等待匹配m.pfx"service/lock/")這個字首(可類比在這個目錄下的)並且createRivision小於m.myRev-1所有key被刪除 //如果沒有比當前客戶端建立的key的revision小的key,則當前客戶端者獲得鎖 //如果有比它小的key則等待,比它小的被刪除 err = waitDeletes(ctx, client, m.pfx, m.myRev-1)

總結一下,上面的鎖的實現,所有的客戶端都在service/lock下建立一個自己的key,createrevision最小的那個客戶端獲得鎖,也就是最早建立key的客戶端獲得鎖,之後按照建立的時間先後依次獲得鎖。