1、etcd简介
1.1 etcd简介
etcd
是开源的、高可用的分布式key-value存储系统,可用于配置共享和服务的注册和发现,它专注于:
-
简单
:定义清晰、面向用户的API(gRPC) -
安全
:可选的客户端TLS证书自动认证 -
快速
:支持每秒10,000次写入 -
可靠
:基于Raft算法确保强一致性
etcd
地址:https://github.com/etcd-io/etcd
etcd
官方文档:https://etcd.io/docs/v3.4/dev-guide/interacting_v3/
etcd官方文档中文版:https://doczhcn.gitbook.io/etcd/
1.2 etcd与redis差异
etcd和redis都支持键值存储,也支持分布式特性,redis支持的数据格式更加丰富,但是他们两个定位和应用场景
不一样,关键差异如下:
-
redis在分布式环境下不是强一致性的,可能会丢失数据,或者读取不到最新数据
-
redis的数据变化监听机制没有etcd完善
-
etcd强一致性保证数据可靠性,导致性能上要低于redis
-
etcd和ZooKeeper是定位类似的项目,跟redis定位不一样
1.3 为什么用 etcd 而不用ZooKeeper?
相较之下,ZooKeeper有如下缺点:
-
复杂
:ZooKeeper的部署维护复杂,管理员需要掌握一系列的知识和技能;而 Paxos 强一致性算法也是素来以复杂难懂而闻名于世;另外,ZooKeeper的使用也比较复杂,需要安装客户端,官方只提供了 Java 和 C 两
种语言的接口。
-
难以维护
:Java 编写。这里不是对 Java 有偏见,而是 Java 本身就偏向于重型应用,它会引入大量的依赖。而运维人员则普遍希望保持强一致、高可用的机器集群尽可能简单,维护起来也不易出错。
-
发展缓慢
:Apache 基金会项目特有的“Apache Way”在开源界饱受争议,其中一大原因就是由于基金会庞大的结构以及松散的管理导致项目发展缓慢。
而 etcd 作为一个后起之秀,其优点也很明显。
-
简单
:使用 Go 语言编写部署简单;使用 HTTP 作为接口使用简单;使用 Raft 算法保证强一致性让用户易于理解。
-
数据持久化
:etcd 默认数据一更新就进行持久化。 -
安全
:etcd 支持 SSL 客户端安全认证。
1.4 应用场景
根据以上特性和API,etcd
有应用场景以下应用场景:
1.4.1 场景一:服务发现
服务发现要解决的也是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务,要如何才能找到
对方并建立连接。本质上来说,服务发现就是想要了解集群中是否有进程在监听 udp 或 tcp 端口,并且通过名字
就可以查找和连接。
1.4.2 场景二:配置中心
etcd
的应用场景优化都是围绕存储的东西是"配置"来设定的。
-
配置的数据量通常都不大,所以默认etcd的存储上限是1GB
-
配置通常对历史版本信息是比较关心的,所以etcd会保存版本(revision) 信息
-
配置变更是比较常见的,并且业务程序会需要实时知道,所以etcd提供了watch机制,基本就是实时通知配置
变化
-
配置的准确性一致性极其重要,所以etcd采用raft算法,保证系统的CP
-
同一份配置通常会被大量客户端同时访问,针对这个做了grpc proxy对同一个key的watcher做了优化
-
配置会被不同的业务部门使用,提供了权限控制和namespace机制
1.4.3 场景三:负载均衡
此处指的负载均衡均为软负载均衡,分布式系统中,为了保证服务的高可用以及数据的一致性,通常都会把数据和
服务部署多份,以此达到对等服务,即使其中的某一个服务失效了,也不影响使用。由此带来的坏处是数据写入性
能下降,而好处则是数据访问时的负载均衡。因为每个对等服务节点上都存有完整的数据,所以用户的访问流量就
可以分流到不同的机器上。
1.4.4 场景四:分布式锁
因为 etcd 使用 Raft 算法保持了数据的强一致性,某次操作存储到集群中的值必然是全局一致的,所以很容易实现
分布式锁。
1.4.5 场景五:集群监控与 Leader 竞选
通过 etcd 来进行监控实现起来非常简单并且实时性强。
-
前面几个场景已经提到 Watcher 机制,当某个节点消失或有变动时,Watcher 会第一时间发现并告知用户。
-
节点可以设置TTL key,比如每隔 30s 发送一次心跳使代表该机器存活的节点继续存在,否则节点消失。
这样就可以第一时间检测到各节点的健康状态,以完成集群的监控要求。
另外,使用分布式锁,可以完成Leader竞选。这种场景通常是一些长时间CPU计算或者使用IO操作的机器,只需
要竞选出的 Leader 计算或处理一次,就可以把结果复制给其他的 Follower。从而避免重复劳动,节省计算资源。
1.4.6 场景六:消息发布与订阅
在分布式系统中,最适用的一种组件间通信方式就是消息发布与订阅。即构建一个配置共享中心,数据提供者在这
个配置中心发布消息,而消息使用者则订阅他们关心的主题,一旦主题有消息发布,就会实时通知订阅者。通过这
种方式可以做到分布式系统配置的集中式管理与动态更新。
1.4.7 场景七:分布式通知与协调
用到了 etcd 中的 Watcher 机制,通过注册与异步通知机制,实现分布式环境下不同系统之间的通知与协调,从而
对数据变更做到实时处理。实现方式通常是这样:不同系统都在 etcd 上对同一个目录进行注册,同时设置
Watcher 观测该目录的变化(如果对子目录的变化也有需要,可以设置递归模式),当某个系统更新了 etcd 的目
录,那么设置了 Watcher 的系统就会收到通知,并作出相应处理。
1.4.8 场景八:分布式队列
分布式队列的常规用法与场景五中所描述的分布式锁的控制时序用法类似,即创建一个先进先出的队列,保证顺
序。
2、etcd安装
2.1 windows下安装
2.1.1 下载安装包
下载地址:https://github.com/etcd-io/etcd/releases/
这里下载 etcd-v3.5.5-windows-amd64
2.1.2 解压缩
将下载的安装包进行解压:
2.1.3 环境变量配置
将D:\DecompressionSoftwareInstall\etcd-v3.5.5-windows-amd64
添加到Path
环境变量中。
2.1.4 测试
$ etcd -version
etcd Version: 3.5.5
Git SHA: 19002cfc6
Go Version: go1.16.15
Go OS/Arch: windows/amd64
正常显示etcd版本信息,则证明安装成功。
2.2 Linux下安装
2.2.1 下载安装包
下载地址:https://github.com/etcd-io/etcd/releases/
这里下载 etcd-v3.5.5-linux-amd64.tar.gz
2.2.2 解压压缩包
$ tar -zxvf etcd-v3.5.5-linux-amd64.tar.gz
[root@zsx etcd-v3.5.5-linux-amd64]# ll
total 56472
drwxr-xr-x. 3 528287 89939 40 Sep 15 20:03 Documentation
-rwxr-xr-x. 1 528287 89939 23760896 Sep 15 20:03 etcd
-rwxr-xr-x. 1 528287 89939 17960960 Sep 15 20:03 etcdctl
-rwxr-xr-x. 1 528287 89939 16031744 Sep 15 20:03 etcdutl
-rw-r--r--. 1 528287 89939 42066 Sep 15 20:03 README-etcdctl.md
-rw-r--r--. 1 528287 89939 7359 Sep 15 20:03 README-etcdutl.md
-rw-r--r--. 1 528287 89939 9394 Sep 15 20:03 README.md
-rw-r--r--. 1 528287 89939 7896 Sep 15 20:03 READMEv2-etcdctl.md
2.2.3 环境变量配置
把etcd
和etcdctl
文件复制到已经配置了环境变量的目录中:
- 方法一:把
etcd
和etcdctl
文件复制到GOBIN
目录下。 - 方法二:在环境变量里添加
etcd
和etcdctl
文件所在的目录。 - 方法三:将
etcd
和etcdctl
二进制文件复制到/usr/local/bin
目录。
$ cp etcd etcdctl /usr/local/bin
2.2.4 测试
[root@zsx ~]# etcd --version
etcd Version: 3.5.5
Git SHA: 19002cfc6
Go Version: go1.16.15
Go OS/Arch: linux/amd64
正常显示etcd版本信息,则证明安装成功。
2.3 将etcd部署为服务
1、创建数据存储目录:
$ mkdir -p /usr/local/etcd/data
2、创建配置文件/usr/local/etcd/conf.yml
:
name: etcd01
data-dir: /usr/local/etcd/data
initial-advertise-peer-urls: http://192.168.165.195:2380
listen-peer-urls: http://192.168.165.195:2380
listen-client-urls: http://192.168.165.195:2379,http://127.0.0.1:2379
advertise-client-urls: http://192.168.165.195:2379
initial-cluster-token: etcd01
initial-cluster: etcd01=http://192.168.165.195:2380
initial-cluster-state: new
配置参数解析:
-
name
:当前etcd节点名称。 -
data-dir
:数据存储目录。 -
initial-advertise-peer-urls
:集群的其他节点通过该地址与当前节点通信。 -
listen-peer-urls
:当前节点通过该地址监听集群其他节点发送的信息。 -
listen-client-urls
:当前节点通过该地址监听客户端发送的信息。 -
advertise-client-urls
:客户端通过该地址与当前节点通信 -
initial-cluster-token
:用于区分不同的集群,同一集群的所有节点配置相同的值。 -
initial-cluster
:当前集群的所有节点信息,当前节点根据此信息与其他节点取得联系。 -
initial-cluster-state
: 本次是否为新建集群,有两个取值:new和existing。
3、创建服务配置文件/usr/lib/systemd/system/etcd.service
:
[Unit]
Description=etcd
After=network.target
[Service]
Type=notify
ExecStart=/usr/local/bin/etcd --config-file=/usr/local/etcd/conf.yml
[Install]
WantedBy=multi-user.target
4、启动服务:
$ systemctl daemon-reload
$ systemctl start etcd.service
5、查看服务是否启动成功:
[root@zsx demo]# systemctl status etcd.service
● etcd.service - etcd
Loaded: loaded (/usr/lib/systemd/system/etcd.service; disabled; vendor preset: disabled)
Active: active (running) since Thu 2023-02-16 21:09:24 CST; 23s ago
Main PID: 106654 (etcd)
Tasks: 7
Memory: 7.3M
CGroup: /system.slice/etcd.service
└─106654 /usr/local/bin/etcd --config-file=/usr/local/etcd/conf.yml
......
6、设置服务为开机自启动:
$ systemctl enable etcd.service
Created symlink from /etc/systemd/system/multi-user.target.wants/etcd.service to /usr/lib/systemd/system/etcd.service.
7、测试:
$ etcd --version
etcd Version: 3.5.5
Git SHA: 19002cfc6
Go Version: go1.16.15
Go OS/Arch: linux/amd64
$ etcdctl member list
7c30ae572716ee16, started, etcd01, http://192.168.165.195:2380, http://192.168.165.195:2379, false
$ etcdctl --endpoints=http://192.168.165.195:2380 endpoint health
http://192.168.165.195:2380 is healthy: successfully committed proposal: took = 3.097752ms
8、开启鉴权
添加root用户:
在开启鉴权之前必须先创建root用户,否则无法启用身份认证功能。etcd默认创建root用户时即创建了root角色,
并为其绑定了该角色,该角色拥有所有权限。
$ etcdctl user add root
Password of root:root
Type password of root again for confirmation:root
User root created
开启鉴权:
$ etcdctl auth enable
{"level":"warn","ts":"2023-02-16T21:16:58.919+0800","logger":"etcd-client","caller":"v3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc0002dca80/127.0.0.1:2379","attempt":0,"error":"rpc error: code = FailedPrecondition desc = etcdserver: root user does not have root role"}
Authentication Enabled
验证:
开启鉴权后,客户端请求etcd server需要使用选项--user
带上用户名和密码,否则会报错。
$ etcdctl --endpoints=http://192.168.165.195:2380 endpoint health
{"level":"warn","ts":"2023-02-16T21:18:46.005+0800","logger":"client","caller":"v3/retry_interceptor.go:62","msg":"retrying of unary invoker failed","target":"etcd-endpoints://0xc0002dca80/192.168.165.195:2380","attempt":0,"error":"rpc error: code = InvalidArgument desc = etcdserver: user name is empty"}
http://192.168.165.195:2380 is unhealthy: failed to commit proposal: etcdserver: user name is empty
Error: unhealthy cluster
$ etcdctl --endpoints=http://192.168.165.195:2380 endpoint health --user=root:root
http://192.168.165.195:2380 is healthy: successfully committed proposal: took = 416.916µs