Skip to content

分布式锁

Cosy 提供的 redis 分布式锁基于 https://github.com/bsm/redislock 封装。

获取锁

go
func ObtainLock(key string, ttl time.Duration, opt *redislock.Options) (*redislock.Lock, error)

示例

go
import (
  "context"
  "fmt"
  "log"
  "time"

  "github.com/uozi-tech/cosy/redis"
  "github.com/bsm/redislock"
  "github.com/redis/go-redis/v9"
)

func main() {
    ctx := context.Background()

	// 尝试获取锁。
	lock, err := redis.ObtainLock("my-key", 100*time.Millisecond, nil)
	if err == redislock.ErrNotObtained {
		fmt.Println("无法获取锁!")
	} else if err != nil {
		log.Fatalln(err)
	}

	// 别忘了延迟释放锁。
	defer lock.Release(ctx)
	fmt.Println("我获得了锁!")

	// 休眠并检查剩余的 TTL。
	time.Sleep(50 * time.Millisecond)
	if ttl, err := lock.TTL(ctx); err != nil {
		log.Fatalln(err)
	} else if ttl > 0 {
		fmt.Println("耶,我仍然持有锁!")
	}

	// 延长我的锁。
	if err := lock.Refresh(ctx, 100*time.Millisecond, nil); err != nil {
		log.Fatalln(err)
	}

	// 再休眠一会儿,然后检查。
	time.Sleep(100 * time.Millisecond)
	if ttl, err := lock.TTL(ctx); err != nil {
		log.Fatalln(err)
	} else if ttl == 0 {
		fmt.Println("现在,我的锁已过期!")
	}
}

参考接口

Key

返回锁使用的 Redis 键。

go
func (l *Lock) Key() string

Metadata

返回锁的元数据。

go
func (l *Lock) Metadata() string

Refresh

使用新的 TTL 扩展锁。如果刷新不成功,可能返回 ErrNotObtained。

go
func (l *Lock) Refresh(ctx context.Context, ttl time.Duration, opt *Options) error

Release

手动释放锁。如果锁未被持有,可能返回 ErrLockNotHeld。

go
func (l *Lock) Release(ctx context.Context) error

TTL

返回剩余的生存时间。如果锁已过期,则返回 0。

go
func (l *Lock) TTL(ctx context.Context) (time.Duration, error)

Token

返回锁设置的令牌值。

go
func (l *Lock) Token() string

配置

go
type Options struct {
    // RetryStrategy 允许自定义锁的重试策略。
    // 默认:不重试
    RetryStrategy RetryStrategy
    
    // Metadata 字符串。
    Metadata string
    
    // Token 是用于标识锁的唯一值。默认情况下,会生成随机令牌。使用此选项可以提供自定义令牌。
    Token string
}

重试策略

重试策略由 package "github.com/bsm/redislock" 提供

ExponentialBackoff

指数回归是一种优化策略,重试时间为 2n 毫秒(n 表示重试次数)。可以设置最小值和最大值,建议最小值不小于 16 毫秒。

go
func ExponentialBackoff(min, max time.Duration) RetryStrategy

LimitRetry

将重试次数限制为最多 max 次。

go
func LimitRetry(s RetryStrategy, max int) RetryStrategy

LinearBackoff

允许以自定义间隔定期重试。

go
func LinearBackoff(backoff time.Duration) RetryStrategy

NoRetry

仅尝试一次获取锁。

go
func NoRetry() RetryStrategy