golang Redis 分布式锁 - Go语言中文社区

golang Redis 分布式锁


参考:https://redis.io/topics/distlock

代码:

package internal

import (
	"errors"
	"fmt"
	"github.com/garyburd/redigo/redis"
)

type RedisLock struct {
	//保存连接
	Conn *redis.Conn
	//生成随机value用于判断是否为自己上锁
	uuid string
	//锁状态
	lock bool
}

/**
初始化
*/
func (redisLock *RedisLock) Init(protocolType string, ipAddress string, passWord string) error {
	conn, err := createConn(protocolType, ipAddress, passWord)
	if err != nil {
		return err
	}

	redisLock.Conn = &conn
	return nil
}

/**
创建redis连接
*/
func createConn(protocolType string, redisAddress string, password string) (redis.Conn, error) {
	var conn redis.Conn
	var err error
	if password == "" {
		conn, err = redis.Dial(protocolType, redisAddress)
	} else {
		conn, err = redis.Dial(protocolType, redisAddress, redis.DialPassword(password))
	}
	if err != nil {
		return nil, err
	}

	return conn, nil
}

/**
尝试上锁
*/
func (redisLock *RedisLock) tryLock(key string) (bool, error) {
	//如果判断已经在锁定状态则直接返回
	if redisLock.lock {
		return true, nil
	}

	//生成uuid
	if redisLock.uuid == "" {
		redisLock.uuid = NewUUID()
	}

	//NX 若Key存在则无法修改其值
	//EX 过期时间 单位 秒
	result, err := (*redisLock.Conn).Do("SET", key, redisLock.uuid, "NX", "EX", 300)
	if err != nil {
		return false, err
	}

	if result == "OK" {
		redisLock.lock = true
		return redisLock.lock, nil
	}

	return false, nil
}

/**
释放锁
*/
func (redisLock *RedisLock) removeLock(key string) (bool, error) {
	if !redisLock.lock {
		return false, errors.New("Unlocked ")
	}

	//判断锁是否为自己使用
	script := "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end"

	//使用脚本方式
	result, err := redis.Bool((*redisLock.Conn).Do("EVAL", script, 1, key, redisLock.uuid))
	if err != nil {
		return result, err
	}

	return result, nil
}

/**
锁模版
*/
func (redisLock *RedisLock) LockForRedis(key string, f func()) error {
	result, err := redisLock.tryLock(key)
	if err != nil {
		return err
	}

	if !result {
		return errors.New("continue")
	}

	fmt.Println("tryLock")

	f()

	result, err = redisLock.removeLock(key)
	if err != nil {
		return err
	}

	if result {
		fmt.Println("removeLock")
	}

	return nil
}

guid:

package internal

import (
	"github.com/typa01/go-utils"
)

func NewGUID() string {
	return tsgutils.GUID()
}

func NewUUID() string {
	return tsgutils.UUID()
}

 test:

func main() {
	fmt.Println("Start......")

	count := 200

	wg := sync.WaitGroup{}
	wg.Add(count)
	for i := 0; i < count; i++ {
		go func() {
			test()
			//testLock()
			wg.Done()
		}()
		//time.Sleep(time.Millisecond * 5)
	}

	wg.Wait()

	fmt.Println(n)
	fmt.Println("End......")
}

func test() {
	n = n + 1
}

上述方式输出结果不确定:

Start......
193
End......

带有锁版本:

const ipAddress = "192.168.170.137:6379"
const protocolType = "tcp"
const passWord = "myredis123"

func main() {
	fmt.Println("Start......")

	count := 200

	wg := sync.WaitGroup{}
	wg.Add(count)
	for i := 0; i < count; i++ {
		go func() {
			test()
			testLock()
			wg.Done()
		}()
		//time.Sleep(time.Millisecond * 5)
	}

	wg.Wait()

	fmt.Println(n)
	fmt.Println("End......")
}

func testLock() {
	key := "myLockKey"

	redisLock := new(internal.RedisLock)
	redisLock.Init(protocolType, ipAddress, passWord)

	result := redisLock.LockForRedis(key, test)
	if result != nil {
		fmt.Println(result)
	}
}

func test() {
	n = n + 1
}

输出:

Start......
continue
continue
continue
continue
continue
continue
continue
tryLock
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
tryLock
removeLock
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
removeLock
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
continue
2
End......

由于在锁定状态直接跳过所以只有拿到了锁的coroutine才有资格进行 n+n+1的操作,上述结果中存在98个continue所以结果为2是正确的。

延长for循环时间:

func main() {
	fmt.Println("Start......")

	count := 200

	wg := sync.WaitGroup{}
	wg.Add(count)
	for i := 0; i < count; i++ {
		go func() {
			testLock()
			wg.Done()
		}()
		time.Sleep(time.Millisecond )
	}

	wg.Wait()

	fmt.Println(n)
	fmt.Println("End......")
}

输出:

Start......
continue
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
continue
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
continue
tryLock
removeLock
tryLock
removeLock
continue
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
tryLock
removeLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
continue
tryLock
removeLock
continue
tryLock
removeLock
continue
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
continue
continue
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
continue
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
tryLock
removeLock
174
End......

 continue数量与实际计算结果:

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_40165163/article/details/105456154
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-04-18 22:51:23
  • 阅读 ( 1509 )
  • 分类:Go

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢