golang etcd 操作
go get -u -x google.golang.org/grpc@v1.26.0
package main
import (
"context"
"fmt"
"time"
"github.com/coreos/etcd/clientv3"
)
func main() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"localhost:2379"},
DialTimeout: time.Duration(5) * time.Second,
})
if err != nil {
fmt.Println("connect failed, err", err)
return
}
fmt.Println("connect success")
defer cli.Close()
for {
ctx, cancel := context.WithCancel(context.Background())
fmt.Println("Please input xi value:")
var xiValue string
fmt.Scanln(&xiValue)
// 如果输入exit,退出程序
if xiValue == "exit" {
break
}
_, err = cli.Put(ctx, "/xi", xiValue)
cancel()
if err != nil {
fmt.Println("put failed, err: ", err)
return
}
ctx, cancel = context.WithCancel(context.Background())
resp, err := cli.Get(ctx, "/xi")
cancel()
if err != nil {
fmt.Println("get failed, err: ", err)
return
}
for _, ev := range resp.Kvs {
fmt.Printf("%s, %s\n", ev.Key, ev.Value)
}
}
}
etcd 实现分布式锁
package example
import (
"context"
"fmt"
"sync"
"testing"
"github.com/coreos/etcd/clientv3"
)
var (
cnt int
// expect int
)
func worker(i int) int {
cnt++
return 1
}
type XLock struct {
lease clientv3.Lease
kv clientv3.KV
LockKey string
cancelFunc context.CancelFunc
}
func New(cli *clientv3.Client) *XLock {
return &XLock{
lease: clientv3.NewLease(cli),
kv: clientv3.NewKV(cli),
LockKey: "simple0",
// cancelFunc: context.CancelFunc,
}
}
func (u *XLock) LockTest0() (err error) {
var (
leaseGrantResp *clientv3.LeaseGrantResponse
cancelCtx context.Context
cancelFunc context.CancelFunc
leaseid clientv3.LeaseID
keepRespChan <-chan *clientv3.LeaseKeepAliveResponse
)
if leaseGrantResp, err = u.lease.Grant(context.TODO(), 5); err != nil {
return
}
leaseid = leaseGrantResp.ID
// 释放租约
defer u.lease.Revoke(context.TODO(), leaseid)
cancelCtx, cancelFunc = context.WithCancel(context.TODO())
defer cancelFunc()
if keepRespChan, err = u.lease.KeepAlive(cancelCtx, leaseid); err != nil {
// goto FAIL
return err
}
_ = keepRespChan
go func() {
var (
keepResp *clientv3.LeaseKeepAliveResponse
)
for {
select {
case keepResp = <-keepRespChan:
if keepResp == nil {
goto END
}
}
}
END:
}()
// 创建 etcd 事务
txn := u.kv.Txn(context.TODO())
lockkey := u.LockKey
txn.If(clientv3.Compare(clientv3.CreateRevision(lockkey), "=", 0)).Then(clientv3.OpPut(lockkey, "", clientv3.WithLease(leaseid))).
Else(clientv3.OpGet(lockkey))
// 提交事务
var (
txnResp *clientv3.TxnResponse
)
if txnResp, err = txn.Commit(); err != nil {
return err
}
if !txnResp.Succeeded {
fmt.Println("版本更新了!")
// return fmt.Errorf("失败更新")
}
fmt.Println("dot it")
cnt++
// return fmt.Errorf("error 0 %w", err)
return nil
}
func Test_llock(t *testing.T) {
if client, err = clientv3.New(conf); err != nil {
t.Log(err)
return
}
maxn := 50
var wg sync.WaitGroup
for i := 0; i < maxn; i++ {
wg.Add(1)
go func() {
ll := New(client)
ll.LockTest0()
wg.Done()
}()
}
wg.Wait()
if cnt != maxn {
t.Errorf("errror cnt=%d, want %d", cnt, maxn)
} else {
t.Logf("succeess cnt=%d, want %d", cnt, maxn)
}
}