筹建8月份etcd技术分享

1. 了解etcd

etcd是什么

强一致的分布式K/V存储引擎。但常用于配置共享和服务发现。

历史背景

etcd 是 CoreOS 团队于 2013 年 6 月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库,基于 Go 语言实现。

2014年6月,作为Kubernetes核心元数据的存储服务一起发布,自此ETCD社区得到飞速发展。

2015年2月,发布了第一个正式稳定版本2.0,重构了Raft一致性算法,提供了用户树形数据视图,支持每秒超过1000次的写入性能。

2017年1月,发布了3.1版本,提供了一套全新的API,同时提供了gRPC接口,通过gRPC的proxy扩展并极大地提高ETCD的读取性能,支持每秒超过10000次的写入。

2018年11月,项目进入CNCF的孵化项目。后续的3.x版本提升性能以及稳定性,增强运维能力。

为什么出现

etcd是受到Zookeeper和doozer(死掉)启发而催生的项目,相比其他竞品具有以下4个特点

  • 简单: 基于HTTP+JSON的API让你可以用CURL命令就可以轻松使用。
  • 安全: 可以选择SSL客户认证机制。
  • 快速: 每个实例每秒支持一千次写操作。
  • 可信: 使用Raft算法充分实现了分布式。

一致性说明

强一致性:任何时刻所有的用户与进程查询到的都是最近一次成功更新的数据。

弱一致性:系统对一致性要求不高,即使系统不一致,也能很好的提供服务,不影响用户的体验。

最终一致性:弱一致性的一种体现,某一时刻用户或进程查询到的数据可能不同,但是最终成功更新的数据都会被所有用户或者进程查询到。

竞品对比

名字 优点 缺点
zookeeper 技术成熟,功能丰富 复杂,Java技术栈带来的依赖
doozer Go编译单独二进制部署,Paxos达成集群共识 2013年停止维护
redis 易于部署,数据格式丰富 分布式环境下只满足最终强一致性
etcd 易于部署,轻量,数据持久性,安全,丰富文档 高速迭代和开发,出现了v2/v3API

比较 etcd/redis

- etcd redis
兴起 k8s 用 etcd 做服务发现 emcache 缓存的局限性
一致性 raft 算法做分布式一致性,强调各个节点之间的通信、同步,确保各节点数据和事务的一致性,使得服务发现工作更稳定 可以做主从同步和读写分离,但节点一致性强调的是数据,不是事务。redis 的注册和发现只能通过 pub 和 sub 实现,安全性不能保证(断线重连之后不会将历史信息推送给客户端,需要自己做一个定时轮询),延时也比 etcd v3 高
存储 采用 boltdb 做存储,value 直接持久化 内存数据库,它的持久化方案有 aof 和 rdb,在宕机时都或多或少会丢失数据

比较 etcd/zookeeper

功能 etcd zookeeper
分布式锁
watcher
一致性算法 raft zab
选举
元数据(metadata)存储

使用场景

应用场景 etcd zookeeper
发布与订阅(配置中心)
软负载均衡
命名服务(Naming Service)
服务发现
分布式通知/协调
集群管理与Master选举
分布式锁
分布式队列

服务发现

本质上,服务发现就是要了解集群中是否有进程在监听upd或者tcp端口,并且通过名字就可以进行查找和链接。

解决服务发现问题的三个关键:

  1. 一个强一致性、高可用的服务存储目录。基于raft算法的etcd天生就有强一致性、高可用的服务存储目录。
  2. 一种注册服务和健康服务健康状况的机制。用户可以在etcd中注册服务,并且对注册的服务配置key TTL,定时保持服务的心跳以达到监控健康状态的效果。
  3. 一种查找和连接服务的机制。通过在etcd指定的主题下注册的服务业能在对应的主题下查找到。

2. etcd技术架构

先看看如何使用

etcdctl put foo bar # 写入一条数据 foo => bar revision=1
etcdctl get foo --rev=3 # 读取foo的第三次修订版本
foo
bar3
etcdctl del foo # 删除foo
etcdctl watch foo # 观察foo的变化
etcdctl compact 5 # 手动压缩清理[:current_pointer-5]
compacted revision 5
# 新建租约 grant:添加 revoke:删除 keep-alive:续签 timetolive:租约详情
etcdctl lease grant 600
lease 694d80dbb1a2b50d granted with TTL(600s)
# foo绑定租约 600s后过期
etcdctl put foo "alive value" --lease=694d80dbb1a2b50d
# cli实现分布式锁
etcdctl lock mutexKey # 在第一个终端
mutexKey/326963a02758b52d
etcdctl lock mutexKey # 在第二个终端
...阻塞 当第一个终端结束了,第二个终端会显示
mutexKey/326963a02758b531

3. 强一致性保障

raft 一种共识算法,在计算机集群中提供解决方法,确保集群内任意节点在某种状态转换上保持一致。

Raft系统由leader全权负责接收客户端的请求命令,并将命令作为日志条目复制给其他服务器,在确认安全的时候,将日志命令提交执行。当 leader 故障时,会选举产生一个新的 leader。在强 leader 的帮助下,Raft将一致性问题分解为了三个子问题,解这三个子问题的过程,保障了数据的一致:

  1. Leader选举:当已有的leader故障时必须选出一个新的leader。

  2. 日志复制:leader接受来自客户端的命令,记录为日志,并复制给集群中的其他服务器,并强制其他节点的日志与leader保持一致。

  3. 安全safety措施:通过一些措施确保系统的安全性,如确保所有状态机按照相同顺序执行相同命令的措施。

Leader选举

每个成员都有一个随机的超时时间,当到达超时时间,立刻投自己一票,并向其他成员发起竞选邀请。

节点掉线后,通过任期确定一次选举活动。低任期的leader角色上线后总是会变成follower。

日志复制

为了保证数据的强一致性,etcd集群中所有的数据流向都是一个方向,从 Leader 流向 Follower,也就是所有 Follower 的数据必须与 Leader 保持一致,如果不一致会被Leader数据覆盖。另外,写入多数节点((n/2+1)即算写操作成功。

场景1:写follower,读leader,数据还没有流向leader

说明:当follower没有将数据传递给leader时,get不到数据。

场景2:写follower,读leader,get时数据只同步到了大部分节点

Get到了结果,因为leader有数据。那这样,还算时强一致的吗?算的,因为如果此时有节点掉线,那他就不算集群内机器了。

安全措施

随着使用量的增加,WAL 存储的数据会暴增,为了防止磁盘爆满,etcd 默认每 10000 条记录做一次 Snapshot,经过 Snapshot 以后的 WAL 文件就可以删除。基于这个策略,保证ETCD存储的安全性。

snap

snapshot总是存储着某一个时刻etcd所有的数据。可以确保数据在异常时,快速从快照文件中恢复。

etcd 被设计为能承受机器失败。etcd 集群自动从临时失败(例如,机器重启)中恢复,而且对于一个有 N 个成员的集群能容许 (N-1)/2 的持续失败。当一个成员持续失败时,不管是因为硬件失败或者磁盘损坏,它丢失到集群的访问。如果集群持续丢失超过 (N-1)/2 的成员,则它只能悲惨的失败,无可救药的失去法定人数(quorum)。一旦法定人数丢失,集群无法达到一致而因此无法继续接收更新。

恢复集群首先需要来自 etcd 成员的键空间的快照。快速可以是用 etcdctl snapshot save 命令从活动成员获取,或者是从 etcd 数据目录复制 member/snap/db 文件. 例如,下列命令快照在 $ENDPOINT 上服务的键空间到文件 snapshot.db:

etcdctl --endpoints $ENDPOINT snapshot save snapshot.db

wal

二阶段提交,这里不做阐述。