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端口,并且通过名字就可以进行查找和链接。
解决服务发现问题的三个关键:
- 一个强一致性、高可用的服务存储目录。基于raft算法的etcd天生就有强一致性、高可用的服务存储目录。
- 一种注册服务和健康服务健康状况的机制。用户可以在etcd中注册服务,并且对注册的服务配置key TTL,定时保持服务的心跳以达到监控健康状态的效果。
- 一种查找和连接服务的机制。通过在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将一致性问题分解为了三个子问题,解这三个子问题的过程,保障了数据的一致:
-
Leader选举:当已有的leader故障时必须选出一个新的leader。
-
日志复制:leader接受来自客户端的命令,记录为日志,并复制给集群中的其他服务器,并强制其他节点的日志与leader保持一致。
-
安全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
二阶段提交,这里不做