参考这篇文章# Redis分布式锁的正确实现方式 实现的分布式锁
整个过程可以分为四步:
+先用SETNX设置key。key是唯一的,统一时刻只有一个客户端的setnx指令能成功,满足锁的唯一性。如果成功,说明没有人持有锁,否则锁被占有,则获取锁的释放时间,然后进入睡眠。睡眠时间为一个任意的值,小于锁的TTL。
- 用EXPIRE设置key。expire是为了防止客户端崩溃锁变成死锁。SETNX和EXPIRE两个指令应该是原子的,go下面没法实现。需要修改redis支持。
- 获取到锁后干活
- 释放锁
package main
import (
"fmt"
"time"
"os"
"strconv"
"github.com/gomodule/redigo/redis"
)
const dist_lock = "distlock"
func main() {
redis_conn, err := redis.Dial("tcp", "127.0.0.1:6379", redis.DialPassword("hdiot"))
if err != nil {
fmt.Println(err)
return
}
defer redis_conn.Close()
pidstr := strconv.Itoa(os.Getpid())
for {
fmt.Println("try lock")
_, err := redis_conn.Do("SETNX", dist_lock, pidstr)
if err != nil {
fmt.Println(err)
ttl, err := redis.Int(redis_conn.Do("TTL", dist_lock))
if err != nil {
fmt.Println(err)
}
time.Sleep(time.Duration(ttl/2) * time.Second)
} else {
// we get lock
break;
}
}
_, err = redis_conn.Do("EXPIRE", dist_lock, 10)
if err != nil {
fmt.Println(err)
return
}
// do something
fmt.Println("get lock")
// release lock
pid_ret, err := redis.String(redis_conn.Do("GET", dist_lock))
if err != nil {
fmt.Println(err)
return
}
pid, _ := strconv.Atoi(pid_ret)
if(pid != os.Getpid()) {
fmt.Println("not my lock")
return
}
_, err = redis_conn.Do("Del", dist_lock)
if err != nil {
fmt.Println(err)
return
}
fmt.Println("release lock ok")
}
网友评论