Redis深度歷險-分佈式鎖 Redis分佈式鎖

Redis分佈式鎖

Redis可以用來實現分佈式鎖,有兩種實現方式:通過setnx實現的悲觀鎖和通過watch實現的樂觀鎖

悲觀鎖

package main

import (
    "fmt"
    "github.com/garyburd/redigo/redis"
    "log"
    "math/rand"
    "strconv"
)

func  main() {
    conn, err := redis.Dial("tcp", "127.0.0.1:6379")
    if err != nil {
        log.Fatal(err)
    }

    tag := strconv.Itoa(rand.Int())
    reply, err := conn.Do("set", "lock", tag, "ex", "1", "nx")
    if reply == "OK" {
        //do something
    }

    reply, err = conn.Do("eval",
        "if redis.call('get', KEYS[1]) == ARGV[1] then " +
        "   return redis.call('del', KEYS[1])" +
        "else" +
        "   return 0 " +
        "end", "1", "lock", tag)
    
    if reply == int64(1) {
        fmt.Println("release lock")
    }

}

本質就是通過set+nx的方式只允許一個客戶端加鎖成功,主要的問題在於:

  • 要注意給鎖加上超時,否則當客戶端斷了就再也沒人解鎖了
  • 在解鎖的時候,注意只能刪除自己加的鎖,所以要做delifequals這樣的原子指令

樂觀鎖

package main

import (
    "fmt"
    "github.com/garyburd/redigo/redis"
    "log"
)

func  main() {
    conn, err := redis.Dial("tcp", "127.0.0.1:6379")
    if err != nil {
        log.Fatal(err)
    }

    conn.Do("set", "lock", "1")
    conn.Do("watch", "lock")
    //conn.Do("set", "lock", "2")

    conn.Do("multi")
    conn.Do("set", "key", "123")
    reply, err := conn.Do("exec")

    fmt.Println(reply, err)

}

樂觀鎖則是利用watch+multi+exec機制來實現,在exec時會檢查watch的值是否有發生變化

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章