Skip to content

分布式锁 ​

Redis 分布式锁基于 SET NX EX 命令实现。

基本实现 ​

SET NX EX ​

bash
# 获取锁
SET lock:resource unique_value NX EX 10

# 释放锁(Lua 脚本保证原子性)
EVAL "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end" 1 lock:resource unique_value

Go 实现 ​

go
package main

import (
    "context"
    "time"
    "github.com/redis/go-redis/v9"
)

type RedisLock struct {
    client *redis.Client
    key    string
    value  string
}

func (l *RedisLock) Acquire(timeout time.Duration) bool {
    ctx := context.Background()
    return l.client.SetNX(ctx, l.key, l.value, timeout).Val()
}

func (l *RedisLock) Release() error {
    ctx := context.Background()
    script := `
        if redis.call("get", KEYS[1]) == ARGV[1] then
            return redis.call("del", KEYS[1])
        else
            return 0
        end
    `
    return l.client.Eval(ctx, script, []string{l.key}, l.value).Err()
}

// 使用示例
func main() {
    rdb := redis.NewClient(&redis.Options{Addr: "localhost:6379"})
    
    lock := &RedisLock{
        client: rdb,
        key:    "lock:my-resource",
        value:  "unique-id",
    }
    
    if lock.Acquire(10 * time.Second) {
        defer lock.Release()
        // 执行关键操作
    }
}

Redlock 算法 ​

Redis 官方提出的分布式锁算法,基于多个 Redis 实例。

原理 ​

  1. 获取当前时间戳
  2. 依次向 N 个 Redis 实例请求锁
  3. 计算获取锁消耗的时间
  4. 只有大多数实例成功才算成功
  5. 锁的有效时间 = 设置时间 - 获取时间

Go 实现 ​

go
import "github.com/go-redsync/redsync/v4"

// 使用 redsync 库
rs := redsync.New(redsync.NewPool(rdb1), redsync.NewPool(rdb2), redsync.NewPool(rdb3))

mutex := rs.NewMutex("lock:resource")
if err := mutex.Lock(); err != nil {
    panic(err)
}
defer mutex.Unlock()

最佳实践 ​

  1. 锁超时:设置合理的过期时间
  2. 锁续期:长时间操作需要续期
  3. 唯一值:每个锁请求使用唯一标识
  4. 释放验证:只释放自己持有的锁
  5. 故障处理:使用 Redlock 提高可靠性

在下一章中,我们将学习性能优化。