zoukankan      html  css  js  c++  java
  • go redis锁

    redis经常用作分布式锁,这里记录一个简单的锁代码如下:

    package main
    
    import (
        "crypto/rand"
        "encoding/base64"
        "fmt"
        "github.com/go-redis/redis"
        "io"
        "sync"
        "time"
    )
    
    func main() {
        addr := "192.168.100.30:6379"
        rdb := redis.NewUniversalClient(&redis.UniversalOptions{
            Addrs:    []string {addr},
            Password: "", // no password set
            DB:       0,  // use default DB
        })
        defer func() {
            _ = rdb.Close()
        }()
    
        key := "gavin-lock"
        uid, err := Lock(rdb, key, time.Second*1, time.Second*2)
        if err == nil {
            _ = Unlock(rdb, key, uid)
        }
    }
    
    var randMutex sync.Mutex
    var randBytes []byte
    
    // 获取随机字串
    func randToken() string {
        randMutex.Lock()
        defer randMutex.Unlock()
    
        if len(randBytes) == 0 {
            randBytes = make([]byte, 16)
        }
    
        if _, err := io.ReadFull(rand.Reader, randBytes); err != nil {
            return ""
        }
        return base64.RawURLEncoding.EncodeToString(randBytes)
    }
    
    func Lock(redisClient redis.UniversalClient, lockKey string, acquireTimeOut, lockTimeOut time.Duration) (token string, err error) {
        token = randToken()
        var acquireDuration = acquireTimeOut
    
        for acquireDuration > 0 {
            ok, err := redisClient.SetNX(lockKey, token, lockTimeOut).Result()
            if err != nil {
                fmt.Printf("redis锁 - 加锁失败 key: %s, token: %s, ttl: %v, err: %v\r\n", lockKey, token, lockTimeOut, err)
                return "", err
            }
    
            if ok {
                fmt.Printf("redis锁 - 加锁成功 key: %s, token: %s, ttl: %v\r\n", lockKey, token, lockTimeOut)
                return token, nil
            }
            time.Sleep(time.Millisecond * 100) // next: sleep 500ms
            acquireDuration -= time.Millisecond * 100
        }
        fmt.Printf("redis锁 - 加锁超时 key: %s, token: %s, ttl: %v\r\n", lockKey, token, acquireTimeOut)
        return "", fmt.Errorf("获取redis锁超时: %v\r\n", acquireTimeOut)
    }
    
    func Unlock(redisClient redis.UniversalClient, lockKey, token string) error {
        const script = `if redis.call('GET', KEYS[1]) == ARGV[1] then return redis.call('DEL', KEYS[1]) else return 0 end`
        ret, err := redisClient.Eval(script, []string{lockKey}, token).Result()
        if err != nil {
            fmt.Printf("redis锁 - 解锁失败 key: %s, token: %s,  err: %v\r\n", lockKey, token, err)
            return err
        }
    
        if v, ok := ret.(int64); ok && v == 1 {
            fmt.Printf("redis锁 - 解锁成功 key: %s, token: %s\r\n", lockKey, token)
            return nil
        }
    
        fmt.Printf("redis锁 - 解锁失败 key: %s, token: %s, key已经过期\r\n", lockKey, token)
        return nil
    }
    windows技术爱好者
  • 相关阅读:
    删除ubuntu多余内核
    Linux从入门到精通(第8章--磁盘管理)
    图书销售管理系统概要设计,系统数据结构设计分工
    图书管理销售系统,出错设计部分
    图书管理销售系统概要分析,接口设计部分
    图书管理销售系统,运行设计部分
    图书管理销售管理系统,总体设计部分
    图书销售管理概要分析报告,引言部分
    图书销售管理系统概要分析报告总体分工
    图书销售管理系统需求分析,各种功能图部分
  • 原文地址:https://www.cnblogs.com/majiang/p/15621088.html
Copyright © 2011-2022 走看看