<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                [TOC] ## 概述 網上有很多golang操作redis的例子,我使用`github.com/gomodule/redigo/redis`包寫一個關于redis分布式鎖的問題。 ## redis分布式鎖 鎖需要的幾個組件 * 獲取鎖 * 刪除鎖 分布式鎖還需要 * 給鎖加上唯一id (只能獲取和刪除自己的鎖) * 給鎖加上過期時間 (防止死鎖) ## golang代碼 推薦使用redis的連接池 ```golang pool := redis.Pool{ MaxIdle: 8, MaxActive: 0, IdleTimeout: 100, Dial: func() (redis.Conn, error) { return redis.Dial("tcp", "127.0.0.1:6100") }, } ``` 通過lua腳本保證`獲取鎖/加過期時間`和`獲取鎖的值/刪除鎖`為原子操作 ```golang var ( updateLockExpireUidScript = redis.NewScript(1, ` local res = redis.call("SETNX", KEYS[1], ARGV[1]) if res == 1 then return redis.call("EXPIRE", KEYS[1], ARGV[2]) end return res `) deleteLockByUidScript = redis.NewScript(1, ` local res = redis.call("GET", KEYS[1]) if res == ARGV[1] then return redis.call("DEL", KEYS[1]) end return res `) ) ``` golang完整代碼 ```golang package main import ( "fmt" "github.com/gomodule/redigo/redis" "time" ) func getLock(conn redis.Conn, key []string, uid int, expire int) bool { lock := false for !lock { res, err := updateLockExpireUidScript.Do(conn, key, uid, expire) if err != nil { fmt.Println(err.Error()) break } if res.(int64) == 1 { lock = true fmt.Println("獲取鎖成功") return true } } fmt.Println("獲取鎖失敗") return false } func delLock(conn redis.Conn, key []string, uid int) bool { _, err := deleteLockByUidScript.Do(conn, key, uid) if err != nil { fmt.Println("刪除鎖失敗") fmt.Println(err.Error()) return false } fmt.Println("刪除鎖成功") return true } var ( updateLockExpireUidScript = redis.NewScript(1, ` local res = redis.call("SETNX", KEYS[1], ARGV[1]) if res == 1 then return redis.call("EXPIRE", KEYS[1], ARGV[2]) end return res `) deleteLockByUidScript = redis.NewScript(1, ` local res = redis.call("GET", KEYS[1]) if res == ARGV[1] then return redis.call("DEL", KEYS[1]) end return res `) ) func main() { pool := redis.Pool{ MaxIdle: 8, MaxActive: 0, IdleTimeout: 100, Dial: func() (redis.Conn, error) { return redis.Dial("tcp", "127.0.0.1:6100") }, } key := []string{"distribute"} uid := 1 expire := 20 fmt.Println(time.Now()) for i:= 1; i< 100; i++ { go func() { conn := pool.Get() if getLock(conn, key, uid, expire) { fmt.Println("開始執行邏輯...") fmt.Println("邏輯結束,刪除鎖") delLock(conn, key, uid) } }() } fmt.Println(time.Now()) time.Sleep(time.Second * 20) } ``` ## LUA **Lua腳本的限制** * Redis不提供引入額外的包,例如os等,只有redis這一個包可用。 * Lua腳本將會在一個函數中運行,所有變量必須使用local聲明 * return返回多個值時,Redis將會只給你第一個 **腳本中的類型限制** * 腳本返回nil時,Go中得到的是`err = redis.Nil`(與Get找不到值相同) * 腳本返回false時,Go中得到的是nil,腳本返回true時,Go中得到的是int64類型的1 * 腳本返回{"ok": ...}時,Go中得到的是redis的status類型(true/false) * 腳本返回{"err": ...}時,Go中得到的是err值,也可以通過`return redis.error_reply("My Error")`達成 * 腳本返回number類型時,Go中得到的是int64類型 * 傳入腳本的KEYS/ARGV中的值一律為string類型,要轉換為數字類型應當使用to\_number **如果腳本運行了很久會發生什么?** Lua腳本運行期間,為了避免被其他操作污染數據,這期間將不能執行其它命令,一直等到執行完畢才可以繼續執行其它請求。當Lua腳本執行時間超過了lua-time-limit時,其他請求將會收到Busy錯誤,除非這些請求是SCRIPT KILL(殺掉腳本)或者SHUTDOWN NOSAVE(不保存結果直接關閉Redis) 更多內容參考以下地址,我這里主要是根據使用Go的經驗提供一些總結。[https://redis.io/commands/eval](https://redis.io/commands/eval) 一段更“復雜”的腳本,它要求在獲取一個key值時,如果該值訪問較多,就延長生存周期。此外還要比較更新時間,如果不需要更新,則直接返回取到的值,否則返回redis.Nil ck: https://cloud.tencent.com/developer/article/1830969
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看