etcd
是使用Go
语言开发的一个开源、高可用的分布式key-value
存储系统,可以用于:
- 配置共享
- 服务注册与发现
- 分布式锁
类似的项目或者说中间件还有zookeeper
和consul
,其中zookeeper
,在java
的技术栈中利用的最多,而在go
语言中更多的是使用etcd
或者consul
,这俩对比,etcd
的文档又比consul
更齐全。
etcd
通过raft
算法实现了强一致、高可用的服务存储目录,集群中每个节点都可以使用完整的存档,集群部署也实现了高可用。
1.应用场景
1.1 服务注册/服务发现
服务发现要解决的也是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务,要如何才能找到对方并建立连接。本质上来说,服务发现就是想要了解集群中是否有进程在监听 udp
或 tcp
端口,并且通过名字就可以查找和连接。就像查字典一样。etcd
就能充当一个服务字典的角色,服务上线去往etcd
进行注册,etcd
与服务之间维持一个心跳,保证服务是否可用。
1.2 配置中心/配置共享
将分布式系统中各种各样的配置信息集中放至etcd
上,集中管理。可以减少部署、运维成本。
这类应用场景的使用方式通常是:通过程序写入共享配置信息,其他分布式应用启动的时候主动从etcd
获取一次配置信息,同时,应用程序在etcd
节点上注册一个Watcher
并等待,相当于一个订阅者,只要etcd
配置有更新,就会实时通知这些订阅者,以此获得最新的配置信息。
1.3 分布式锁
因为etcd
使用Raft
算法保持了数据的一致性, 因此在操作后存储到集群中的值必然是全局一致的,所以很容易实现分布式锁。实现分布式锁的服务有两种方式:
- 保持独占:只有一个可以获得锁,
etcd
提供了一套实现分布式锁原子操作CAS(CompareAndSwap)
的API
.通过设置prevExist
值,可以保证多个节点同时去创建某个目录时,只有一个成功。而创建成功的那一个就可以认为是获得了锁。 - 控制时序:对所有想要获得锁进行排序,这个顺序全局唯一,
etcd
提供了一套API
,用于自动创建有序键。
总而言之:维护了不同语言不同进程之间访问 etcd
的时序。
2.对比
etcd
能实现的功能,zookeeper
都能做到。具体为什么选择etcd
?
好吧,其实博主对zookeeper
不甚了解。下面的就算是道听途说吧,说的不对也不要喷博主:
- zookeepr部署维护复杂:管理员需要掌握一系列的知识和技能;java编写,会引入大量依赖;运维人员普遍希望保持强一致、高可用的集群尽可能简单,维护简单不易出错。
- 算法复杂:
zookeeper
采用的Paxos
强一致性算法素来以复杂难懂闻名于世; - 发展缓慢:
Apache
基金会项目特有的Apache Wag
在开源界饱受争议,由于基金会庞大的结构和松散的管理导致项目发展缓慢。
etcd
后起之秀,技术上的’后起之秀‘,往往能规避’前辈‘的问题,改良甚至摒弃:
- 部署简单:
Go
语言编写,部署简单是一个特点; - 使用简单:使用
HTTP
作为接口; - 算法简单:
Raft
算法保证强一致性,易于理解; - 数据持久化:
etcd
默认数据一更新就进行持久化; - 安全:
etcd
支持SSL
客户端安全认证。
3.etcd架构
etcd
分为四个部分:
- HTTP Server:用于处理用户发送的
API
请求以及其他etcd
节点的同步与心跳请求; - Store:用于处理
etcd
所支持的各类功能的事务,包括 数据索引、节点状态变更、监控与反馈、事件处理与执行等等,是etcd
对用户提供的大多数API
功能的具体实现; - Raft:当然是指的
Raft
强一致性算法的具体实现,这是etcd
的核心; - WAL:Write Ahead Log-预写式日志,是
etcd
的数据存储方式。除了在内存中存放所有数据的状态、节点的索引以外,etcd
还会通过WAL
进行数据持久化存储。WAL
中,所有的数据提交前都会事先记录日志。- Snapshot:为了防止数据过多而进行的状态快照;
- Entry:表示存储的具体日志内容。
4.下载与安装
文档:https://etcd.io/docs/
4.1 下载
去官方的github
下载最新版本的etcd
,找到最新的release
https://github.com/etcd-io/etcd/releases
分不清楚adm
与arm
的童鞋参考下面链接:
扩展阅读-x86 x86_64/x64 amd64 arm64/aarch64
4.2 拷贝至服务器
博主是先在windows
上下载好,使用的winscp
拷贝至服务器的
4.3 解压
代码语言:javascript复制cd /home/randyfield/etcd-release/
tar -zxvf etcd-v3.2.32-linux-amd64.tar.gz
查看解压后的目录
5.运行
5.1 直接运行
代码语言:javascript复制cd /home/randyfield/etcd-release/etcd-v3.2.32-linux-amd64
./etcd
端口为2379
5.2 nohup
不挂断的运行命令,由于在主流的 Linux
发行版中都会默认安装 nohup
命令工具:
#启动
nohup ./etcd &
#查看进程-返回进程 id
ps -ef | grep etcd
6.使用
6.1 命令行
所以需要设置环境变量:
代码语言:javascript复制export ETCDCTL_API=3
./etcdctl put name "garfield"
./etcdctl get name
如果要指定端点,请带上--endponits
参数
./etcdctl --endpoints=[127.0.01:2379] put name "garfield"
7.集群搭建
etcd
作为高可用的键值存储系统,从出生那一刻就是为集群化的设计而来,所以实际生产环境中,应该使用集群部署。另外,Raft
算法在做决策时需要多数节点进行投票,所以etcd
集群部署都会推荐奇数个节点,推荐3、5、7构成集群。可以使用物理机、虚拟机、容器搭建集群。
示例:搭建3个节点的etcd集群
代码语言:javascript复制export ETCDCTL_API=3
TOKEN=token-01
CLUSTER_STATE=new
NAME_1=machine-1
NAME_2=machine-2
NAME_3=machine-3
HOST_1=192.168.31.204
HOST_2=192.168.31.205
HOST_3=192.168.31.206
CLUSTER=${NAME_1}=http://${HOST_1}:2380,${NAME_2}=http://${HOST_2}:2380,${NAME_3}=http://${HOST_3}:2380
TOKEN
:标识etcd
集群,区分不同集群CLUSTER_STATE
:集群状态,标识此集群是新建CLUSTER
:指定集群具体节点
在n1节点中执行命令以启动etcd
etcd --data-dir=data.etcd --name n1
--initial-advertise-peer-urls http://192.168.31.204:2380 --listen-peer-urls http://192.168.31.204:2380
--advertise-client-urls http://192.168.31.204:2379 --listen-client-urls http://192.168.31.204:2379
--initial-cluster ${CLUSTER}
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
etcd
:启动etcd
命令--data-dir
:数据存储位置--name
:节点名称--initial-advertise-peer-urls
:用于同一个集群中其他节点的连接,2380端口peer
:翻译同等地位的人,同龄人,所以指代的是节点之间
--advertise-client-urls
2379 客户端连接--initial-cluster
:初始化一个集群
在n2节点执行命令以启动etcd
etcd --data-dir=data.etcd --name n2
--initial-advertise-peer-urls http://192.168.31.205:2380 --listen-peer-urls http://192.168.31.204:2380
--advertise-client-urls http://192.168.31.204:2379 --listen-client-urls http://192.168.31.204: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://192.168.31.206:2380 --listen-peer-urls http://192.168.31.206:2380
--advertise-client-urls http://192.168.31.206:2379 --listen-client-urls http://192.168.31.206:2379
--initial-cluster ${CLUSTER}
--initial-cluster-state ${CLUSTER_STATE} --initial-cluster-token ${TOKEN}
使用集群
集群就算搭建好了,集群中的节点通过2380端口彼此通信,通过2379与客户端通信
代码语言:javascript复制export ETCDCTL_API=3
HOST_1=192.168.31.204
HOST_2=192.168.31.205
HOST_3=192.168.31.206
ENDPONITS=$HOST_1:2379,$HOST_2:2379,$HOST_3:2379
etcdctl --endpoints=$ENDPOINTS member list
- 连接3个节点的集群,就要在
--endpoints
中指定3个节点的。