分布式锁在后台应用广泛,抢票系统,秒杀系统都能看到它的身影,实现分布式锁的方式有很多,比如zookeeper,redis,以及etcd。下面用一个简单的用例来说明etcd的实现。
package main
import (
"context"
"fmt"
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/clientv3/concurrency"
"log"
"time"
)
func main() {
cli,err := clientv3.New(clientv3.Config{
Endpoints: []string{"localhost:12379", "localhost:22379", "localhost:32379"},
AutoSyncInterval: 0,
DialTimeout: 5 * time.Second,
DialKeepAliveTime: 0,
DialKeepAliveTimeout: 0,
MaxCallSendMsgSize: 0,
MaxCallRecvMsgSize: 0,
TLS: nil,
Username: "",
Password: "",
RejectOldCluster: false,
DialOptions: nil,
Context: nil,
})
if err != nil{
log.Fatal("err:",err.Error())
}
// 创建两个单独的会话用来演示锁竞争
s1,err := concurrency.NewSession(cli)
if err != nil{
log.Fatal(err)
}
defer s1.Close()
m1 := concurrency.NewMutex(s1,"/my-lock/")
s2,err := concurrency.NewSession(cli)
if err != nil{
log.Fatal(err)
}
defer s2.Close()
m2 := concurrency.NewMutex(s2,"/my-lock/")
// 会话s1获取锁
if err := m1.Lock(context.TODO());err != nil{
log.Fatal(err)
}
m2Locked := make(chan struct{})
go func() {
defer close(m2Locked)
// 等待直到会话s1释放了/my-lock/的锁
if err := m2.Lock(context.TODO());err != nil{
log.Fatal(err)
}
fmt.Println("m2 locked")
}()
if err := m1.Unlock(context.TODO());err != nil{
log.Fatal(err)
}
fmt.Println("released lock for s1")
<- m2Locked
fmt.Println("acquired lock for s2")
}