# 1. 基于 Redis 的分布式锁
优点:
- 性能高,延迟低
- 实现相对简单
- 支持过期时间自动释放
核心特性:
- 使用 SET NX PX 原子操作获取锁
- 使用 Lua 脚本确保释放锁的原子性
- 防止误删其他客户端的锁
- 支持锁续约
import ( | |
"context" | |
"crypto/rand" | |
"encoding/hex" | |
"errors" | |
"time" | |
"github.com/redis/go-redis/v9" | |
) | |
type DistributedLock interface { | |
Lock(ctx context.Context) error | |
Unlock(ctx context.Context) error | |
TryLock(ctx context.Context) (bool, error) | |
Refresh(ctx context.Context, ttl time.Duration) error | |
} | |
// 基于 Redis 的分布式锁 | |
type RedisDistriburedLock struct { | |
client *redis.Client | |
key string | |
value string | |
ttl time.Duration | |
retryDelay time.Duration | |
} | |
// 生成随机值,防止误解锁 | |
func generateRandomValue() string { | |
bytes := make([]byte, 16) | |
rand.Read(bytes) | |
return hex.EncodeToString(bytes) | |
} | |
func (r *RedisDistriburedLock) Lock(ctx context.Context) error { | |
ticker := time.NewTicker(r.retryDelay) | |
defer ticker.Stop() | |
for { | |
select { | |
case <-ctx.Done(): | |
return ctx.Err() | |
case <-ticker.C: | |
result := r.client.SetNX(ctx, r.key, r.value, r.ttl) | |
if result.Err() != nil { | |
return result.Err() | |
} | |
if result.Val() { | |
return nil // 获取锁成功 | |
} | |
} | |
} | |
} | |
// 尝试获取锁,不阻塞 | |
func (r *RedisDistriburedLock) TryLock(ctx context.Context) (bool, error) { | |
result := r.client.SetNX(ctx, r.key, r.value, r.ttl) | |
if result.Err() != nil { | |
return false, result.Err() | |
} | |
return result.Val(), nil | |
} | |
func (r *RedisDistriburedLock) Unlock(ctx context.Context) error { | |
//lua 脚本,确保只有锁的持有者才能释放锁 | |
luaScript := ` | |
if redis.call("GET",KEY[1]) == ARGV[1] then | |
return redis.call("DEL",KEYS[1]) | |
else | |
return 0 | |
end | |
` | |
result := r.client.Eval(ctx, luaScript, []string{r.key}, r.value) | |
if result.Err() != nil { | |
return result.Err() | |
} | |
if result.Val().(int64) == 0 { | |
return errors.New("lock not owned by current client") | |
} | |
return nil | |
} | |
func (r *RedisDistriburedLock)Refresh(ctx context.Context,ttl time.Duration) error{ | |
luaScript := ` | |
if redis.call("GET",KEYS[1]) = ARGV[1] then | |
return redis.call("PEXPIRE",KEYS[1],ARGV[2]) | |
else | |
return 0 | |
end | |
` | |
result := r.client.Eval(ctx, luaScript, []string{r.key}, r.value, int64(ttl/time.Millisecond)) | |
if result.Err() != nil { | |
return result.Err() | |
} | |
if result.Val().(int64) == 0 { | |
return errors.New("lock not owned by current client") | |
} | |
return nil | |
} |
# 2. 基于 etcd 的分布式锁
优点:
- 强一致性保证
- 自动续约机制
- 支持锁的监听和等待
核心特性:
- 基于 etcd 的 lease 机制
- 使用 concurrency 包简化实现
- 会话自动续约
# 3. 基于数据库的分布式锁
优点:
- 实现简单,易于理解
- 可以利用现有数据库
- 强一致性
缺点:
- 性能相对较低
- 需要定期清理过期锁