为什么使用ETCD
- ETCD简介
- ETCD发展史
- ETCD架构
- etcd数据通道
- 具体交互
- ETCD使用场景
- 概念词汇
ETCD简介
现代键值(Key - Value)存储系统,ZooKeeper是历史最悠久的项目,起源于Hadoop。这里ETCD与Zk对比。
ETCD相比与ZK,更加简单,安装部署和使用更加容易,etcd的某些功能是ZK没有的。具体如下:
- etcd更加稳定可靠
- 在服务发现的实现上,etcd使用的是节点租约,并支持多group;而zk使用的是临时节点,临时节点存在很多问题
- etcd支持稳定的watch
- etcd支持MVCC(多版本并发控制),因为有协同系统需要无锁操作
- etcd支持更大的数据规模,支持存储百万到千万级别的key
- etcd的性能比zk更好,三台8C节点,etcd v3版本可以每秒万次的写操作和数十万次的读操作
etcd名字由来:分为etc和d,etc即linux/unix操作系统下的/etc目录,d表示分布式(distributed),/etc一般存储配置信息,所以寓意就是大规模分布式系统存储配置信息。
etcd是一个Go语言编写的分布式,高可用的一致性键值存储系统,是基于Raft协议,通过复制日志文件的方式来保证数据的强一致性。当客户端应用写一个key时,首先会存储到etcd的Leader上,然后再通过Raft协议复制到etcd集群的所有成员中,以此维护各个节点状态的一致性与实现可靠性。
虽然etcd是一个强一致性的系统,但也支持从非Leader节点读取数据以提高性能,而且写操作仍需Leader支持。
etcd实现了一个Go语言版的Raft程序库,并广泛应用于各个项目。
etcd具备一定的容错能力,假设集群共有n个节点,即便集群(n-1)/2个节点发生故障,只要剩下(n+1)/2个节点达成一致,也能操作成功。因此它能够有效应对网络分区和机器故障带来的数据丢失风险。
etcd默认数据一更新就罗盘持久化,数据持久化存储使用WAL(write ahead log,预写式日志)格式。WAL记录数据变化的全过程,在etcd中所有数据在提交之前都要先写入WAL中;etcd的Snapshot(快照)文件则存储了某一时刻的etcd的所有数据,默认设置为每10000条记录做一次快照,经过快照后WAL文件即可删除。
ETCD发展史
etcd发展至今,有几个重要的版本。
- etcd0.4版本
是etcd对外发布的第一个稳定版本
Raft算法做分布式协同
HTTP+JSON的API
使用SSL客户端证书验证
基准测试在每个实例中每秒写入1000次等
- etcd2.0版本
etcd2.0版本是etcd第一个真正意义上的大版本,引入几个重要功能:
内部etcd协议的优化避免意外错误配置
etcdctl增加了backup命令便于从集群异常恢复数据
运行时动态更新集群member配置,通过etcdctl客户端的member子命令
通过CRC校验和append-only的行为提高了存盘数据的安全性
优化Raft一致性算法实现,该实现会被其他项目引用
etcd的TCP2379/2380端口正式成为IANA(The Internet Assigned Numbers Authority,互联网数字分配机构)官方分配的端口
- etcd3.0版本
对2.0版本做了多出优化
提升了整体吞吐量,降低了时延,通过gRPC API降低了Raft协议调用的开销,提升了WAL的磁盘利用率
全新的存储后端带来了每个key平均内存开销的减少
自动的TLS配置
扁平的二进制键空间:摈弃了v2的key-value层级和目录
全新的v3 API,支持基于key为前缀和范围的get、watch
多版本的键空间:允许访问历史版本的key
事务:将对etcd服务的多个请求合并成一个操作
租约:允许一组key共享一个TTL
监控/告警:通过存储配额保护etcd免受偶然发生的超额使用
ETCD架构
etcd设计使用考虑的四个要素
- 简单
使用RESTful风格的HTTP+JSON的API
性能考虑,etcd v3增加了对gRPC的支持,同时也提供rest gateway进行转化
Go语言编写,跨平台,部署和维护简单
使用Raft算法保证强一致性,Raft算法可理解性好 - 安全
支持TLS客户端安全认证 - 性能
但实力支持以每秒1000次以上的写操作(v2),极限写性能可达10K+QPS(v3) - 可靠
使用Raft算法充分保证分布式系统数据的强一致性
etcd(server)大致可以分为网络层(http server),Raft模块,复制状态机,存储模块,大致如下:
网络层:提供网络数据读写功能,监听服务短裤,完成集群节点之间数据通信,收发客户端数据
Raft模块:Raft强一致性算法具体实现
存储模块:设计KV存储,WAL文件,Snapshot管理等,用于处理etcd支持的各类功能,包含数据索引,节点状态变更,监控与反馈,事件处理与执行等
复制状态机:抽象的一个模块,状态机的数据维护在内存中,定期持久化到磁盘。
一个用户请求,经过HTTP Server转发给存储模块进行具体的事务处理,如果涉及到节点状态更新,则交给Raft模块进行仲裁和日志记录,然后再同步给别的etcd节点,只有当半数以上的节点确认了该节点状态修改后,才会进行数据持久化。
集群中各节点传输数据:
1)Leader向Follower发送心跳包,Follower向Leader回复消息
2)Leader向Follower发送日志追加信息
3)Leader向Follower发送Snapshot数据
4)Candidate节点发起选举,向其他节点发起投票请求
5)Follower将收到的写操作数据转发给Leader
集群中任意2个节点之间均有长连接相互连接的网状结构
etcd数据通道
根据不同用途,定义了各种不同消息类型,这些不同的消息,最终都通过protocol buffer格式进行编码。消息数据大小可能不同,例如Snapshot数据量比较大,甚至会超过1GB,心跳消息可能就几十KB,所以抽象类两种类型的消息传输通道,即Stream类型通道,Pipeline类型通道,都是使用HTTP传输数据。
Stream类型通道:用于处理数据量较少的消息,例如,心跳和日志追加消息,点对点之间只维护一个HTTP长连接,交替向链接中写入数据和读取数据。
通过Channel与Raft模块传递消息,每个Stream类型通道关联2个goroutine,一个用于建立HTTP链接,从链接上读取数据并解码成消息,再通过channel传递给raft模块,另一个通过channel从raft模块中接受消息,然后写入Stream类型通道
Pipiline类型通道:用于处理数据量大的消息,例如Snapshot,这种类型的消息需要与心跳等消息分开,否则会阻塞心跳包的传输,进而影响集群的稳定性。不维护HTTP长连接,只通过短连接传输数据,用完即关闭。
不过当Stream类型链接不可用时,也可以使用Pipiline传输
Pipeline类型通道可以并行发送消息,它维护一组goroutine,每个goroutine可以向对端发送POST请求,收到回复后,链接关闭。
具体交互
具体各个模块交互,涉及到几个重要的结构体,EtcdServer ,RaftNode,Node
EtcdServer 是整个etcd节点的功能的入口,包含etcd节点运行过程中需要的大部分成员
RaftNode是raft状态机,维护raft状态机的步进和状态迁移。
Node包含在raftNode中,是Node接口的实现。里面包含一个协程和多个队列,是状态机消息处理的入口。
网络层和Raft模块是通过RaftNode,channel来进行交互的。
ETCD使用场景
服务注册与发现
- 微服务注册
原因:etcd具备强一致性,具备注册服务和健康健康状况的机制(对注册的key设置TTL,服务定时发送心跳),查找和连接服务(etcd指主题下注册的业务能再对应的主题下找到) - Paas平台应用多实例与实力故障重启透明化
一般应用都会有多个实例,通过域名,负载均衡。但是应用随时可能故障重启,这时候需要动态的配置域名解析路由信息,etcd服务可以轻松解决这个动态配置的问题
消息发布和订阅
topic(etcd的某个prefix或者某个key),producer写入etcd,consumer 作为etcd的一个watcher监听消息,然后进行消费
负载均衡
服务提供方注册到etcd中,当服务提供方不健康时,etcd告诉服务请求者,提出不健康的服务
分布式锁
通过判断某个key是否存在,以及事务特性来实现
分布式队列
通过key设置一直+1,
集群监控与Leader竞选
通过watcher机制,节点设置TTL key,服务通过不断发送健康检查来对集群进行监控,
概念词汇
名词 | 描述 |
---|---|
Raft | etcd所采用的保证分布式系统强一致性的一种算法 |
Node | 一个Raft状态机实例 |
Member | 一个etcd实例,管理一个Node,并可以为客户端请求提供服务 |
Cluster | 多个Member构成,遵循Raft一致性协议的etcd集群 |
Peer | 对同一个etcd集群中另外一个Member的叫法 |
Client | 凡是连接etcd服务器请求服务的,臀如,获取key-value、写数据或watch更新的程序,都统你为Client |
Proposal | 一个需要经过Raft一致性协议的请求,例加,写请求或配置更新请求 |
Quorum | |
WAL | :预写式日志,etcd用于持久化存储的日志格式 |
Snapshot | etcd集群状态在某一时间点的快照(备份),etcd为防止WL文件过多而设置的快照,用于存储etcd的数据状态 |
Proxy | etcd的一种模式,为etcd集群提供反向代理服务 |
Leader | Raft算法中通过竞选而产生的处理所有数据提交的节点 |
Follower | 竞选失败的节点作为Raft中的从属节点,为算法提供强一致性保证 |
Candidate | 当Follower超过一定的时间还接收不到Leader的心跳时转为Candidate开始竞选 |
Term | 某个节点从成为Leader到下一次竞选的时间,称为一个Term |
Index | WAL日志数据项编号。Raft中通过Term和index来定位数据 |
Key | 用户定义的用于存储和获取用户定义数据的标识符 |
Key space | 键空间,etcd集群内所有键的集合 |
Revision | etcd集群范围内64位的计数器,键空间的每次修改都会导致该计数器的增加 |
Modification Revision | 一个key最后一次修改的revision |
Lease | 一个短时的(会过期),可续订的契约(租约),当它过期时,就会删除与之关联的所有键 |
Transition | 事务,一个自动执行的操作集,要么一块成功,要么一块失败。 |
Watcher | 观察者,etcd最具特色的概念之一。客户端通过打开一个观察者来获取一个给定键范围的更新 |
Key Range | 键范围,一个键的集合,这个集合既可以是只有一个key或者是在一个字典区间,例如(a,b],或者是大于某个key的所有key |
Endpoint | 指向etcd服务或资源的URL |
Compaction | etcd的压缩(Compaction)操作,丢弃所有etcd的历史数据并且取代一个给定revision之前的所有key。压缩操作通常用于重新声明etcd后端数据库的存储空间。其与Raft的日志压缩是一个原理 |
key version | 键版本,即一个健从创建开始的写(修改)次数,从1开始。一个不存在成已制除的健版本是0。其与revision的概念不同 |