英文:
Redis distributed lock does not take effect
问题
我正在使用go-redis distributed lock
实现互斥访问,我的服务器是单线程服务器。但是同时有很多请求获取到了distributed lock
。
获取锁的代码如下:
func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
encodeKey := transcoding.Base64Encode(key)
_, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
if err != nil {
return -1
}
return 0
}
func (redisMgrPtr *RedisMgr) delLock(key string, sessionId string) {
encodeKey := transcoding.Base64Encode(key)
redisMgrPtr.redisClient.Del(redisMgrPtr.ctx, encodeKey)
Log.Errorf("session[%s] del lock", sessionId)
}
获取锁的代码如下:
func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
for {
locRes := redisMgrPtr.getLock(name)
if locRes == 0 {
break
} else {
time.Sleep(5 * time.Millisecond)
continue
}
}
defer redisMgrPtr.delLock(sceneLock, sessionId)
Log.Errorf("session[%s] get lock", sessionId)
// do something
}
我发现很多请求同时获取到了锁,结果如下:
2021-09-08T15:05:21.073+0800 session[51776955325] get lock
2021-09-08T15:05:21.073+0800 session[91776955325] get lock
2021-09-08T15:05:21.073+0800 session[71776955325] get lock
我认为在同一时间只有一个会话可以获取到锁。
英文:
I am using go-redis distributed lock
to realize mutual exclusion access, my server is a single thread server. But at the same time, many requests get the distributed lock
.
func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
encodeKey := transcoding.Base64Encode(key)
_, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx,
encodeKey, 1, TIMEOUT).Result()
if err != nil {
return -1
}
return 0
}
func (redisMgrPtr *RedisMgr) delLock(key string, sessionId string) {
encodeKey := transcoding.Base64Encode(key)
redisMgrPtr.redisClient.Del(redisMgrPtr.ctx, encodeKey)
Log.Errorf("session[%s] del lock", sessionId)
}
Get lock code is like this:
func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
for {
locRes := redisMgrPtr.getLock(name)
if locRes == 0 {
break
} else {
time.Sleep(5 * time.Millisecond)
continue
}
}
defer redisMgrPtr.delLock(sceneLock, sessionId)
Log.Errorf("session[%s] get lock", sessionId)
// do something
}
I find many requests get the lock at the same time, result is
2021-09-08T15:05:21.073+0800 session[51776955325] get lock
2021-09-08T15:05:21.073+0800 session[91776955325] get lock
2021-09-08T15:05:21.073+0800 session[71776955325] get lock
I think at the same time only one session can get the lock
答案1
得分: 2
问题似乎出在锁定函数上。它没有检查值是否存在,只是检查了错误。
func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
encodeKey := transcoding.Base64Encode(key)
wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
if err != nil || !wasSet {
return -1
}
return 0
}
... 或者使用布尔值使其更易于理解:
func (redisMgrPtr *RedisMgr) getLock(key string) (ok bool) {
encodeKey := transcoding.Base64Encode(key)
wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
return err == nil && wasSet
}
使用布尔值版本,GetServer
可以这样写:
func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
for {
if ok := redisMgrPtr.getLock(name); ok {
break
}
time.Sleep(5 * time.Millisecond)
}
defer redisMgrPtr.delLock(sceneLock, sessionId)
Log.Errorf("session[%s] get lock", sessionId)
// 做一些操作
}
英文:
The problem seems to be with the lock function. It does not check if the value existed or not, it just checks the error.
func (redisMgrPtr *RedisMgr) getLock(key string) (int32) {
encodeKey := transcoding.Base64Encode(key)
wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
if err != nil || !wasSet {
return -1
}
return 0
}
... or using a boolean to make it easier to reason about:
func (redisMgrPtr *RedisMgr) getLock(key string) (ok bool) {
encodeKey := transcoding.Base64Encode(key)
wasSet, err := redisMgrPtr.redisClient.SetNX(redisMgrPtr.ctx, encodeKey, 1, TIMEOUT).Result()
return err == nil && wasSet
}
With the boolean version GetServer
could look like this:
func (redisMgrPtr *RedisMgr) GetServer(name string, session string) () {
for {
if ok := redisMgrPtr.getLock(name); ok {
break
}
time.Sleep(5 * time.Millisecond)
}
defer redisMgrPtr.delLock(sceneLock, sessionId)
Log.Errorf("session[%s] get lock", sessionId)
// do something
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论