当前位置:网站首页>Golang+redis distributed mutex
Golang+redis distributed mutex
2022-06-24 15:47:00 【lestat】
introduction
Suppose one of our businesses involves data updating , At the same time, there is a large amount of concurrency in the actual scenario . technological process : Read -> modify -> preservation , Based on DB In the case of concurrent processing of layer , This scenario may cause unexpected execution results for some data , At this point, you can consider using distributed locks to solve this problem
Problems to be solved
- False release of lock
- Business execution timeout causes concurrency
- Retry mechanism
GETandDELNon atomicity
Code
Directory structure :
│ main.go
│
└─demo
lock.golock.go:
package demo
import (
"context"
"fmt"
"github.com/go-redis/redis/v8"
"math/rand"
"time"
)
// Retry count
var retryTimes = 5
// Retry frequency
var retryInterval = time.Millisecond * 50
var rdb = redis.NewClient(&redis.Options{
Addr: "localhost:6379",
Password: "", // no password set
DB: 0, // use default DB
})
// The default expiration time of the lock
var expiration time.Duration
// Simulate the locking scenario of distributed services
func MockTest(tag string) {
var ctx, cancel = context.WithCancel(context.Background())
defer func() {
// stop it goroutine
cancel()
}()
// Random value
lockV := getRandValue()
lockK := "EXAMPLE_LOCK"
// Default expiration time
expiration = time.Millisecond * 200
fmt.Println(tag + " Try to lock ")
set, err := rdb.SetNX(ctx, lockK, lockV, expiration).Result()
if err != nil {
panic(err.Error())
}
// Locking failed , retry
if set == false && retry(ctx, rdb, lockK, lockV, expiration, tag) == false {
fmt.Println(tag + " server unavailable, try again later")
return
}
fmt.Println(tag + " Lock successfully ")
// Locking success , Add a new daemon thread
go watchDog(ctx, rdb, lockK, expiration, tag)
// Deal with business ( Through random time delay simulation )
fmt.Println(tag + " Wait for the business processing to complete ...")
time.Sleep(getRandDuration())
// Business processing completed
// Release the lock
val := delByKeyWhenValueEquals(ctx, rdb, lockK, lockV)
fmt.Println(tag+" Release results :", val)
}
// Release the lock
func delByKeyWhenValueEquals(ctx context.Context, rdb *redis.Client, key string, value interface{}) bool {
lua := `
-- If the current value is consistent with the lock value , Delete key
if redis.call('GET', KEYS[1]) == ARGV[1] then
return redis.call('DEL', KEYS[1])
else
return 0
end
`
scriptKeys := []string{key}
val, err := rdb.Eval(ctx, lua, scriptKeys, value).Result()
if err != nil {
panic(err.Error())
}
return val == int64(1)
}
// Generate random time
func getRandDuration() time.Duration {
rand.Seed(time.Now().UnixNano())
min := 50
max := 100
return time.Duration(rand.Intn(max-min)+min) * time.Millisecond
}
// Generate random values
func getRandValue() int {
rand.Seed(time.Now().UnixNano())
return rand.Int()
}
// The guardian thread
func watchDog(ctx context.Context, rdb *redis.Client, key string, expiration time.Duration, tag string) {
for {
select {
// Business done
case <-ctx.Done():
fmt.Printf("%s Task to complete , close %s Automatic renewal of \n", tag, key)
return
// Business not completed
default:
// Automatic renewal
rdb.PExpire(ctx, key, expiration)
// Continue to wait for
time.Sleep(expiration / 2)
}
}
}
// retry
func retry(ctx context.Context, rdb *redis.Client, key string, value interface{}, expiration time.Duration, tag string) bool {
i := 1
for i <= retryTimes {
fmt.Printf(tag+" The first %d Attempts to lock ...\n", i)
set, err := rdb.SetNX(ctx, key, value, expiration).Result()
if err != nil {
panic(err.Error())
}
if set == true {
return true
}
time.Sleep(retryInterval)
i++
}
return false
}Process description
hypothesis
MockTestMethods are business processing methods
- initialization
contextUsed to control the exit of the daemon thread - Set random value to try to lock ( Random value can avoid false release when releasing lock )
- If locking fails , Try again , The retry mechanism depends on the business , Retry failure processing depends on the business
- Open a daemon thread after locking successfully (
watchDog), The expiration time used to continuously refresh the lock , Ensure that the lock will not expire during business execution - Simulation of random time-consuming business processing
- Release the lock after business processing (
luaProcessing ensures atomicity , And comparevalueAvoid accidental release ) - adopt
cancelClose the daemon thread (watchDog), Avoid deadlock
Respond to the scene
- The thread terminates abnormally after obtaining the lock , The lock will be there
expireAutomatically release after expiration - Thread execution time exceeds the default value of the lock
expire, adoptwatchDogAutomatic renewal , Avoid this
test
main.go:
package main
import (
"play/demo"
"time"
)
func main() {
go demo.MockTest("A")
go demo.MockTest("B")
go demo.MockTest("C")
go demo.MockTest("D")
go demo.MockTest("E")
// Used for testing goroutine Received ctx.Done() Printing after signal
time.Sleep(time.Second * 2)
}result :
$ go run main.go A Try to lock D Try to lock E Try to lock B Try to lock C Try to lock D Lock successfully D Wait for the business processing to complete ... B The first 1 Attempts to lock ... E The first 1 Attempts to lock ... A The first 1 Attempts to lock ... C The first 1 Attempts to lock ... B The first 2 Attempts to lock ... D Release results : true B Lock successfully E The first 2 Attempts to lock ... B Wait for the business processing to complete ... C The first 2 Attempts to lock ... A The first 2 Attempts to lock ... D Task to complete , close EXAMPLE_LOCK Automatic renewal of A The first 3 Attempts to lock ... C The first 3 Attempts to lock ... E The first 3 Attempts to lock ... B Release results : true A Lock successfully A Wait for the business processing to complete ... B Task to complete , close EXAMPLE_LOCK Automatic renewal of E The first 4 Attempts to lock ... C The first 4 Attempts to lock ... A Release results : true A Task to complete , close EXAMPLE_LOCK Automatic renewal of C The first 5 Attempts to lock ... E The first 5 Attempts to lock ... C Lock successfully C Wait for the business processing to complete ... E server unavailable, try again later C Release results : true C Task to complete , close EXAMPLE_LOCK Automatic renewal of
If you are lazy, you don't write unit tests
边栏推荐
- FreeRTOS新建任务不执行问题解决办法
- Remote connection raspberry pie in VNC Viewer Mode
- Es search content top
- Database tools in intelij can connect but cannot display schema, tables
- 中国产品经理的没落:从怀恋乔布斯开始谈起
- How to efficiently transfer enterprise business data?
- Paper: Google TPU
- Attacked! Cloud development monitoring alarm practice
- 【C语言刷题——Leetcode12道题】带你起飞,飞进垃圾堆
- [tke] multiple ingress controllers are used in the cluster
猜你喜欢

MySQL binlog

FreeRTOS新建任务不执行问题解决办法

设备通过国标GB28181接入EasyCVR平台,出现断流情况该如何解决?

How to generate assembly code using clang in Intel syntax- How to generate assembly code with clang in Intel syntax?

Still worried about missing measurements? Let's use Jacobo to calculate the code coverage

CAP:多重注意力机制,有趣的细粒度分类方案 | AAAI 2021

Database tools in intelij can connect but cannot display schema, tables

Linux记录-4.22 MySQL5.37安装(补充)

还在担心漏测吗?快来使用jacoco统计下代码覆盖率

熬夜整理出的软件测试【高频】面试题大全(2022最新)
随机推荐
CIA security model - use PGP to describe privacy and integrity of network security CIA model
Sequential representation and implementation of linear table (refer to YanWeiMin version)
How to use nested tags in thymeleaf3 Tags
Easy installation of Jenkins
The equipment is connected to the easycvr platform through the national standard gb28181. How to solve the problem of disconnection?
Xingxinghai, it is said that the new generation can fight better?
Crmeb multi merchant system applet authorization problem solving paste
Logstash introduction and simple case
Most common usage of vim editor
Mysql之Binlog
Use tuples
"Industry foresight" future development trend of intelligent security monitoring industry
Use dictionary
This website teaches you to imitate more than 100 well-known websites!
Apple is no match for the longest selling mobile phone made in China, and has finally brought back the face of the domestic mobile phone
CAP:多重注意力机制,有趣的细粒度分类方案 | AAAI 2021
Motion planning of floating base robot
如何轻松实现在线K歌房,与王心凌合唱《山海》
How to modify the login user name of easynvr video monitoring system?
Junit5中的参数化测试(Parameterized Tests)指南