Etcd是什么
Etcd是CoreOS团队于2013年6月发起的开源项目,是一个高可用、强一致的分布式键值(Key-Value)数据库,主要用途是共享配置和服务发现。
CoreOS 团队选择了易理解实现的 Raft 算法,它将复杂的一致性问题分解成 Leader 选举、日志同步、安全性三个相对独立的子问题,只要集群一半以上节点存活就可提供服务,具备良好的可用性。使用boltdb来持久化存储KV核心的元数据。
Etcd 命名的由来
在 Unix 系统中,/etc 目录用于存放系统管理和配置文件。分布式系统(Distributed System)第一个字母是“d”。组合在一起表示 etcd 是用于存储分布式配置的信息存储服务。
etcd 可以用来构建高可用的分布式键值数据库,总结来说有如下特点。
简单:etcd 的安装简单,且为用户提供了 HTTP API,使用起来也很简单。
存储:etcd 的基本功能,数据分层存储在文件目录中,类似于我们日常使用的文件系统。
Watch 机制:Watch 指定的键、前缀目录的更改,并对更改时间进行通知。
安全通信:支持 SSL 证书验证。
高性能:etcd 单实例可以支持 2K/s 读操作,官方也有提供基准测试脚本。
一致可靠:基于 Raft 共识算法,实现分布式系统内部数据存储、服务调用的一致性和高可用性。
etcd 是一个实现了分布式一致性键值对存储的中间件,支持跨平台,拥有活跃用户的技术社区。etcd 集群中的节点基于 Raft 算法进行通信,Raft 算法保证了微服务实例或机器集群所访问的数据的可靠一致性。
Etcd 架构

从 etcd 的架构图中我们可以看到,etcd 主要分为四个部分。
HTTP Server:用于处理客户端发送的 API 请求以及其它 Etcd 节点的同步与心跳信息请求。
Store:用于处理 Etcd 支持的各类功能的事务,包括数据索引、节点状态变更、监控与反馈、事件处理与执行等等,是 Etcd 对用户提供的大多数 API 功能的具体实现。
Raft:Raft 强一致性算法的具体实现,是 Etcd 的核心。
WAL:Write Ahead Log(预写式日志),是 Etcd 的数据存储方式。除了在内存中存有所有数据的状态以及节点的索引,Etcd 还通过 WAL 进行持久化存储。WAL 中,所有的数据提交前都会事先记录日志。
Snapshot 是为了防止数据过多而进行的状态快照。
Entry 表示存储的具体日志内容。
Snapshot 和 WAL 相结合,etcd 可以有效地进行数据存储和节点故障恢复等操作。
一个用户的请求发送过来,会经由 HTTP Server 转发给 Store 进行具体的事务处理,如果涉及到节点的修改,则交给 Raft 模块进行状态的变更、日志的记录,然后再同步给别的 etcd 节点以确认数据提交,最后进行数据的提交,再次同步。
虽然 etcd 内部实现机制复杂,但对外提供了简单的 API 接口,方便客户端调用。我们可以通过etcdctl 客户端命令行操作和访问 etcd 中的数据,或者通过HTTP API接口直接访问 etcd。
Etcd 中的数据结构很简单,它的数据存储其实就是键值对的有序映射。etcd 还提供了一种键值对监测机制,即 Watch 机制,客户端通过订阅相关的键值对,获取其更改的事件信息。Watch 机制实时获取 etcd 中的增量数据更新,使数据与 etcd 同步。
Etcd 目前有 V2.x 和 V3.x 两个大版本。etcd V2 和 V3 是在底层使用同一套 Raft 算法的两个独立应用,但相互之间实现原理和使用方法上差别很大,接口不一样、存储不一样,两个版本的数据互相隔离。
Etcd 中常用的术语
Raft:etcd所采用的保证分布式系统强一致性的算法。Node:一个Raft状态机实例。Member:一个etcd实例。它管理着一个Node,并且可以为客户端请求提供服务。Cluster:由多个Member构成可以协同工作的etcd集群。Peer:对同一个etcd集群中另外一个Member的称呼。Client:向etcd集群发送HTTP请求的客户端。WAL:预写式日志,etcd用于持久化存储的日志格式。snapshot:etcd防止WAL文件过多而设置的快照,存储etcd数据状态。Proxy:etcd的一种模式,为etcd集群提供反向代理服务。Leader:Raft算法中通过竞选而产生的处理所有数据提交的节点。Follower:竞选失败的节点作为Raft中的从属节点,为算法提供强一致性保证。Candidate:当Follower超过一定时间接收不到Leader的心跳时转变为Candidate开始竞选。Term:某个节点成为Leader到下一次竞选时间,称为一个Term。Index:数据项编号。Raft中通过Term和Index来定位数据。
- Etcd 常见应用场景
etcd 在稳定性、可靠性和可伸缩性上表现极佳,同时也为云原生应用系统提供了协调机制。etcd 经常用于服务注册与发现的场景,此外还有键值对存储、消息发布与订阅、分布式锁等场景
键值对存储
键值对存储是etcd的最基本的功能,使用etcd进行存储的应用都建立在etcd的可靠存储上。如k8s将一些元数据存储在etcd中,将存储状态数据的复杂工作给到etcd,可以保障k8s自身的功能与架构的更加稳定,同时coredns也可以使用etcd作为存储数据库
采用 kv 型数据存储,一般情况下比关系型数据库快
支持动态存储(内存)以及静态存储(磁盘)
分布式存储,可集成为多节点集群
存储方式,采用类似目录结构
只有叶子节点才能真正存储数据,相当于文件
叶子节点的父节点一定是目录,目录不能存储数据
服务注册与发现
服务注册与发现(Service Discovery)要解决的是分布式系统中最常见的问题之一,即在同一个分布式集群中的进程或服务如何才能找到对方并建立连接。
从本质上说,服务发现就是要了解集群中是否有进程在监听 UDP 或者 TCP 端口,并且通过名字就可以进行查找和链接。
要解决服务发现的问题,需要有下面三大支柱,缺一不可。
1,强一致性、高可用的服务存储目录。基于 Raft 算法的 etcd 天生就是这样一个强一致性、高可用的服务存储目录
2,一种注册服务和监控服务健康状态的机制。用户可以在 etcd 中注册服务,并且对注册的服务设置 key TTL,定时保持服务的心跳以达到监控健康状态的效果。
3,一种查找和连接服务的机制。通过在 etcd 指定的主题下注册的服务业能在对应的主题下查找到。为了确保连接,我们可以在每个服务机器上都部署一个 Proxy 模式的 etcd,这样就可以确保访问 etcd 集群的服务都能够互相连接。

消息发布与订阅
在分布式系统中,服务之间还可以通过消息通信,即消息的发布与订阅。
通过构建 etcd 消息中间件,服务提供者发布对应主题的消息,消费者则订阅他们关心的主题,一旦对应的主题有消息发布,就会产生订阅事件,消息中间件就会通知该主题所有的订阅者。

场景大概流程:应用在启动的时候主动从 etcd 获取一次配置信息,同时在 etcd 节点上注册一个 Watcher 并等待,以后每次配置有更新的时候,etcd 都会实时通知订阅者,以此达到获取最新配置信息的目的。
分布式锁
分布式系统中涉及多个服务实例,存在跨进程之间资源调用,对于资源的协调分配,单体架构中的锁已经无法满足需要,需要引入分布式锁的概念。
etcd 基于 Raft 算法,实现分布式集群的一致性,存储到 etcd 集群中的值必然是全局一致的,因此基于 etcd 很容易实现分布式锁。
锁服务有以下两种使用方式:
保持独占
即所有试图获取锁的用户最终只有一个可以得到。
etcd为此提供了一套实现分布式锁原子操作CAS(CompareAndSwap)的API。通过设置prevExist值,可以保证在多个节点同时创建某个目录时,只有一个成功,而该用户即可认为是获得了锁。
控制时序
即所有试图获取锁的用户都会进入等待队列,获得锁的顺序是全局唯一的,同时决定了队列执行顺序。
etcd为此也提供了一套API(自动创建有序键),对一个目录建值时指定为POST动作,这样etcd会自动在目录下生成一个当前最大的值为键,存储这个新的值(客户端编号)。
同时还可以使用API按顺序列出所有当前目录下的键值。此时这些键的值就是客户端的时序,而这些键中存储的值可以是代表客户端的编号。

参考与推荐阅读文章:
https://tonydeng.github.io/2015/10/19/etcd-application-scenarios/
https://www.modb.pro/db/249967
https://learn.lianglianglee.com/%E4%B8%93%E6%A0%8F/%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%AD%E9%97%B4%E4%BB%B6%E5%AE%9E%E8%B7%B5%E4%B9%8B%E8%B7%AF%EF%BC%88%E5%AE%8C%EF%BC%89/09%20%E5%88%86%E5%B8%83%E5%BC%8F%E4%B8%80%E8%87%B4%E6%80%A7%E7%AE%97%E6%B3%95%20Raft%20%E5%92%8C%20Etcd%20%E5%8E%9F%E7%90%86%E8%A7%A3%E6%9E%90.md