etcd简介

etcd 是一个高度一致的分布式键值存储,它提供了一种可靠的方式来存储需要由分布式系统或机器集群访问的数据。在很多分布式系统架构中得到了广泛的应用,它内部采用 raft协议 作为一致性算法,基于Go语言实现。其主要功能有服务注册与发现、消息发布与订阅、负载均衡、分布式通知与协调、分布式锁、分布式队列、集群监控与 leader 选举等。

主要具有以下几个特点:

  • 简单:安装配置简单,易于部署,易使用。基于 HTTP 的 API 让你用 curl 就可以轻松使用。
  • 安全:支持 SSL 证书验证。
  • 键值对存储:将数据存储在分层组织的目录中,如同在标准文件系统中。
  • 监测变更:监测特定的键或目录以进行更改,并对值的更改做出反应。
  • 快速:根据官方提供的 benchmark 数据,单实例支持每秒 2k+ 读操作。
  • 可靠:采用raft算法,实现分布式系统数据的可用性和一致性。

存储特点

etcd 是一个 键值存储 的组件,其他的应用都是基于其键值存储的功能展开。etcd 的存储有如下特点:

  • 采用kv型数据存储,一般情况下比关系型数据库快。
  • 支持动态存储(内存)以及静态存储(磁盘)。
  • 分布式存储,可集成为多节点集群。
  • 存储方式,采用类似目录结构。
    • 只有叶子节点才能真正存储数据,相当于文件。
    • 叶子节点的父节点一定是目录,目录不能存储数据。

etcd应用场景

etcd 的场景默认处理的数据都是系统中的控制数据。所以etcd在系统中的角色不是其他NoSQL产品的替代品,更不能作为应用的主要数据存储。etcd中应该 尽量只存储系统中服务的配置信息,对于应用数据只推荐把数据量很小,但是更新和访问频次都很高的数据存储在etcd中。

服务发现(Service Discovery)

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

要解决服务发现的问题,需要具备下面三种必备属性:

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

etcd架构图

images
images

从上图中我们可以看到,etcd 主要分为四个部分。

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

通常,一个用户的请求发送过来,会经由 HTTP Server 转发给 Store 进行具体的事务处理,如果涉及到节点的修改,则交给 Raft 模块进行状态的变更、日志的记录,然后再同步给别的 etcd 节点以确认数据提交,最后进行数据的提交,再次同步。

消息发布与订阅

在分布式系统中,最适用的一种组件间通信方式就是消息发布与订阅。即构建一个 配置共享中心,数据提供者在这个配置中心发布消息,而消息使用者则订阅他们关心的主题,一旦主题有消息发布,就会实时通知订阅者。通过这种方式可以做到分布式系统配置的集中式管理与动态更新。

images
images

应用中用到的一些 配置信息 放到etcd上进行集中管理。使用方式:应用在启动的时候主动从etcd获取一次配置信息,同时,在etcd节点上注册一个Watcher并等待,以后每次配置有更新的时候,etcd都会实时通知订阅者,以此达到获取最新配置信息的目的。

分布式搜索服务中,索引的元信息和服务器集群机器的节点状态存放在etcd中,供各个客户端订阅使用。使用etcd的key TTL功能可以确保机器状态是实时更新的。

分布式日志收集系统,这个系统的核心工作是收集分布在不同机器的日志。收集器通常是按照应用(或主题)来分配收集任务单元,因此可以在etcd上创建一个以应用(主题)命名的目录P,并将这个应用(主题相关)的所有机器ip,以子目录的形式存储到目录P上,然后设置一个 etcd 递归的Watcher,递归式的监控应用(主题)目录下所有信息的变动。这样就实现了机器IP(消息)变动的时候,能够实时通知到收集器调整任务分配。

用户从集群中哪个节点读写数据?

为了保证数据的强一致性,etcd集群中所有的数据流向都是一个方向,从 Leader (主节点)流向 Follower,也就是所有 Follower 的数据必须与 Leader 保持一致,如果不一致会被覆盖。

简单点说就是,用户可以对etcd集群中的所有节点进行读写,读取非常简单因为每个节点保存的数据是强一致的。对于写入来说,etcd集群中的节点会选举出Leader节点,如果写入请求来自Leader节点即可直接写入然后Leader节点会把写入分发给所有Follower,如果写入请求来自其他Follower节点那么写入请求会给转发给Leader节点,由Leader节点写入之后再分发给集群上的所有其他节点。

如何选举Leader节点

假设集群中有三个节点,集群启动之初节点中并没有被选举出的Leader。

  • Raft算法使用 随机Timer 来初始化Leader选举流程。比如说在上面三个节点上都运行了Timer(每个Timer的持续时间是随机的),第一个节点率先完成了Timer,随后它就会向其他两个节点发送成为Leader的请求,其他节点接收到请求后会以 投票回应 然后第一个节点被选举为Leader。

  • 成为Leader后,该节点会 以固定时间间隔向其他节点发送通知,确保自己仍是Leader。 有些情况下当Follower们收不到Leader的通知后,比如说Leader节点宕机或者失去了连接,其他节点会重复之前选举过程选举出新的Leader。

判断写入是否成功

etcd认为写入请求被Leader节点处理并分发给了 多数节点 后,就是一个成功的写入。如何界定多数节点呢?假设总结点数是N,那么界定多数节点的公式是 Quorum=N/2+1

容错节点数:集群中节点总数(Instances)对应的Quorum数量,用Instances减去Quorom就是集群中容错节点(允许出故障的节点)的数量。

所以在集群中推荐的最少节点数量是3个,因为1和2个节点的容错节点数都是0,一旦有一个节点宕掉整个集群就不能正常工作了。

1
2
3
4
5
6
7
8
9
Instances Quorum Fault Toleran
1 1/2+1=1 1-1=0
2 2/2+1=2 2-2=0
3 3/2+1=2 3-2=1
4 3 1
5 3 2
6 4 2
7 4 3

如上所示:当决定集群中节点的数量时,强烈推荐奇数数量的节点。 例如:6个节点的集群它的容错能力并没有比5个节点的好,他们的容错节点数一样,一旦容错节点超过2后,由于Quorum节点数小于4整个集群也变为不可用的状态了。