国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - 編程技術 - 一篇帶給你etcd與分布式鎖

一篇帶給你etcd與分布式鎖

2021-05-19 23:48今日頭條編程技術之道 編程技術

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

一篇帶給你etcd與分布式鎖

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

 

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

一篇帶給你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. 業務處理過程中過程中,另起線程/協程進行鎖的續約

一篇帶給你etcd與分布式鎖

4. 關于etcd

 

一篇帶給你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中用的則會更多。

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

一篇帶給你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。

原文鏈接:https://www.toutiao.com/i6963570087278182923/

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成年人免费在线观看视频网站 | 欧美视频第一页 | 国产精品视频专区 | www亚洲精品| 久久国产精品一区 | 伊人久久综合精品一区二区三区 | 亚洲一视频 | 精品成人在线视频 | 日本在线不卡视频 | 成人在线视频一区 | 亚洲欧美另类图片 | 国产乱轮 | 麻豆一区二区三区 | 一区二区精品在线 | 激情五月婷婷 | 精品视频网 | 成人小视频在线观看 | 91免费小视频| 国产一区二区三区在线免费观看 | 国产福利在线观看 | 亚洲精品日韩在线 | 欧美一区二区三区在线观看视频 | 一级片在线免费观看视频 | 毛片免费观看 | 亚洲一区二区在线 | 成人激情视频在线观看 | 黄色综合| 亚洲成人高清 | 污视频免费 | 国产中文字幕一区 | 久久久看片 | 黄色影视| 国产精品视频一区二区三区 | 视频一区二区三区免费观看 | 午夜精品久久久久久久久 | 欧美一级欧美三级在线观看 | 欧美一区二区在线观看 | 亚洲一区精品在线 | 亚洲国产精品久久久久婷婷老年 | 久久精品国产一区二区三区不卡 | 国产午夜精品一区二区三区嫩草 |