etcd是使用Go语言开发的一个开源、高可用的分布式key-value存储系统,可以用于:

  • 配置共享
  • 服务注册与发现
  • 分布式锁

类似的项目或者说中间件还有zookeeperconsul,其中zookeeper,在java的技术栈中利用的最多,而在go语言中更多的是使用etcd或者consul,这俩对比,etcd的文档又比consul更齐全。

etcd通过raft算法实现了强一致、高可用的服务存储目录,集群中每个节点都可以使用完整的存档,集群部署也实现了高可用。

1.应用场景

1.1 服务注册/服务发现

服务发现要解决的也是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务,要如何才能找到对方并建立连接。本质上来说, 服务发现就是想要了解集群中是否有进程在监听 udptcp 端口,并且通过名字就可以查找和连接。 就像查字典一样。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架构

image-20210504123637530

etcd分为四个部分:

  • HTTP Server:用于处理用户发送的API请求以及其他etcd节点的同步与心跳请求;
  • Store:用于处理etcd所支持的各类功能的事务,包括 数据索引节点状态变更监控与反馈事件处理与执行等等,是etcd对用户提供的大多数 API功能的具体实现;
  • Raft:当然是指的Raft强一致性算法的具体实现,这是etcd的核心;
  • WALWrite Ahead Log-预写式日志,是etcd的数据存储方式。除了在内存中存放所有数据的状态、节点的索引以外,etcd还会通过WAL进行数据持久化存储。WAL中,所有的数据提交前都会事先记录日志。
    • Snapshot:为了防止数据过多而进行的状态快照;
    • Entry:表示存储的具体日志内容。

4.下载与安装

文档:https://etcd.io/docs/

image-20210504124620421

4.1 下载

去官方的github下载最新版本的etcd,找到最新的release

https://github.com/etcd-io/etcd/releases

image-20210504124658811

分不清楚admarm的童鞋参考下面链接:

扩展阅读-x86 x86_64/x64 amd64 arm64/aarch64

4.2 拷贝至服务器

博主是先在windows上下载好,使用的winscp拷贝至服务器的

image-20210504124849379

4.3 解压

cd /home/randyfield/etcd-release/
tar -zxvf etcd-v3.2.32-linux-amd64.tar.gz

image-20210504125008334

查看解压后的目录

image-20210504125036996

5.运行

5.1 直接运行

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

image-20210504125308058

image-20210504125323083

6.使用

6.1 命令行

image-20210504125550733

所以需要设置环境变量:

export ETCDCTL_API=3
./etcdctl put name "garfield"
./etcdctl get name 

image-20210504125646403

如果要指定端点,请带上--endponits参数

 ./etcdctl --endpoints=[127.0.0.1:2379] put name "garfield"

7.集群搭建

etcd作为高可用的键值存储系统,从出生那一刻就是为集群化的设计而来,所以实际生产环境中,应该使用集群部署。另外,Raft算法在做决策时需要多数节点进行投票,所以etcd集群部署都会推荐奇数个节点,推荐3、5、7构成集群。可以使用物理机、虚拟机、容器搭建集群。

示例:搭建3个节点的etcd集群

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与客户端通信

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个节点的。