高手之路——分佈式鎖設計與實踐

分佈式鎖設計與實踐

分佈式鎖定義

  • 分佈式環境下,鎖定全局唯一資源
    • 請求處理串行化
    • 實際表現互斥鎖

分佈式鎖目的

  • 交易訂單鎖定
    • 防止重複下單
    • 解決業務層冪等問題
  • MQ消息冪等性
    • 發送消息重複
    • 消息消費端去重
    • 比如手機提現
  • 在用戶對商品下單後,訂單狀態爲待支付,在某一時刻用戶正在對該訂單做支付操作,商家對該訂單進行改價操作
    • 狀態的修改行爲需要做串行化處理,避免出現數據錯亂。

基於redis分佈式鎖

  • 基於redis分佈式鎖方案
    • 唯一線程串行處理
    • 實現方式
      • Redis Setnx(set if not exists)命令在指定的key不存在時,爲key設置指定的值
        • setnx key value expire time
          • 設置成功,返回1,設置失敗返回0
      • 存在問題
        • 鎖時間不可控
          • 無法續租期
        • 單點問題
          • 單實例存在進程一旦死掉,會徹底阻塞業務流程(無法保證高可用)
          • 主從方式,主從數據異步,會存在鎖失效問題
        • 官方建議
          • redis本身建議使用Redlock算法來保證,但是問題是需要至少三個Redis主從實例來完成,維護成本相對較高。Redlock等同於自己實現簡單的一致性協議,細節繁瑣,且容易出錯。

問題本質:分佈式鎖是CP模型,redis集羣是AP模型通過CP模型解決

高可用分佈式鎖設計目標

  • 設計目標
    • 強一致性
    • 服務高可用,系統穩健
    • 鎖自動續約及其自動釋放
    • 代碼高度抽象,業務接入極簡
    • 可視化管理後臺,監控及管理

高可用分佈式鎖設計方案對比

存儲層產品對比

- redis zookeeper etcd
一致性算法 paxos raft
CAP AP CP CP/AP
高可用 主從 N+1可用 N+1可用
接口類型 客戶端 客戶端 http/grpc
實現 setNX createEphemeral restful API
  • 由於redis無法保證數據一致性
  • zk對鎖實現使用創建臨時節點和watch機制。執行效率、擴展性、社區活躍度等低於etcd
  • 選擇基於etcd實現

分佈式鎖存儲選型

  • etcd

    • 簡單KV
    • 強一致性
    • 高可用
      • 無單點
    • 數據高可靠
      • 持久化
  • 分佈式Client+etcd

    • Client TTL模式

使用場景一:申請鎖

  • 業務方申請資源鎖,調用時提供key,ttl
  • etcd生成uuid,作爲當前鎖的唯一憑證,將(key,uuid,ttl)寫etcd
  • 檢查etcd中此key是否存在,如沒有,嘗試寫入key,寫入失敗,拿鎖失敗,寫入成功拿到鎖
  • 拿鎖後,心跳線程啓動,心跳線程維持時間爲ttl/3,cas uuid(比較還是不是自己的鎖,是的話就更新),從而將key值續租
  • 相關etcd API
    • 申請鎖
      • curl http://ip:2379/v2/keys/foo -XPUT -d value=bar -d ttl=5 prevExist=false
    • CAS更新鎖租約
      • curl http://ip:2379/v2/keys/foo?prevValue=prev_uuid -XPUT -d ttl=5 -d ttl=5 -d refresh=true -d prevExist=true
    • CAS刪除鎖
      • curl http://ip:2379/v2/keys/foo?prevValue=prev_uuid -XDELETE

使用場景二:申請鎖,但鎖已被持有

  • 業務方申請資源鎖,調用時提過key,ttl
  • 檢查etcd中key的存在,若已存在,拿鎖失敗

使用場景三:鎖的清理

  • 如果調用方正常結束,通過cas接口調用delete方法自動清理etcd中的key值
  • 如果調用方異常終止,等待原有鎖ttl過期後,鎖資源釋放

業務接入

提供客戶端
作業:使用etcd實現分佈式鎖,提供簡易客戶端

獲取鎖平均耗時監控

在這裏插入圖片描述

etcd兼容性測試

  • etcd提供了獨有的集羣管理模式,方便進行極端case下的測試,以三個節點的etcd集羣爲例
    • 單節點停機,不影響持續寫入,不影響讀,結果有一致性
    • 當只有一個節點時,讀會停機,寫入成功
    • 理論上只要不是多節點同時停機,線上服務不會受影響

etcd恢復/版本

  • etcd有自有的數據恢方式,如果服務停機後,可以將所有數據轉移重啓
  • etcd的增刪節點,節點遷移等部署相關,均有相關操作方式
  • etcd版本選擇,選擇使用etcd3.2.9,但是因爲V3 API暫時還不完備,建議用V2方式實現
    • V3提供gRPC接口
    • 天然提供分佈式鎖功能
      • 只需要申請鎖,釋放鎖
      • 不用關注鎖的租期問題

分佈式鎖特殊場景

  • 特殊場景一:分佈式鎖只是在同一自然時間的互斥鎖,本身不解決冪等性問題

    • 接入業務需要完善從獲得鎖到釋放鎖中間的數據冪等邏輯
  • 特殊場景二:鎖沒有按照預期續租

    • 心跳續租沒成功
    • 馬上啓動GC,GC時間夠長
  • 特殊場景三:etcd內部協調發生問題

    • leader節點掛了,選主中
    • Raft日誌數據同步發送錯誤或者不一致問題
發佈了44 篇原創文章 · 獲贊 4 · 訪問量 1975
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章