1. etcd 介绍 etcd 是使用Go语言开发的一个开源的、高可用的分布式key-value存储系统,可以用于配置共享和服务的注册和发现。类似项目有zookeeper和consul。
etcd具有以下特点:
完全复制:集群中的每个节点都可以使用完整的存档 高可用性:Etcd可用于避免硬件的单点故障或网络问题 一致性:每次读取都会返回跨多主机的最新写入 简单:包括一个定义良好、面向用户的API(gRPC) 安全:实现了带有可选的客户端证书身份验证的自动化TLS 快速:每秒10000次写入的基准速度 可靠:使用Raft算法实现了强一致、高可用的服务存储目录 2. etcd 安装和使用 2.1 下载安装 https://github.com/etcd-io/etcd/releases
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 ETCD_VER=v3.4.13 GOOGLE_URL=https://storage.googleapis.com/etcd GITHUB_URL=https://github.com/etcd-io/etcd/releases/download DOWNLOAD_URL=${GOOGLE_URL} rm -f /tmp/etcd-${ETCD_VER} -linux-amd64.tar.gzrm -rf /tmp/etcd-download-test && mkdir -p /tmp/etcd-download-testcurl -L ${DOWNLOAD_URL} /${ETCD_VER} /etcd-${ETCD_VER} -linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER} -linux-amd64.tar.gz tar xzvf /tmp/etcd-${ETCD_VER} -linux-amd64.tar.gz -C /tmp/etcd-download-test --strip-components=1 rm -f /tmp/etcd-${ETCD_VER} -linux-amd64.tar.gz/tmp/etcd-download-test/etcd --version /tmp/etcd-download-test/etcdctl version
2.2 启动 为了方便, 移动到环境变量下
1 2 mv /tmp/etcd-download-test/etcd /usr/local/bin/mv /tmp/etcd-download-test/etcdctl /usr/local/bin/
1 2 3 etcd nohup etcd --listen-client-urls http://0.0.0.0:2379 --advertise-client-urls http://0.0.0.0:2379 &
The official etcd ports 对于客户端请求是2379,即curl set get 时用的端口。节点间通信端口是2380。
2.3 操作 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 etcdctl put mykey "this is awesome" etcdctl get mykey etcdctl del mykey etcdctl get mykey etcdctl get / --prefix --keys-only etcdctl get "" --prefix --keys-only | sed '/^\s*$/d'
2.4 集群 1 etcd --config-file etcd.conf
etcd1.conf
1 2 3 4 5 6 7 8 9 name: etcd-1 data-dir: /data/server/etcd/data listen-client-urls: http://172.21.0.17:2379,http://127.0.0.1:2379 advertise-client-urls: http://172.21.0.17:2379,http://127.0.0.1:2379 listen-peer-urls: http://172.21.0.17:2380 initial-advertise-peer-urls: http://172.21.0.17:2380 initial-cluster: etcd-1 =http://172.21 .0.17 :2380 ,etcd-2 =http://172.21 .0.17 :2390 ,etcd-3 =http://172.21 .0.15 :2380 initial-cluster-token: etcd-cluster-token initial-cluster-state: new
etcd2.conf
1 2 3 4 5 6 7 8 9 name: etcd-2 data-dir: /data/server/etcd2/data listen-client-urls: http://172.21.0.17:2389,http://127.0.0.1:2389 advertise-client-urls: http://172.21.0.17:2389,http://127.0.0.1:2389 listen-peer-urls: http://172.21.0.17:2390 initial-advertise-peer-urls: http://172.21.0.17:2390 initial-cluster: etcd-1 =http://172.21 .0.17 :2380 ,etcd-2 =http://172.21 .0.17 :2390 ,etcd-3 =http://172.21 .0.15 :2380 initial-cluster-token: etcd-cluster-token initial-cluster-state: existing
etcd3.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 name: etcd-3 data-dir: /data/server/etcd/data listen-client-urls: http://172.21.0.15:2379,http://127.0.0.1:2379 advertise-client-urls: http://172.21.0.15:2379,http://127.0.0.1:2379 listen-peer-urls: http://172.21.0.15:2380 initial-advertise-peer-urls: http://172.21.0.15:2380 initial-cluster: etcd-1 =http://172.21 .0.17 :2380 ,etcd-2 =http://172.21 .0.17 :2390 ,etcd-3 =http://172.21 .0.15 :2380 initial-cluster-token: etcd-cluster-token initial-cluster-state: new
etcdctl member list
1 2 3 4 5 hash1: name =etcd-1 peerURLs=http://172.21 .0.17 :2380 clientURLs=http://127.0 .0.1 :2379 ,http://172.21 .0.17 :2379 isLeader=false hash2: name =etcd-2 peerURLs=http://172.21 .0.17 :2390 clientURLs=http://127.0 .0.1 :2389 ,http://172.21 .0.17 :2389 isLeader=false hash3: name =etcd-3 peerURLs=http://172.21 .0.15 :2380 clientURLs=http://127.0 .0.1 :2379 ,http://172.21 .0.15 :2379 isLeader=true
3. golang 使用 etcd https://github.com/etcd-io/etcd/tree/master/client
1 go get go.etcd.io/etcd/v3/client
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package mainimport ( "log" "time" "context" "go.etcd.io/etcd/v3/client" ) func main () { cfg := client.Config{ Endpoints: []string {"http://127.0.0.1:2379" }, Transport: client.DefaultTransport, HeaderTimeoutPerRequest: time.Second, } c, err := client.New(cfg) if err != nil { log.Fatal(err) } kapi := client.NewKeysAPI(c) log.Print("Setting '/foo' key with 'bar' value" ) resp, err := kapi.Set(context.Background(), "/foo" , "bar" , nil ) if err != nil { log.Fatal(err) } else { log.Printf("Set is done. Metadata is %q\n" , resp) } log.Print("Getting '/foo' key value" ) resp, err = kapi.Get(context.Background(), "/foo" , nil ) if err != nil { log.Fatal(err) } else { log.Printf("Get is done. Metadata is %q\n" , resp) log.Printf("%q key has %q value\n" , resp.Node.Key, resp.Node.Value) } }
3.1 报错 undefined: balancer.PickOptions 具体操作方法是在go.mod里加上:
1 replace google.golang.org/grpc => google.golang.org/grpc v1.26 .0
4. 参考资料