# Golang 高性能Redis分布式锁 **Repository Path**: worklz/go-redis-lock ## Basic Information - **Project Name**: Golang 高性能Redis分布式锁 - **Description**: 基于Golang实现的高性能Redis分布式锁库,提供了安全可靠的分布式锁解决方案。该库具有自动续约、上下文自动释放、重试机制等特性,适用于分布式系统中的并发控制场景。 - **Primary Language**: Go - **License**: MIT - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2025-10-04 - **Last Updated**: 2025-10-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # go-redis-lock - 高性能Redis分布式锁 ## 项目简介 本项目是基于Golang实现的高性能Redis分布式锁库,提供了安全可靠的分布式锁解决方案。该库具有自动续约、上下文自动释放、重试机制等特性,适用于分布式系统中的并发控制场景。 ## 核心特性 ### 1. 安全可靠的锁实现 - **原子操作**:基于Redis的`SET NX PX`命令实现原子性的锁获取 - **唯一标识**:使用UUID生成唯一值,确保只有锁的持有者才能释放锁 - **Lua脚本**:通过Lua脚本实现原子性的锁释放和续约操作 ### 2. 智能自动续约 - **自动续约**:锁获取后自动启动续约协程,确保业务执行期间锁不会过期 - **续约间隔**:默认使用TTL/3作为续约间隔,平衡性能和安全性 - **重试机制**:续约失败时支持指数退避重试,提高可靠性 ### 3. 灵活的锁释放机制 - **手动释放**:提供显式的Release()方法释放锁 - **自动释放**:支持基于上下文的自动释放,上下文结束时自动释放锁 - **Finalizer**:设置对象Finalizer作为最后防线,防止忘记释放导致的死锁 ### 4. 多样化的锁获取模式 - **等待模式**:支持设置等待时间,在指定时间内阻塞等待锁 - **非等待模式**:获取失败时立即返回,适用于不需要等待的场景 - **退避策略**:等待模式下使用随机退避策略,减少锁竞争 ### 5. 完善的参数控制 - **TTL设置**:支持设置锁的过期时间 - **最大持有时间**:限制锁的最长持有时间,防止无限续约 - **重试间隔**:可自定义锁获取的重试间隔范围 ## 快速开始 ### 安装 ```bash go get gitee.com/worklz/go-redis-lock ``` ### 初始化redis锁 ```golang import ( "context" "errors" "fmt" redislock "gitee.com/worklz/go-redis-lock" "github.com/go-redis/redis/v8" "log" "sync" ) // 初始化Redis锁 func init() { err := redislock.Init( func(ctx context.Context, args ...interface{}) (interface{}, error) { res, err := GetRedisClient().Do(ctx, args...).Result() if err != nil && errors.Is(err, redis.Nil) { err = nil } return res, err }, redislock.WithLogger(&MyLogger{}), redislock.WithFullKey(func(key string) string { return "redis.lock.example:" + key }), ) if err != nil { panic(fmt.Sprintf("Redis锁初始化失败: %v", err)) } } var redisClientOnce sync.Once var redisClient *redis.Client // GetRedisClient 获取Redis客户端 func GetRedisClient() *redis.Client { redisClientOnce.Do(func() { redisClient = redis.NewClient(&redis.Options{ Addr: "192.168.88.201:6379", Password: "123456", // 没有密码 DB: 1, // 默认DB }) // 检查Redis连接 ctx := context.Background() _, err := redisClient.Ping(ctx).Result() if err != nil { panic(fmt.Sprintf("Failed to connect to Redis: %v", err)) } }) return redisClient } // MyLogger 自定义日志实现 type MyLogger struct{} func (m *MyLogger) Infof(format string, args ...interface{}) { log.Printf("[INFO] "+format+"\r\n", args...) } func (m *MyLogger) Warnf(format string, args ...interface{}) { log.Printf("[WARN] "+format+"\r\n", args...) } func (m *MyLogger) Errorf(format string, args ...interface{}) { log.Printf("[ERROR] "+format+"\r\n", args...) } ``` ### [基本使用(推荐)](https://gitee.com/worklz/go-redis-lock/blob/master/example/tests/example1_base_test.go) ```go // 创建并获取锁 lock := redislock.NewLock( "order:123", 5*time.Second, // 锁过期时间5s,若在时间内业务没有完成,会在另外的协程中自动续约,续约的总时间不会超过最大持有时间 redislock.WithWaitTime(5*time.Second), // 锁等待时间5s(阻塞等待模式下超过当前时间就不再继续等待,返回锁获取失败) redislock.WithMaxHoldTime(30*time.Second), // 锁最大持有时间10s,超过这个时间会被自动释放(默认为5倍过期时间,一般可不设置) ) release, err := lock.Acquire() if err != nil { log.Printf("锁获取失败: %v", err) } else { defer release() // 确保释放 // 执行业务逻辑... } ``` ### [上下文自动释放](https://gitee.com/worklz/go-redis-lock/blob/master/example/tests/example2_context_test.go) ```golang ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) defer cancel() lock := redislock.NewLock( "order:123", 5*time.Second, redislock.WithContext(ctx), // 传入上下文,上下文完成或者超时会自动释放锁 ) acquired, err := lock.Get() if err != nil { log.Printf("锁获取失败: %v", err) } else if acquired { // 模拟忘记调用Release() // 执行业务逻辑,上下文超时会自动释放锁 } ``` ### [非等待模式](https://gitee.com/worklz/go-redis-lock/blob/master/example/tests/example3_non_wait_test.go) ```golang // 不传入redislock.WithWaitTime(...)锁等待时间,则默认非等待模式,获取锁失败会立即返回 lock := redislock.NewLock( "order:123", 5*time.Second, ) acquired, err := lock.Get() if err != nil { log.Printf("锁获取失败: %v\r\n", err) } else if acquired { defer func() { if _, err := lock.Release(); err != nil { log.Printf("锁释放失败:%v\r\n", err) } }() log.Printf("锁获取成功\r\n") // 执行业务逻辑... } else { log.Printf("锁已被其他携程持有\r\n") } ``` ## 适用场景 - **分布式任务调度**:确保同一时间只有一个节点执行任务 - **资源竞争控制**:控制对共享资源的并发访问 - **幂等性保证**:防止重复处理(如重复支付、重复下单) - **限流控制**:限制对特定资源的访问频率 ## 优势亮点 1. **高性能**:优化的锁获取和释放逻辑,减少Redis通信次数 2. **高可靠性**:完善的错误处理和重试机制 3. **易用性**:简洁的API设计,降低使用门槛 4. **安全性**:多重保障机制,防止死锁和误释放 5. **灵活性**:支持多种配置参数,适应不同场景需求 ## 注意事项 1. 确保Redis服务的高可用性,避免单点故障 2. 合理设置锁的TTL和最大持有时间,平衡安全性和性能 3. 尽量使用`defer release()`模式确保锁的释放 4. 对于长时间运行的任务,考虑使用上下文自动释放机制 ## 兜底特性 若因为一些情况(如:忘记调用Release()主动释放,或一些其他原因导致锁没有释放),在续约结束(超过最大持有时间)后也会被自动释放; 且锁内部设置了Finalizer:当锁对象被GC时强制释放(最后防线),一般也不会触发(除非续约协程挂了),因为续约期间锁对象会被一直引用(所以还是会在续约结束后自动释放)。 ## 许可证 本项目采用MIT许可证,详情参见LICENSE文件。