Go-etcd学习笔记

281 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第28天,点击查看活动详情

前言

在使用Go语言进行开发或者k8s中,总能看见etcd的身影,那么它是什么呢?下面就来学习一下

介绍

A distributed, reliable key-value store for the most critical data of a distributed system

根据官方的说法,etcd是一个分布式、可靠的键值对的存储系统,同时etcd是使用Go来开发、开源的。通常用来当作注册中心、配置管理、分布式锁等,大多数情况下还是被用来做注册中心,即类似于Java微服务中的eurekazookeeper等。

etcd具有以下的一些特点:

  • 高可用:集群中的每个节点都有完整的数据保存,避免某个单点故障所导致的数据丢失。
  • 速度较快:每秒有近1w次的写入速度、1~10w次的读取速度
  • 出色跨平台性:因为是Go语言开发,因此能够在多个平台上部署。
  • 安全:通信支持SSL证书
  • 可靠:基于Raft算法实现了强一致性、高可用的服务存储目录

PS: Raft是一个用于管理日志一致性的协议。

下载

我们去到官网进行下载相关平台的etcd:github.com/etcd-io/etc…

在这里我选择etcd-v3.5.5-windows-amd64.zip的版本进行下载安装。

随后点击etcd.exe进行启动excd的服务器,默认服务器处理请求的端口为2379

测试一下

需要注意V2V3的命名并不兼容,这里使用的是V3常用的命令:

  • 增改键值对:etcdctl put KEY VALUE
  • 获得对应键值对:etcdctl get KEY
  • 模糊查询前缀为PREFIX的数据:etcdctl get --prefix PREFIX
  • 删除对应键值对:etcdctl del KEY
  • 查看etcd版本:etcdctl version

这里需要注意etcd的存储格式、目前仅支持键值对,同时键以目录树的结构进行存储。

Go+etcd

下面使用Go来连接etcd来进行crud

引入依赖

  • go get go.etcd.io/etcd/clientv3
  • go get -u -x google.golang.org/grpc@v1.26.0

CRUD

func testEtcd() {
    client, err := clientv3.New(clientv3.Config{Endpoints: []string{"localhost:2379"}})
    if err != nil {
        panic(err)
    }
    defer client.Close()
    client.Put(GetTimeOutCtx(), "/demo/1", "just value") // put
    getResp, _ := client.Get(GetTimeOutCtx(), "/demo/1") // get
    for _, kv := range getResp.Kvs {
        fmt.Printf("key=%s\tvalue=%s\n", kv.Key, kv.Value) 
    }
    client.Delete(GetTimeOutCtx(), "/demo1/1") // delete
​
}
​
func GetTimeOutCtx() context.Context {
    ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
    return ctx
}
​

前缀查询

func testPrefixGet() {
   client, err := clientv3.New(clientv3.Config{Endpoints: []string{"localhost:2379"}})
   if err != nil {
      panic(err)
   }
   defer client.Close()
   client.Put(GetTimeOutCtx(), "/demo/1", "1")
   client.Put(GetTimeOutCtx(), "/demo/2", "2")
   response, _ := client.Get(GetTimeOutCtx(), "/demo", clientv3.WithPrefix())
   for _, kv := range response.Kvs {
      fmt.Printf("key=%s\tvalue=%s\n", kv.Key, kv.Value)
   }
}
// key=/demo/1     value=1
// key=/demo/2     value=2

监控watch

func testWatch() {
    client, err := clientv3.New(clientv3.Config{Endpoints: []string{"localhost:2379"}})
    if err != nil {
        panic(err)
    }
    defer client.Close()
    fmt.Println("start watch ...")
    client.Put(GetTimeOutCtx(), "/demo/1", "oldValue") // 设置旧值
    watch := client.Watch(context.Background(), "/demo/1") // 观察对应key,返回单向接受通道 <-chan WatchResponse
    for response := range watch {
        for _, kv := range response.Events {
            fmt.Printf("key=%s\tnowValue=%s\n", kv.Kv.Key, kv.Kv.Value)
        }
    }
}
​

这时候我们打开客户端,执行etcdctl put /demo/1 newvalue命令,会发现控制台输出啦~

它会一直监控,该通道不会自动关闭

key=/demo/1     nowValue=newvalue