用Etcd實現分布式鎖和選主

2021-09-23 17:49:51 字數 1537 閱讀 2617

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

先貼一下鎖的code (

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

是字首,比如"service/lock/"

是乙個64位的整數值,etcd v3引入了lease(租約)的概念,concurrency包基於lease封裝了session,每乙個客戶端都有自己的lease,也就是說每個客戶端都有乙個唯一的64位整形值

類似於"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

m.myrev = resp.header.revision

if !resp.succeeded

//如果上面的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的客戶端獲得鎖,之後按照建立的時間先後依次獲得鎖。

選主(的實現與鎖的實現非常類似,這裡就不做詳述了。

etcd實現分布式鎖

我們希望同一時間只有乙個執行緒能夠訪問到資源,但是分布式資源點之間的協調會非常麻煩,這個時候我們就需要乙個分布式鎖。etcd分布式鎖實現原理 1.利用租約在etcd集群中建立乙個key,這個key有兩種形態,存在和不存在,而這兩種形態就是互斥量。2.如果這個key不存在,那麼執行緒建立key,成功則...

etcd 分布式鎖實現原理

每個mutex會建立乙個租約lease,並且租約是長期有效的 使用prefix leaseid作為key向etcd插入資料 etcd確保每次插入的key都有乙個位移的createrevision,並且createrevision是從0開始遞增的 第2條規定所有mutex按照prefix leasei...

用redis實現分布式鎖

通常部署的服務都是在多台伺服器上,不會只有一台。那麼在分布式環境下,就會遇到共享資源的問題。比如乙個人只能有一條記錄,下次進來就只能修改,而不是再新增。如果只有一台伺服器,可以使用多執行緒下的單例模式來控制,但是分布式下,就不管用了。有三種方式,一是使用資料庫的樂觀鎖,二是redis的鎖,三是zoo...