1.安装
wget下载地址 https://mirrors.huaweicloud.c...
etcd.config
name: "etcd"
data-dir: "/var/lib/etcd/data"
listen-client-urls: "http://0.0.0.0:2379"
advertise-client-urls: "http://0.0.0.0:2379"
启动
./etcd --config-file=/opt/etcd/etcd.config
2.基本命令
设置key
etcdctl put slq1 1
获取key
etcdctl get slq1 //获取key为slq1的value
etcdctl get slq1 --print-value-only //只打印对应的值
etcdctl get slq1 --hex //以十六进制显示
etcdctl get slq1 slq5 //获取一定范围的key 不包括slq5
etcdctl get --prefix slq //获取以slq为前缀的key
etcdctl get --limit=2 --prefix slq //限制数量为2
etcdctl get --from-key s //查找大于s的所有key
etcdctl get --prefix --rev=4 slq1 //获取slq1 key version为4时候对应的值
删除key
etcdctl del slq1 //删除slq1
etcdctl del slq1 slq5 //删除slq1到slq5的key
etcdctl del --prefix slq //删除前缀为slq的key
etcdctl del --from-key s //删除大于s的所有key
监听key变化
etcdctl watch slq1 //监测slq1
etcdctl watch slq1 slq5 //监测slq1到slq5的key
etcdctl watch --prefix slq //监测前缀为slq的key
etcdctl watch --from-key s //监测大于s的所有key
对key进行加锁
etcdctl lock slq1
------------------------------------
[root@node3 opt]# etcdctl lock slq1
slq1/694d7afa84f70318
------------------------------------
[root@node3 etcd]# etcdctl lock slq1
发生阻塞
------------------------------------
事务txn
etcdctl txn -i //-i使用交互式
清理历史版本信息compact
etcdctl compact 5
[root@prometheus ~]# etcdctl compact 3
compacted revision 3
[root@prometheus ~]#
lease和ttl
[root@prometheus ~]# etcdctl lease grant 100
lease 694d7afa84f70339 granted with TTL(100s)
[root@prometheus ~]#
[root@prometheus ~]#
[root@prometheus ~]# etcdctl put --lease=694d7afa84f70339 slqslq slq
OK
[root@prometheus ~]#
[root@prometheus ~]# etcdctl get slqslq
slqslq
slq
[root@prometheus ~]#
撤销租期
[root@prometheus ~]# etcdctl lease revoke 694d7afa84f70339
lease 694d7afa84f70339 revoked
[root@prometheus ~]#
[root@prometheus ~]#
[root@prometheus ~]# etcdctl get slqslq
[root@prometheus ~]#
查看租期有效时间
[root@prometheus ~]# etcdctl lease timetolive 694d7afa84f70343
lease 694d7afa84f70343 granted with TTL(100s), remaining(66s)
保持租期有效
etcdctl lease keep-alive 694d7afa84f70339
[root@prometheus ~]# etcdctl lease keep-alive 694d7afa84f70343
lease 694d7afa84f70343 keepalived with TTL(100)
3.clientv3操作api
下载包
go get -u go.etcd.io/etcd/clientv3@v3.3.24
程序
package main
import(
"context"
"fmt"
"go.etcd.io/etcd/clientv3"
"log"
"time"
)
//基本操作
//其他操作的查询、设置和删除 详细请参考源码
// Get retrieves keys.
// By default, Get will return the value for "key", if any.
// When passed WithRange(end), Get will return the keys in the range [key, end).
// When passed WithFromKey(), Get returns keys greater than or equal to key.
// When passed WithRev(rev) with rev > 0, Get retrieves keys at the given revision;
// if the required revision is compacted, the request will fail with ErrCompacted .
// When passed WithLimit(limit), the number of returned keys is bounded by limit.
// When passed WithSort(), the keys will be sorted.
func main() {
client, err := clientv3.New(clientv3.Config{
Endpoints: []string{"http://192.168.56.111:2379"},
DialTimeout: 2 * time.Second,
})
if err != nil {
log.Println("create client err:",err)
}
defer client.Close()
keyName := "slq0909"
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
_, err = client.Put(ctx, keyName, "xxxxxx")
cancel()
if err != nil {
log.Printf("put to etcd failed,err:%v \n",err)
return
}
ctx, cancel = context.WithTimeout(context.Background(), time.Second)
resp,err := client.Get(ctx, keyName)
cancel()
if err != nil {
log.Println("get keyname err:",err)
}
for _,ev := range resp.Kvs {
fmt.Printf("%s:%s \n",ev.Key,ev.Value)
}
ctx, cancel = context.WithTimeout(context.Background(), time.Second)
respon, err := client.Delete(ctx, keyName)
cancel()
if err != nil {
log.Println("del keyname err:",err)
}
log.Println("delete result :",respon)
}
//watch
func main() {
client, err := clientv3.New(clientv3.Config{
Endpoints: []string{"http://192.168.56.111:2379"},
DialTimeout: 2 * time.Second,
})
if err != nil {
log.Println("create client err:",err)
}
defer client.Close()
keyName := "slq0909"
watch := client.Watch(context.Background(), keyName)
for resp := range watch {
for _,ev := range resp.Events {
fmt.Printf("Type: %s Key:%s Value:%s\n", ev.Type, ev.Kv.Key, ev.Kv.Value)
}
}
}
4.concurrency 分布式锁
版本一
package main
import (
"context"
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/clientv3/concurrency"
"log"
"time"
)
func main() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"http://192.168.56.111:2379"},
DialTimeout: 2 * time.Second,
})
if err != nil {
log.Println("create client err:", err)
}
defer cli.Close()
session, err := concurrency.NewSession(cli)
if err != nil {
log.Println("session err :",err)
}
mutex := concurrency.NewMutex(session, "/slq")
err = mutex.Lock(context.Background())
if err != nil {
log.Println("don't get mutex:",err)
}else {
log.Println("get mutex:",err)
}
time.Sleep(time.Second * 5)
mutex.Unlock(context.Background())
log.Println("finished get mutex:",err)
}
//利用原生的concurrency.NexMutex(),实现分布式锁,缺点是如果协程没有抢到锁会一直阻塞住,所以需要加租期时间
版本2
package main
import (
"context"
"github.com/coreos/etcd/clientv3"
"github.com/coreos/etcd/clientv3/concurrency"
"log"
"time"
)
var client *clientv3.Client
func init() {
cli, err := clientv3.New(clientv3.Config{
Endpoints: []string{"http://192.168.56.111:2379"},
DialTimeout: 2 * time.Second,
})
if err != nil {
log.Println("create client err:", err)
}
client = cli
}
func main() {
disLock("/slq",60, func() {
log.Println("func start")
time.Sleep(time.Second * 4)
log.Println("func end")
})
}
/**
key: 加锁key
timeout: 超时时间,此时间包含整个任务加锁执行时间,是disLock函数整个执行的时间,如果超过timeout的时间,即使业务逻辑执行完成了,也会失败
x: 业务逻辑
*/
func disLock(key string,timeout int64,x func()) {
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(timeout) * time.Second)
defer cancel()
lease, err := client.Grant(ctx, timeout)
session, err := concurrency.NewSession(client, concurrency.WithLease(lease.ID))
if err != nil {
log.Println("session err :", err)
}
defer session.Close()
mutex := concurrency.NewMutex(session, key)
log.Println("start get mutex:", err)
err = mutex.Lock(ctx)
if err != nil {
log.Println("don't get mutex:", err)
} else {
log.Println("get mutex:", err)
}
x()
log.Println("unlock mutex:", err)
err = mutex.Unlock(ctx)
if err != nil {
log.Println("unlock mutex error:", err)
}
log.Println("finished get mutex:", err)
}
问题
A. 安装clientv3遇到的问题
go: downloading golang.org/x/net v0.0.0-20210726213435-c6fcb2dbf985
# github.com/coreos/etcd/clientv3/balancer/picker
..\..\go\pkg\mod\github.com\coreos\etcd@v3.3.25+incompatible\clientv3\balancer\picker\err.go:37:44: undefined: balancer.PickOptions
..\..\go\pkg\mod\github.com\coreos\etcd@v3.3.25+incompatible\clientv3\balancer\picker\roundrobin_balanced.go:55:54: undefined: balancer.PickOptions
# github.com/coreos/etcd/clientv3/balancer/resolver/endpoint
..\..\go\pkg\mod\github.com\coreos\etcd@v3.3.25+incompatible\clientv3\balancer\resolver\endpoint\endpoint.go:114:78: undefined: resolver.BuildOption
..\..\go\pkg\mod\github.com\coreos\etcd@v3.3.25+incompatible\clientv3\balancer\resolver\endpoint\endpoint.go:182:31: undefined: resolver.ResolveNowOption
go.mod
replace google.golang.org/grpc => google.golang.org/grpc v1.26.0
B. time.Duration()
不能和变量进行相乘
time.Second * timeout //编译报错
time.Duration(timeout) * time.Second //官方推荐
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。