保卫萝卜4纸鸢探春第九关攻略
etcd是独霸的完近几年斗劲炽热的一个开源的 、分布式的成示键值对数据存储琐细,供给共享设置设备放置、独霸的完处事的成示注册和创作创造,本文次要引见etcd的独霸的完拆卸和独霸。
etcdetcd引见
etcd是成示独霸Go言语斥地的一个开源的 、高可用的独霸的完分布式key-value存储琐细,可以用于设置设备放置共享和处事的成示注册和创作创造 。
近似项目有zookeeper和consul 。独霸的完
etcd具有以下特点:
- 无缺复制:集群中的成示每个节点都可独霸无缺的存档
- 高可用性 :Etcd可用于阻拦硬件的单点偏向或群集问题
- 齐截性:每次读取都邑前去跨多主机的最新写进
- 复杂:包含一个定义出色、面向用户的独霸的完API(gRPC)
- 安然:完成了带有可选的客户端证书身份验证的主动化TLS
- 疾速 :每秒10000次写进的基准速度
- 刚毅 :独霸Raft算法完成了强齐截、高可用的成示处事存储目次
etcd独霸处景
处事创作创造
处事创作创造要措置的也是分布式琐细中最罕有的问题之一,即在不合个分布式集群中的独霸的完过程或处事,要若何才调找到对方并创建邻接 。成示本质下往讲 ,独霸的完处事创作创培养是想要体味合群中可否有过程在监听 udp 或 tcp 端口 ,并且经由过程名字便可以查找和邻接 。

设置设备放置中心
将一些设置设备放信赖息放到 etcd 前程行集结治理。
这类场景的独霸编制但凡是多么:独霸在启动的时辰主动从 etcd 掉落踪掉落踪一次设置设备放信赖息 ,同时 ,在 etcd 节点上注册一个 Watcher 并等待,往后每次设置设备放置有更新的时辰,etcd 都邑及时赐顾帮衬订阅者,以此抵达掉落踪掉落踪最新设置设备放信赖息的方针 。
分布式锁
因为 etcd 独霸 Raft 算法贯穿连接了数据的强齐截性,某次独霸存储到集群中的值必定是全局齐截的 ,所以很随便完成分布式锁 。锁处事有两种独霸编制,一是贯穿连接独有,二是独霸时序。
贯穿连接独有即全数掉落踪掉落踪锁的用户幻想下场只需一个可以掉落踪掉落踪 。etcd 为此供给了一套完成分布式锁原子独霸 CAS(CompareAndSwap)的 API 。经由过程设置prevExist值,可以担保在多个节点同时往成立某个目次时 ,只需一个成功。而成立成功的用户便可以认为是掉落踪掉落踪了锁。
独霸时序 ,即全数想要掉落踪掉落踪锁的用户都邑被放置奉行 ,可是掉落踪掉落踪锁的按序也是全局独一的 ,同时决意了奉行按序 。etcd 为此也供给了一套 API(主动成立有序键) ,对一个目次建值时指定为POST行动,多么 etcd 会主动在目次下生成一个往后最除夜的值为键,存储这个新的值(客户端编号)。同时还可独霸 API 按按序列出全数往后目次下的键值。此时这些键的值就是客户端的时序 ,而这些键中存储的值可所以代表客户端的编号 。

为甚么用 etcd 而不必ZooKeeper?
etcd 完成的这些下场 ,ZooKeeper都能完成。那么为甚么要用 etcd 而非直接独霸ZooKeeper呢 ?
为甚么不选择ZooKeeper ?
- 放置呵护宏壮,其独霸的Paxos强齐截性算法严重难解 。官方只供给了Java和C两种言语的接口。
- 独霸Java编写引进除夜量的依托 。运维人员呵护起来斗劲贫穷。
- 比来几年展开迟缓 ,不如etcd和consul等后起之秀 。
为甚么选择etcd?
- 复杂。独霸 Go 言语编写放置复杂;支撑HTTP/JSON API,独霸复杂;独霸 Raft 算法担保强齐截性让用户易于邃晓。
- etcd 默许数据一更新就举办经久化。
- etcd 支撑 SSL 客户端安然认证 。
末尾,etcd 作为一个年青的项目,正在高速迭代和斥地中,这既是一个益处,也是一个偏向偏向。益处是它的将来具有没有穷的大年夜大年夜约性,偏向偏向是没法掉落踪掉落踪除夜项目长时分独霸的考验。可是 ,如今 CoreOS、Kubernetes和CloudFoundry等驰名项目均在花费气候中独霸了etcd,所以总的来讲 ,etcd值得你往考验考验。
etcd集群
etcd 作为一个高可用键值存储琐细 ,见成效是为集群化而筹划的 。因为 Raft 算法在做决意狡计时需求除夜都节点的投票,所以 etcd 一样往常放置集群推荐奇数个节点,推荐的数量为 3、5 或 7 个节点构成一个集群。
搭建一个3节点集群示例:
在每个etcd节点指定集群成员 ,为了分辨不合的集群最好同时设置设备放置一个并世无双的token。
上面是延迟定义好的集群信息,个中n1 、n2和n3展示3个不合的etcd节点。
TOKEN=token-01CLUSTER_STATE=newCLUSTER=n1=http://10.240.0.17:2380,n2=http://10.240.0.18:2380,n3=http://10.240.0.19:2380
在n1这台机械上奉行以下呼唤来启动etcd:
etcd --data-dir=data.etcd --name n1 \ --initial-advertise-peer-urls http://10.240.0.17:2380 --listen-peer-urls http://10.240.0.17:2380 \ --advertise-client-urls http://10.240.0.17:2379 --listen-client-urls http://10.240.0.17:2379 \ --initial-cluster ${ CLUSTER} \ --initial-cluster-state ${ CLUSTER_STATE} --initial-cluster-token ${ TOKEN}在n2这台机械上奉行以下呼唤启动etcd :
etcd --data-dir=data.etcd --name n2 \ --initial-advertise-peer-urls http://10.240.0.18:2380 --listen-peer-urls http://10.240.0.18:2380 \ --advertise-client-urls http://10.240.0.18:2379 --listen-client-urls http://10.240.0.18:2379 \ --initial-cluster ${ CLUSTER} \ --initial-cluster-state ${ CLUSTER_STATE} --initial-cluster-token ${ TOKEN}在n3这台机械上奉行以下呼唤启动etcd:
etcd --data-dir=data.etcd --name n3 \ --initial-advertise-peer-urls http://10.240.0.19:2380 --listen-peer-urls http://10.240.0.19:2380 \ --advertise-client-urls http://10.240.0.19:2379 --listen-client-urls http://10.240.0.19:2379 \ --initial-cluster ${ CLUSTER} \ --initial-cluster-state ${ CLUSTER_STATE} --initial-cluster-token ${ TOKEN}etcd 官网供给了一个可以公网访谒的 etcd 存储地址。你可以经由过程以下呼唤掉落踪掉落踪 etcd 处事的目次,并把它作为-discovery参数独霸 。
curl https://discovery.etcd.io/new?size=3https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92 # grab this tokenTOKEN=token-01CLUSTER_STATE=newDISCOVERY=https://discovery.etcd.io/a81b5818e67a6ea83e9d4daea5ecbc92 etcd --data-dir=data.etcd --name n1 \ --initial-advertise-peer-urls http://10.240.0.17:2380 --listen-peer-urls http://10.240.0.17:2380 \ --advertise-client-urls http://10.240.0.17:2379 --listen-client-urls http://10.240.0.17:2379 \ --discovery ${ DISCOVERY} \ --initial-cluster-state ${ CLUSTER_STATE} --initial-cluster-token ${ TOKEN} etcd --data-dir=data.etcd --name n2 \ --initial-advertise-peer-urls http://10.240.0.18:2380 --listen-peer-urls http://10.240.0.18:2380 \ --advertise-client-urls http://10.240.0.18:2379 --listen-client-urls http://10.240.0.18:2379 \ --discovery ${ DISCOVERY} \ --initial-cluster-state ${ CLUSTER_STATE} --initial-cluster-token ${ TOKEN} etcd --data-dir=data.etcd --name n3 \ --initial-advertise-peer-urls http://10.240.0.19:2380 --listen-peer-urls http://10.240.0.19:2380 \ --advertise-client-urls http://10.240.0.19:2379 --listen-client-urls http:/10.240.0.19:2379 \ --discovery ${ DISCOVERY} \ --initial-cluster-state ${ CLUSTER_STATE} --initial-cluster-token ${ TOKEN}到此etcd集群就搭建起来了 ,可独霸etcdctl来邻接etcd 。
export ETCDCTL_API=3HOST_1=10.240.0.17HOST_2=10.240.0.18HOST_3=10.240.0.19ENDPOINTS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379 etcdctl --endpoints=$ENDPOINTS member lis
Go言语独霸etcd
这里独霸官方的etcd/clientv3包来邻接etcd并举办相干独霸。
拆卸
go get go.etcd.io/etcd/clientv3
put和get独霸
put呼唤用来设置键值对数据,get呼唤用来屈就key掉落踪掉落踪值。
package main import ( "context" "fmt" "time" "go.etcd.io/etcd/clientv3") // etcd client put/get demo// use etcd/clientv3 func main() { cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{ "127.0.0.1:2379"}, DialTimeout: 5 * time.Second, }) if err != nil { // handle error! fmt.Printf("connect to etcd failed, err:%v\n", err) return } fmt.Println("connect to etcd success") defer cli.Close() // put ctx, cancel := context.WithTimeout(context.Background(), time.Second) _, err = cli.Put(ctx, "q1mi", "dsb") cancel() if err != nil { fmt.Printf("put to etcd failed, err:%v\n", err) return } // get ctx, cancel = context.WithTimeout(context.Background(), time.Second) resp, err := cli.Get(ctx, "q1mi") cancel() if err != nil { fmt.Printf("get from etcd failed, err:%v\n", err) return } for _, ev := range resp.Kvs { fmt.Printf("%s:%s\n", ev.Key, ev.Value) }}watch独霸
watch用来掉落踪掉落踪将来变换的赐顾帮衬 。
package main import ( "context" "fmt" "time" "go.etcd.io/etcd/clientv3") // watch demo func main() { cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{ "127.0.0.1:2379"}, DialTimeout: 5 * time.Second, }) if err != nil { fmt.Printf("connect to etcd failed, err:%v\n", err) return } fmt.Println("connect to etcd success") defer cli.Close() // watch key:q1mi change rch := cli.Watch(context.Background(), "q1mi") // <-chan WatchResponse for wresp := range rch { for _, ev := range wresp.Events { fmt.Printf("Type: %s Key:%s Value:%s\n", ev.Type, ev.Kv.Key, ev.Kv.Value) } }}将上面的代码保管编译奉行 ,此时法度圭表类型就会等待etcd中q1mi这个key的改削。
比如:我们翻开终端奉行以下呼唤改削、删除 、设置q1mi这个key 。
etcd> etcdctl.exe --endpoints=http://127.0.0.1:2379 put q1mi "dsb2"OK etcd> etcdctl.exe --endpoints=http://127.0.0.1:2379 del q1mi1 etcd> etcdctl.exe --endpoints=http://127.0.0.1:2379 put q1mi "dsb3"OK
上面的法度圭表类型都能收到以下赐顾帮衬 。
watch>watch.execonnect to etcd successType: PUT Key:q1mi Value:dsb2Type: DELETE Key:q1mi Value:Type: PUT Key:q1mi Value:dsb3
lease租约
package main import ( "fmt" "time") // etcd lease import ( "context" "log" "go.etcd.io/etcd/clientv3") func main() { cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{ "127.0.0.1:2379"}, DialTimeout: time.Second * 5, }) if err != nil { log.Fatal(err) } fmt.Println("connect to etcd success.") defer cli.Close() // 成立一个5秒的租约 resp, err := cli.Grant(context.TODO(), 5) if err != nil { log.Fatal(err) } // 5秒钟此后, /nazha/ 这个key就会被移除 _, err = cli.Put(context.TODO(), "/nazha/", "dsb", clientv3.WithLease(resp.ID)) if err != nil { log.Fatal(err) }}keepAlive
package main import ( "context" "fmt" "log" "time" "go.etcd.io/etcd/clientv3") // etcd keepAlive func main() { cli, err := clientv3.New(clientv3.Config{ Endpoints: []string{ "127.0.0.1:2379"}, DialTimeout: time.Second * 5, }) if err != nil { log.Fatal(err) } fmt.Println("connect to etcd success.") defer cli.Close() resp, err := cli.Grant(context.TODO(), 5) if err != nil { log.Fatal(err) } _, err = cli.Put(context.TODO(), "/nazha/", "dsb", clientv3.WithLease(resp.ID)) if err != nil { log.Fatal(err) } // the key 'foo' will be kept forever ch, kaerr := cli.KeepAlive(context.TODO(), resp.ID) if kaerr != nil { log.Fatal(kaerr) } for { ka := <-ch fmt.Println("ttl:", ka.TTL) }}基于etcd完成分布式锁
go.etcd.io/etcd/clientv3/concurrency在etcd之上完成并发独霸 ,如分布式锁 、樊篱和推荐 。
导进该包:
import "go.etcd.io/etcd/clientv3/concurrency"
基于etcd完成的分布式锁示例:
cli, err := clientv3.New(clientv3.Config{ Endpoints: endpoints})if err != nil { log.Fatal(err)}defer cli.Close() // 成立两个孤单的会话用来演示锁竞争s1, err := concurrency.NewSession(cli)if err != nil { log.Fatal(err)}defer s1.Close()m1 := concurrency.NewMutex(s1, "/my-lock/") s2, err := concurrency.NewSession(cli)if err != nil { log.Fatal(err)}defer s2.Close()m2 := concurrency.NewMutex(s2, "/my-lock/") // 会话s1掉落踪掉落踪锁if err := m1.Lock(context.TODO()); err != nil { log.Fatal(err)}fmt.Println("acquired lock for s1") m2Locked := make(chan struct{ })go func() { defer close(m2Locked) // 等待直到会话s1释放了/my-lock/的锁 if err := m2.Lock(context.TODO()); err != nil { log.Fatal(err) }}() if err := m1.Unlock(context.TODO()); err != nil { log.Fatal(err)}fmt.Println("released lock for s1") <-m2Lockedfmt.Println("acquired lock for s2")输进:
acquired lock for s1
released lock for s1
acquired lock for s2
搜检文档体味更多
其他独霸
其他独霸请搜检etcd/clientv3官方文档。
参考链接:
https://etcd.io/docs/v3.3.12/demo/
https://www.infoq.cn/article/etcd-interpretation-application-scenario-implement-principle/ 代码改削全国,脚结壮地 ,python 、Golang。
到此这篇关于Go独霸etcd的完成示例的文章就引见到这了,更多相干Go独霸etcd内容请搜刮完竣下载之前的文章或延续不雅不雅不雅不雅鉴赏上面的相干文章希看大年夜师往后多多支撑完竣下载 !
