當前位置: 妍妍網 > 碼農

全新的分布式鎖,幾行程式碼搞定,簡單且強大

2024-03-15碼農

分布式鎖是分布式系統中一個極為重要的工具。目前有多種分布式鎖的設計方案,比如借助 redis,mq,資料庫,zookeeper 等第三方服務系統來設計分布式鎖。tldb 提供的分布式鎖,主要是要簡化這個設計的過程,提供一個簡潔可靠,類似使用程式中物件鎖的方式來獲取分布式鎖。

來源:https://my.oschina.net/donnie4w/blog/10114233


tldb 提供分布式鎖使用方法:

  1. lock 阻塞式請求鎖

  2. trylock 嘗試加鎖,若鎖已被占用,則失敗返回,反之,則獲取該鎖

  3. unlock 釋放已經獲取的鎖

    tldb 提供的分布式鎖功能主要在 MQ 模組中實作,呼叫的方法在 MQ 客戶端實作,客戶端的實作實際非常簡單,除了目前已經實作的幾種語言 java,golang,python,javaScript 寫的 simpleClient,其實其他開發者有興趣也可以實作其他語言的 MQ 客戶端,完全沒有技術門檻。分布式鎖由 tldb 伺服器控制,所以它相對客戶端來說,也是跨語言的,如,用 java 客戶端上鎖的物件,其他語言同樣無法獲取該物件鎖。

Lock (string,int) 方法的使用

tldb 提供的是以字串為鎖物件的獨占鎖, 如,lock ("abc",3) 必須提供兩個參數:

  1. 第一個參數為鎖物件,即伺服器對 「abc」 物件分配一個鎖,所有對 "abc" 物件請求加鎖的執行緒爭用一個獨占鎖,該方法為一個阻塞方法,請求到鎖則返回,如果鎖被其他執行緒占用,則一直阻塞直至獲取到鎖。

  2. 第二個參數為持有該分布式鎖的最長時間,單位為秒,例如 lock ("abc",3),意思是,如果超過 3 秒還沒有呼叫 unlock 釋放該鎖,伺服器將強制釋放該鎖,繼續將鎖分配給其他請求的執行緒。

UnLock (string) 方法的使用

  • UnLock 為釋放分布式鎖時呼叫的方法。客戶端在成功獲取分布式鎖後,伺服器會返回一個該鎖的 key,客戶端執行完邏輯程式碼的最後,必須顯式呼叫 UnLock (key) 來釋放該分布式鎖。如果沒有呼叫 unlock 釋放鎖,tldb 將等待鎖釋放的超時時間直至超時後強制釋放該鎖。

  • TryLock (string,int) 方法的使用

  • trylock 與 lock 相似,但是 lock 方法阻塞的,呼叫 lock 方法請求分布式鎖時,如果該鎖已經被占用,那麽 lock 方法將一直等待直至 tldb 伺服器將鎖分配給它,這與程式中獲取獨占鎖的方式一致。而 trylock 時非阻塞的,呼叫 trylock 後會立即返回,如果獲取到鎖,tldb 會將標識該鎖的 key 一並返回,如何該鎖已經被占用,伺服器將返回空數據。

  • 以下以 go 為例使用分布式鎖

    因為 tldb 分布式的實作是在 MQ 模組,所以 go 程式必須使用 tlmq-go, tldb 的 mq 客戶端進行呼叫鎖方法。

    import"github.com/donnie4w/tlmq-go/cli"

    呼叫 lock 的程式:lock 方法是阻塞的

    sc := cli.NewMqClient("ws://127.0.0.1:5001", "mymq=123")
    sc.Connect()
    //以上為 客戶端連線MQ伺服器
    key, err := sc.Lock("testlock", 3)
    //lock中兩個參數,第一個參數為字串,即tldb伺服器為「testlock」分配一個全域的分布式鎖
    //第二個參數3為客戶端持有該鎖的最長時間,表示超過3秒沒有釋放鎖時,tldb伺服器將在伺服端強制釋放該鎖,並分配給其他請求鎖的執行緒
    if err!=nil{
    //獲取鎖失敗,需檢視tldb能正常存取
    }else{
    defer sc.UnLock(key) //獲取鎖成功後,必須在程式最後呼叫Unlock
    //執行業務邏輯程式
    }

    呼叫 tryLock 的程式,trylock 是非阻塞的

    sc := cli.NewMqClient("ws://127.0.0.1:5001", "mymq=123")
    sc.Connect()
    if key, ok := sc.TryLock("testlock2", 3); ok {
    //ok為true,表示已經成功獲取到分布式鎖
    defer sc.UnLock(key) //在程式最後釋放鎖物件
    ...
    }

    go 用自旋的方式使用 trylock 獲取分布式鎖,實作程式的阻塞等待

    sc := cli.NewMqClient("ws://127.0.0.1:5001", "mymq=123")
    sc.Connect()
    var key string
    for {
    if v, ok := sc.TryLock("testlock", 3); ok {
    key = v
    break
    } else {
    <-time.After(100* time.Millisecond)
    }
    }
    defer sc.UnLock(key)
    ...//業務邏輯程式碼

    這段程式應該比較易於理解,就是每隔 100 毫秒,迴圈獲取字串 「testlock」 的分布式鎖直至成功。

    以下以 java 為例 java 客戶端為 tlmq-j :https://github.com/donnie4w/tlmq-j

    maven 配置

    <dependency>
    <groupId>io.github.donnie4w</groupId>
    <artifactId>tlmq-j</artifactId>
    <version>0.0.2</version>
    </dependency>

    呼叫 lock 方法

    MqClient mc = new SimpleClient("ws://127.0.0.1:5001", "mymq=123");
    mc.connect();
    //java連線伺服器
    String key = null;
    try{
    key = mc.lock("testlock", 3); //獲取分布式
    ... //執行業務邏輯程式
    }finally {
    if (key!=null){
    mc.unLock(key); //釋放分布式鎖
    }
    }

    呼叫 trylock 方法

    MqClient mc = new SimpleClient("ws://127.0.0.1:5001", "mymq=123");
    mc.connect();
    String key = null;
    try{
    key = mc.tryLock("testlock", 3); //獲取分布式
    ... //執行業務邏輯程式
    } finally {
    if (key!=null){
    mc.unLock(key); //釋放分布式鎖
    }
    }

    以下是 tldb 分布式鎖的功能測試數據: 多執行緒並行 呼叫 lock 獲取同一個物件鎖後,程式的執行數據:

    多執行緒並行使用自旋的方式呼叫 trylock 與 lock 獲取同一個物件鎖:

    >>

    END

    精品資料,超贊福利,免費領

    微信掃碼/長按辨識 添加【技術交流群

    群內每天分享精品學習資料

    最近開發整理了一個用於速刷面試題的小程式;其中收錄了上千道常見面試題及答案(包含基礎並行JVMMySQLRedisSpringSpringMVCSpringBootSpringCloud訊息佇列等多個型別),歡迎您的使用。

    👇👇

    👇點選"閱讀原文",獲取更多資料(持續更新中