ETCD的raft选举及应用场景

Posted 北漂悟道之路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ETCD的raft选举及应用场景相关的知识,希望对你有一定的参考价值。

etcd的作用,很多人第一反应可能是一个键值存储仓库,却没有重视官方定义的后半句,用于配置共享和服务发现。

A highly-available key value store for shared configuration and service discovery.

特性如下:

  • 简单:基于 HTTP+JSON 的 API 让你用 curl 就可以轻松使用。

  • 安全:可选 SSL 客户认证机制。

  • 快速:每个实例每秒支持一千次写操作。

  • 可信:使用 Raft 算法充分实现了分布式。

值得注意的是,分布式系统中的数据分为控制数据和应用数据。使用 etcd 的场景默认处理的数据都是控制数据,对于应用数据,只推荐数据量很小,但是更新访问频繁的情况。

一致性的原理:Raft协议

etcd raft选举机制

etcd 是一个分布式的k/V存储系统。核心使用了RAFT分布式一致性协议。一致性这个概念,它是指多个服务器在状态达成一致,但是在一个分布式系统中,因为各种意外可能,有的服务器可能会崩溃或变得不可靠,它就不能和其他服务器达成一致状态。这样就需要一种Consensus协议,一致性协议是为了确保容错性,也就是即使系统中有一两个服务器当机,也不会影响其处理过程。

为了以容错方式达成一致,我们不可能要求所有服务器100%都达成一致状态,只要超过半数的大多数服务器达成一致就可以了,假设有N台服务器,N/2 +1 就超过半数,代表大多数了。

raft协议核心要点:

  • Leader选举(Leader Election)

  • 日志同步 (Log Replication)

  • leader收到client的更新请求后,会讲更新的内容同步给所有follower。

  • 集群状态的正确性 (Safety)

  • 保证日志的一致性

  • 保证选举的正确性

服务器状态:

  • leader
    处理所有客户端交互,日志复制等,一个任期只有一个。

  • follower
    完全被动的选民,是只读的。

  • candidate
    候选人,可以被选举为新领导。

状态之间的转换:

任期(terms)


如上图,蓝色代表 Election 模式,绿色代表 Operation 模式

  • 在每个任期内最多一个leader

  • 有些可能没有leader

  • 每一个服务会维护当前的任期值

  • 每一个rpc请求中都会携带term值

  • 如果一个peer实例拥有老的term值,则更新为最新的term值并状态变为follower

  • 一旦一个服务选举为leader,就会进入 operation 模式

Leader选举

etcd服务启动后,会进入 follower 状态,leader 心跳超时后会进入选举状态。

选举流程分解

  • 初始状态都是Follower

  • S1 超时, 变为Candidate,开始选举, 发起投票请求

  • S1 变为Leader

  • S2 和 S3 同意投票给S1

    ETCD的raft选举及应用场景

    image

  • Leader S1开始接受客户端写请求

  • Leader接受到客户端写请求后,会将数据更新写入到log中

  • 如果S2和S3收到客户端写请求,会将请求转发到Leader S1

  • Leader会异步的将更新的log同步到Follower S2和S3

  • 超过多数的Follower将数据成功同步到log后,Leader会将该条数据更新为Committed状态,Committed index会随着增长。

    ETCD的raft选举及应用场景



选举的正确性

        在每一任期内,最多允许一个服务被选举为leader

    • 在一个任期内,一个服务只能投一票

    • 只有获得大多数投票才能作为leader

        如果有多个candidate,最终一定会有一个被选举为leader

    • 如果多个candidate同时发起了选举,导致都没有获得大多数选票时,每一个candidate会随机等待一段时间后重新发起新一轮投票(一般是随机等待150-300ms)

日志的一致性

        客户端写入数据到 leader:

    • leader 把数据提交后,返回给client结果

    • 在下一个心跳中,leader 通知follower更新已经提交的数据

    • leader 将数据写入到 log

    • leader将更新的数据广播到所有的followers

    • 多数follower成功写入log后,leader会将该数据提交到状态机

    Crashed/slow followers ?

    • leader会一直重试同步数据到follower,直到成功

列举几种应用场景

场景一:服务发现(Service Discovery)

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

  1. 一个强一致性、高可用的服务存储目录。基于 Raft 算法的 etcd 天生就是这样一个强一致性高可用的服务存储目录。

  2. 一种注册服务和监控服务健康状态的机制。用户可以在 etcd 中注册服务,并且对注册的服务设置key TTL,定时保持服务的心跳以达到监控健康状态的效果。

  3. 一种查找和连接服务的机制。通过在 etcd 指定的主题下注册的服务也能在对应的主题下查找到。为了确保连接,我们可以在每个服务机器上都部署一个 Proxy 模式的 etcd,这样就可以确保能访问 etcd 集群的服务都能互相连接。

场景二:消息发布与订阅

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

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

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

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

  • 系统中信息需要动态自动获取与人工干预修改信息请求内容的情况。通常是暴露出接口,例如 JMX 接口,来获取一些运行时的信息。引入 etcd 之后,就不用自己实现一套方案了,只要将这些信息存放到指定的 etcd 目录中即可,etcd 的这些目录就可以通过 HTTP 的接口在外部访问。

场景三:分布式锁

因为 etcd 使用 Raft 算法保持了数据的强一致性,某次操作存储到集群中的值必然是全局一致的,所以很容易实现分布式锁。锁服务有两种使用方式,一是保持独占,二是控制时序。

  • 保持独占即所有获取锁的用户最终只有一个可以得到。etcd 为此提供了一套实现分布式锁原子操作 CAS(CompareAndSwap)的 API。通过设置prevExist值,可以保证在多个节点同时去创建某个目录时,只有一个成功。而创建成功的用户就可以认为是获得了锁。

  • 控制时序,即所有想要获得锁的用户都会被安排执行,但是获得锁的顺序也是全局唯一的,同时决定了执行顺序。etcd 为此也提供了一套 API(自动创建有序键),对一个目录建值时指定为POST动作,这样 etcd 会自动在目录下生成一个当前最大的值为键,存储这个新的值(客户端编号)。同时还可以使用 API 按顺序列出所有当前目录下的键值。此时这些键的值就是客户端的时序,而这些键中存储的值可以是代表客户端的编号。

场景四:分布式队列

分布式队列的常规用法与场景五中所描述的分布式锁的控制时序用法类似,即创建一个先进先出的队列,保证顺序。

另一种比较有意思的实现是在保证队列达到某个条件时再统一按顺序执行。这种方法的实现可以在 /queue 这个目录中另外建立一个 /queue/condition 节点。

  • condition 可以表示队列大小。比如一个大的任务需要很多小任务就绪的情况下才能执行,每次有一个小任务就绪,就给这个 condition 数字加 1,直到达到大任务规定的数字,再开始执行队列里的一系列小任务,最终执行大任务。

  • condition 可以表示某个任务在不在队列。这个任务可以是所有排序任务的首个执行程序,也可以是拓扑结构中没有依赖的点。通常,必须执行这些任务后才能执行队列中的其他任务。

  • condition 还可以表示其它的一类开始执行任务的通知。可以由控制程序指定,当 condition 出现变化时,开始执行队列任务。

其他场景:

集群监控与 Leader 竞选(CAS 机制)、分布式通知与协调(watcher机制)、负载均衡等

关于作者

任职拉勾网,是运维开发部的负责人,长期从事运维开发工作,有多年的运维技能培训经验,培训了多批运维同学,至今大致有300人左右;

技能:擅长python开发,django框架开发,Kubernetes架构、运维开发架构,Linux运维,Hadoop运维和流行监控;了解golang开发和C++开发。

爱好:美食,自驾和旅游




以上是关于ETCD的raft选举及应用场景的主要内容,如果未能解决你的问题,请参考以下文章

彻底搞懂etcd raft选举数据同步

彻底搞懂etcd raft选举数据同步

云原生 etcd 系列-2|Leader 是怎么选举出来的?

etcd源码解读之raft协议实现

etcd Raft 源码剖析

etcd Raft 源码剖析