Go语言对etcd的基本操作

  本文简单介绍Go语言对etcd v3的基本操作。

1. Import package
import (
    "github.com/coreos/etcd/clientv3"
    "github.com/coreos/etcd/mvcc/mvccpb"
)
2. Declare Variables
var cli *clientv3.Client

var serverList = []string{
    "192.168.3.102:2379",
    "192.168.3.105:2379",
    "192.168.3.103:2379",
}
var userName = "root"
var password = "shiajun666"
var dialTimeout = 5
var opTimeout = 5
3. Connect to etcd server
var err error
cli, err := clientv3.New(clientv3.Config{
    Endpoints:   serverList,
    DialTimeout: time.Duration(dialTimeout) * time.Second,
    Username:    userName,
    Password:    password,
})
if err != nil {
    fmt.Println("Connect etcd server failed: ", err)
    return
}
4. Get
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

key := "name"
resp, err := cli.Get(ctx, key)
if err != nil {
    fmt.Printf("Get key[%s] failed: %v
", key, err)
    return
}
if len(resp.Kvs) == 0 {
    fmt.Printf("Key[%s] not exists.
", key)
    return
}

fmt.Println("value: ", string(resp.Kvs[0].Value))
Get 方法的返回值如下:
其中 Header *ResponseHeader 几乎是etcd所有方法返回值中都会包含的,它包含了集群ID、etcd节点成员ID、key全局版本号、raft任期号:
Kvs []*mvccpb.KeyValue 包含多个键值对的信息,几乎etcd所有方法返回的键值对信息都由 mvccpb.KeyValue 表示,其结构如下:
 
5. Get values according to key prefix
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

prefix := "name"
resp, err := cli.Get(ctx, prefix, clientv3.WithPrefix())
if err != nil {
    fmt.Printf("Get key prefix[%s] failed: %v
", prefix, err)
    return
}
if len(resp.Kvs) == 0 {
    fmt.Printf("Key prefix[%s] not exists.
", prefix)
    return
}

fmt.Println("values: ", resp.Kvs)
6. put
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

key := "name"
value := "shiajun"
_, err = cli.Put(ctx, key, value)
if err != nil {
    fmt.Printf("Put key[%s] value[%s] failed: %v
", key, value, err)
    return
}
fmt.Println("put success")
Put 方法返回值如下:
prevKv 表示当前Put操作执行之前该key的键值对信息,Put方法第四个参数加上 clientv3.WithPrevKV() 即可返回该信息,如下一个例子所示。
 
7. put new value and get prev value
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

key := "name"
value := "shiajun"
opts := []clientv3.OpOption{clientv3.WithPrevKV()}
resp, err := cli.Put(ctx, key, value, opts...)
if err != nil {
    fmt.Printf("Put key[%s] value[%s] failed: %v
", key, value, err)
    return
}
fmt.Println("prev value: ", string(resp.PrevKv.Value))
8. put with lease
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

//grant lease
var ttl int64 = 10
lease, err := cli.Grant(ctx, ttl)
if err != nil {
    fmt.Printf("Grant lease failed: %v
", err)
}

//put with lease
key := "name"
value := "shiajun"
_, err = cli.Put(ctx, key, value, clientv3.WithLease(lease.ID))
if err != nil {
    fmt.Printf("Put key[%s] value[%s] with lease[%s] failed: %v
", key, value, lease.ID, err)
}

fmt.Println("put with lease success")
Grant 方法返回值如下:
 
 
9. put with lease and keep alive
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

//grant lease
var ttl int64 = 10
lease, err := cli.Grant(ctx, ttl)
if err != nil {
    fmt.Printf("Grant lease failed: %v
", err)
}

//put with lease
key := "name"
value := "shiajun"
_, err = cli.Put(ctx, key, value, clientv3.WithLease(lease.ID))
if err != nil {
    fmt.Printf("Put key[%s] value[%s] with lease[%s] failed: %v
", key, value, lease.ID, err)
}

//keep alive
kaCh, err := cli.KeepAlive(context.Background(), lease.ID)
if err != nil {
    fmt.Printf("Keep alive key[%s] value[%s] with lease[%s] failed: %v
", key, value, lease.ID, err)
}
for {
    kaResp := <-kaCh
    fmt.Println("ttl: ", kaResp.TTL)
}
KeepAlive 方法返回值为一个channel:<-chan *LeaseKeepAliveResponse,接收每一次 keep alive 的结果返回:
 
10. delete
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

key := "name"
_, err = cli.Delete(ctx, key)
if err != nil {
    fmt.Printf("Delete key[%s] failed: %v
", key, err)
    return
}
fmt.Println("delete success")
Delete 方法返回值如下:
 
11. watch
key := "name"
opts := []clientv3.OpOption{clientv3.WithPrevKV(), clientv3.WithPrefix()}
wCh := cli.Watch(context.Background(), key, opts...)
for resp := range wCh {
    for _, event := range resp.Events {
        if event.Type == mvccpb.PUT {
            fmt.Println("put happens")
        } else if event.Type == mvccpb.DELETE {
            fmt.Println("delete happens")
        }
        fmt.Println("prev value: ", event.PrevKv)
        fmt.Println("value: ", event.Kv)
    }
}
Watch 方法返回值为一个Channel:<-chan WatchResponse,接收watch的结果信息:
对watch的key进行put、delete操作,watch操作即可获得变更结果,示例如下:
 
12. compare and set - transation
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(opTimeout)*time.Second)
defer cancel()

key := "number"
kvc := clientv3.NewKV(cli)
resp, err := kvc.Txn(ctx).
    If(clientv3.Compare(clientv3.Value(key), ">", "0")).
    Then(clientv3.OpPut(key, "100")).
    Else(clientv3.OpPut(key, "99")).
    Commit()
if err != nil {
    fmt.Errorf("Compare and set transation failed: %v
", err)
}

fmt.Println(resp.Succeeded)
这是使用etcd事务实现的一个先比较再赋值的简单例子:若 number 的值大于0,则将number赋值为100,否则赋值为99。
 
 

原文地址:https://www.cnblogs.com/wujuntian/p/15130668.html