成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一篇帶給你etcd與分布式鎖

開發 前端 分布式
可以提供分布式鎖功能的組件有多種,但是每一種都有自己的脾氣與性格。至于選擇哪一種組件,則要看數據對業務的重要性,數據要求強一致性推薦支持CP的etcd、zookeeper,數據允許少量丟失、不要求強一致性的推薦支持AP的Redis。

[[400328]]

1. 實現分布式鎖的組件們

在分布式系統中,常用于實現分布式鎖的組件有:Redis、zookeeper、etcd,下面針對各自的特性進行對比:

由上圖可以看出三種組件各自的特點,其中對于分布式鎖來說至關重要的一點是要求CP。但是,Redis集群卻不支持CP,而是支持AP。雖然,官方也給出了redlock的方案,但由于需要部署多個實例(超過一半實例成功才視為成功),部署、維護比較復雜。所以在對一致性要求很高的業務場景下(電商、銀行支付),一般選擇使用zookeeper或者etcd。對比zookeeper與etcd,如果考慮性能、并發量、維護成本來看。由于etcd是用Go語言開發,直接編譯為二進制可執行文件,并不依賴其他任何東西,則更具有優勢。本文,則選擇etcd來討論某些觀點。

2. 對于分布式鎖來說AP為什么不好

在CAP理論中,由于分布式系統中多節點通信不可避免出現網絡延遲、丟包等問題一定會造成網絡分區,在造成網絡分區的情況下,一般有兩個選擇:CP or AP。

① 選擇AP模型實現分布式鎖時,client在通過集群主節點加鎖成功之后,則立刻會獲取鎖成功的反饋。此時,在主節點還沒來得及把數據同步給從節點時發生down機的話,系統會在從節點中選出一個節點作為新的主節點,新的主節點沒有老的主節點對應的鎖數據,導致其他client可以在新的主節點上拿到相同的鎖。這個時候,就會導致多個進程/線程/協程來操作相同的臨界資源數據,從而引發數據不一致性等問題。

② 選擇CP模型實現分布式鎖,只有在主節點把數據同步給大于1/2的從節點之后才被視為加鎖成功。此時,主節點由于某些原因down機,系統會在從節點中選取出來數據比較新的一個從節點作為新的主節點,從而避免數據丟失等問題。

所以,對于分布式鎖來說,在對數據有強一致性要求的場景下,AP模型不是一個好的選擇。如果可以容忍少量數據丟失,出于維護成本等因素考慮,AP模型的Redis可優先選擇。

3. 分布式鎖的特點以及操作

對于分布式鎖來說,操作的動作包含:

  1. 獲取鎖
  2. 釋放鎖
  3. 業務處理過程中過程中,另起線程/協程進行鎖的續約

4. 關于etcd

官方文檔永遠是最好的學習資料,官方介紹etcd如是說:

  • 分布式系統使用etcd作為配置管理、服務發現和協調分布式工作的一致鍵值存儲。許多組織使用etcd來實現生產系統,如容器調度器、服務發現服務和分布式數據存儲。使用etcd的常見分布式模式包括leader選舉、分布式鎖和監視機器活動。
  • Distributed systems use etcd as a consistent key-value store for configuration management, service discovery, and coordinating distributed work. Many organizations use etcd to implement production systems such as container schedulers, service discovery services, and distributed data storage. Common distributed patterns using etcd include leader election, distributed locks, and monitoring machine liveness.
  • https://etcd.io/docs/v3.4/learning/why/

分布式鎖僅是etcd可以實現眾多功能中的一項,服務注冊與發現在etcd中用的則會更多。

官方也對眾多組件進行了對比,并整理如下:

通過對比可以看出各自的特點,至于具體選擇哪一款,你心中可能也有了自己的答案。

5. etcd實現分布式鎖的相關接口

對于分布式鎖,主要用到etcd對應的添加、刪除、續約接口。

  1. // KV:鍵值相關操作 
  2. type KV interface { 
  3.     // 存放. 
  4.     Put(ctx context.Context, key, val string, opts ...OpOption) (*PutResponse, error) 
  5.     // 獲取. 
  6.     Get(ctx context.Context, key string, opts ...OpOption) (*GetResponse, error) 
  7.     // 刪除. 
  8.     Delete(ctx context.Context, key string, opts ...OpOption) (*DeleteResponse, error) 
  9.     // 壓縮rev指定版本之前的歷史數據. 
  10.     Compact(ctx context.Context, rev int64, opts ...CompactOption) (*CompactResponse, error) 
  11.     // 通用的操作執行命令,可用于操作集合的遍歷。Put/Get/Delete也是基于Do. 
  12.     Do(ctx context.Context, op Op) (OpResponse, error) 
  13.     // 創建一個事務,只支持If/Then/Else/Commit操作. 
  14.     Txn(ctx context.Context) Txn 
  15.  
  16.  
  17. // Lease:租約相關操作 
  18. type Lease interface { 
  19.     // 分配一個租約. 
  20.     Grant(ctx context.Context, ttl int64) (*LeaseGrantResponse, error) 
  21.     // 釋放一個租約. 
  22.     Revoke(ctx context.Context, id LeaseID) (*LeaseRevokeResponse, error) 
  23.     // 獲取剩余TTL時間. 
  24.     TimeToLive(ctx context.Context, id LeaseID, opts ...LeaseOption) (*LeaseTimeToLiveResponse, error) 
  25.     // 獲取所有租約. 
  26.     Leases(ctx context.Context) (*LeaseLeasesResponse, error) 
  27.     // 續約保持激活狀態. 
  28.     KeepAlive(ctx context.Context, id LeaseID) (<-chan *LeaseKeepAliveResponse, error) 
  29.     // 僅續約激活一次. 
  30.     KeepAliveOnce(ctx context.Context, id LeaseID) (*LeaseKeepAliveResponse, error) 
  31.     // 關閉續約激活的功能. 
  32.     Close() error 

 6. etcd實現分布式鎖代碼示例

  1. package main 
  2.  
  3. import ( 
  4.     "context" 
  5.     "fmt" 
  6.     "go.etcd.io/etcd/clientv3" 
  7.     "time" 
  8.  
  9. var conf clientv3.Config 
  10.  
  11. // 鎖結構體 
  12. type EtcdMutex struct { 
  13.     Ttl int64//租約時間 
  14.  
  15.     Conf   clientv3.Config    //etcd集群配置 
  16.     Key    string//etcd的key 
  17.     cancel context.CancelFunc //關閉續租的func 
  18.  
  19.     txn     clientv3.Txn 
  20.     lease   clientv3.Lease 
  21.     leaseID clientv3.LeaseID 
  22.  
  23. // 初始化鎖 
  24. func (em *EtcdMutex) init() error { 
  25.     var err error 
  26.     var ctx context.Context 
  27.  
  28.     client, err := clientv3.New(em.Conf) 
  29.     if err != nil { 
  30.         return err 
  31.     } 
  32.  
  33.     em.txn = clientv3.NewKV(client).Txn(context.TODO()) 
  34.     em.lease = clientv3.NewLease(client) 
  35.     leaseResp, err := em.lease.Grant(context.TODO(), em.Ttl) 
  36.  
  37.     if err != nil { 
  38.         return err 
  39.     } 
  40.  
  41.     ctx, em.cancel = context.WithCancel(context.TODO()) 
  42.     em.leaseID = leaseResp.ID 
  43.     _, err = em.lease.KeepAlive(ctx, em.leaseID) 
  44.  
  45.     return err 
  46.  
  47. // 獲取鎖 
  48. func (em *EtcdMutex) Lock() error { 
  49.     err := em.init() 
  50.     if err != nil { 
  51.         return err 
  52.     } 
  53.  
  54.     // LOCK 
  55.     em.txn.If(clientv3.Compare(clientv3.CreateRevision(em.Key), "=", 0)). 
  56.         Then(clientv3.OpPut(em.Key"", clientv3.WithLease(em.leaseID))).Else() 
  57.  
  58.     txnResp, err := em.txn.Commit() 
  59.     if err != nil { 
  60.         return err 
  61.     } 
  62.  
  63.     // 判斷txn.if條件是否成立 
  64.     if !txnResp.Succeeded { 
  65.         return fmt.Errorf("搶鎖失敗"
  66.     } 
  67.  
  68.     returnnil 
  69.  
  70. //釋放鎖 
  71. func (em *EtcdMutex) UnLock() { 
  72.     // 租約自動過期,立刻過期 
  73.     // cancel取消續租,而revoke則是立即過期 
  74.     em.cancel() 
  75.     em.lease.Revoke(context.TODO(), em.leaseID) 
  76.  
  77.     fmt.Println("釋放了鎖"
  78.  
  79. // groutine1 
  80. func try2lock1() { 
  81.     eMutex1 := &EtcdMutex{ 
  82.         Conf: conf, 
  83.         Ttl:  10, 
  84.         Key:  "lock"
  85.     } 
  86.  
  87.     err := eMutex1.Lock() 
  88.     if err != nil { 
  89.         fmt.Println("groutine1搶鎖失敗"
  90.         return 
  91.     } 
  92.     defer eMutex1.UnLock() 
  93.  
  94.     fmt.Println("groutine1搶鎖成功"
  95.     time.Sleep(10 * time.Second
  96.  
  97. // groutine2 
  98. func try2lock2() { 
  99.     eMutex2 := &EtcdMutex{ 
  100.         Conf: conf, 
  101.         Ttl:  10, 
  102.         Key:  "lock"
  103.     } 
  104.  
  105.     err := eMutex2.Lock() 
  106.     if err != nil { 
  107.         fmt.Println("groutine2搶鎖失敗"
  108.         return 
  109.     } 
  110.  
  111.     defer eMutex2.UnLock() 
  112.     fmt.Println("groutine2搶鎖成功"
  113.  
  114. // 測試代碼 
  115. func EtcdRunTester() { 
  116.     conf = clientv3.Config{ 
  117.         Endpoints:   []string{"127.0.0.1:2379"}, 
  118.         DialTimeout: 5 * time.Second
  119.     } 
  120.  
  121.     // 啟動兩個協程競爭鎖 
  122.     go try2lock1() 
  123.     go try2lock2() 
  124.  
  125.     time.Sleep(300 * time.Second

 總結

可以提供分布式鎖功能的組件有多種,但是每一種都有自己的脾氣與性格。至于選擇哪一種組件,則要看數據對業務的重要性,數據要求強一致性推薦支持CP的etcd、zookeeper,數據允許少量丟失、不要求強一致性的推薦支持AP的Redis。

 

責任編輯:姜華 來源: 今日頭條
相關推薦

2021-07-21 09:48:20

etcd-wal模塊解析數據庫

2021-04-01 10:51:55

MySQL鎖機制數據庫

2021-06-16 14:44:32

etcd-raftRaftLeader

2021-07-12 06:11:14

SkyWalking 儀表板UI篇

2021-10-28 08:51:53

GPIO軟件框架 Linux

2021-04-14 07:55:45

Swift 協議Protocol

2022-02-25 15:50:05

OpenHarmonToggle組件鴻蒙

2023-03-13 09:31:04

2021-07-08 07:30:13

Webpack 前端Tree shakin

2021-04-23 08:59:35

ClickHouse集群搭建數據庫

2021-05-08 08:36:40

ObjectString前端

2021-06-21 14:36:46

Vite 前端工程化工具

2021-01-28 08:55:48

Elasticsear數據庫數據存儲

2023-03-29 07:45:58

VS編輯區編程工具

2021-04-14 14:16:58

HttpHttp協議網絡協議

2021-04-08 11:00:56

CountDownLaJava進階開發

2022-03-22 09:09:17

HookReact前端

2024-06-13 08:34:48

2021-03-12 09:21:31

MySQL數據庫邏輯架構

2022-02-17 08:53:38

ElasticSea集群部署
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 久久av资源网 | 久热精品免费 | 亚洲精品乱码久久久久久黑人 | 一区二区在线看 | 精品福利在线 | 四虎影院在线观看av | 天天看天天操 | 亚洲一区中文字幕在线观看 | 亚洲国产成人在线观看 | 影音先锋成人资源 | 欧美激情在线播放 | 亚洲成人激情在线观看 | 亚洲美女网站 | 久久久久久高潮国产精品视 | 欧美高清视频 | 亚洲v日韩v综合v精品v | 久久久久久精 | cao在线| 最新中文字幕久久 | 好姑娘影视在线观看高清 | 一级片在线免费播放 | 亚洲精品影院 | 永久av| 国产三级大片 | 中文字幕亚洲一区二区三区 | 精品一区二区久久久久久久网站 | 精品一区二区三区在线观看国产 | 亚洲成人精品一区二区 | 亚洲高清视频一区二区 | 久久久91精品国产一区二区三区 | 成人免费视频 | 日韩一二三 | 99精品视频一区二区三区 | 精品欧美乱码久久久久久1区2区 | www.中文字幕.com | 亚洲成人二区 | 福利片在线 | 国产乱码精品一区二区三区忘忧草 | 青青草av | 西西裸体做爰视频 | 国产成人免费视频网站高清观看视频 |