etcd的Watch原理

这篇具有很好参考价值的文章主要介绍了etcd的Watch原理。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在 Kubernetes 中,各种各样的控制器实现了 Deployment、StatefulSet、Job 等功能强大的 Workload。控制器的核心思想是监听、比较资源实际状态与期望状态是否一致,若不一致则进行协调工作,使其最终一致。

那么当你修改一个 Deployment 的镜像时,Deployment 控制器是如何高效的感知到期望状态发生了变化呢?

要回答这个问题,我们需要从etcd的Watch特性说起,他是Kubernetes控制器的工作基础。

那么实际上我们有4个核心问题:

  • client获取事件的机制,etcd是使用轮询模式还是推送模式呢?两者有什么优缺点?
  • 事件是如何存储的?会保留多久?watch命令中的版本号有什么作用?
  • 当client和server端出现短暂网络波动等异常因素后,导致事件堆积时,server端会丢弃事件吗?如果你监听的历史版本号server端不存在了,你的代码怎么处理?
  • 如果你创建了上万个 watcher 监听 key 变化,当 server 端收到一个写请求后,etcd 是如何根据变化的 key 快速找到监听它的 watcher 呢?

接下来我就和你分别详细聊聊 etcd Watch 特性是如何解决这四大问题的。搞懂这四个问题,你就明白 etcd 甚至各类分布式存储 Watch 特性的核心实现原理了。

轮询 VS 流式推送

首先第一个问题是client获取事件机制,etcd是使用轮询还是推送模式呢?答案是etcd两者都使用过。

在etcd v2 Watch机制实现中,使用的是HTTP/1.x协议,实现简单,每一个watcher对应一个TCP连接。client通过HTTP/1.1协议长连接定时轮询server获取最新的数据变化事件。

但是当你的watcher成千上万的时候,即使集群空负载,大量轮询也会产生一定的QPS,server端会消耗大量的socket,内存等资源,导致etcd的稳定性无法满足Kubernetes的要求。

etcd v3 的 Watch 机制的设计实现并非凭空出现,它正是吸取了 etcd v2 的经验、教训而重构诞生的。

在 etcd v3 中,为了解决 etcd v2 的以上缺陷,使用的是基于 HTTP/2 的 gRPC 协议,双向流的 Watch API 设计,实现了连接多路复用。

HTTP/2 协议为什么能实现多路复用呢?

etcd的Watch原理

在 HTTP/2 协议中,HTTP 消息被分解独立的帧(Frame),交错发送,帧是最小的数据单位。每个帧会标识属于哪个流(Stream),流由多个数据帧组成,每个流拥有一个唯一的 ID,一个数据流对应一个请求或响应包。

如上图所示,client 正在向 server 发送数据流 5 的帧,同时 server 也正在向 client 发送数据流 1 和数据流 3 的一系列帧。一个连接上有并行的三个数据流,HTTP/2 可基于帧的流 ID 将并行、交错发送的帧重新组装成完整的消息。

通过以上机制,HTTP/2 就解决了 HTTP/1 的请求阻塞、连接无法复用的问题,实现了多路复用、乱序发送。

etcd 基于以上介绍的 HTTP/2 协议的多路复用等机制,实现了一个 client/TCP 连接支持多 gRPC Stream, 一个 gRPC Stream 又支持多个 watcher,如下图所示。同时事件通知模式也从 client 轮询优化成 server 流式推送,极大降低了 server 端 socket、内存等资源。

etcd的Watch原理

HTTP2.0的详细知识请看《小林coding》

当然在 etcd v3 watch 性能优化的背后,也带来了 Watch API 复杂度上升, 不过你不用担心,etcd 的 clientv3 库已经帮助你搞定这些棘手的工作了。

在 clientv3 库中,Watch 特性被抽象成 Watch、Close、RequestProgress 三个简单API 提供给开发者使用,屏蔽了 client 与 gRPC WatchServer 交互的复杂细节,实现了一个 client 支持多个 gRPC Stream,一个 gRPC Stream 支持多个 watcher,显著降低了你的开发复杂度。

同时当 watch 连接的节点故障,clientv3 库支持自动重连到健康节点,并使用之前已接收的最大版本号创建新的 watcher,避免旧事件回放等。

滑动窗口 VS MVCC

介绍完 etcd v2 的轮询机制和 etcd v3 的流式推送机制后,再看第二个问题,事件是如何存储的? 会保留多久呢?watch 命令中的版本号具有什么作用?

第二个问题的本质是历史版本存储,etcd 经历了从滑动窗口到 MVCC 机制的演变,滑动窗口是仅保存有限的最近历史版本到内存中,而 MVCC 机制则将历史版本保存在磁盘中,避免了历史版本的丢失,极大的提升了 Watch 机制的可靠性。

etcd v2 滑动窗口是如何实现的?它有什么缺点呢?

它使用的是如下一个简单的环形数组来存储历史事件版本,当 key 被修改后,相关事件就会被添加到数组中来。若超过 eventQueue 的容量,则淘汰最旧的事件。在 etcd v2 中,eventQueue 的容量是固定的 1000,因此它最多只会保存 1000 条事件记录,不会占用大量 etcd 内存导致 etcd OOM。

type EventHistory struct {
    Queue eventQueue
    StartIndex uint64
    LastIndex uint64
    rwl sync.RWMutex
}

但是它的缺陷显而易见的,固定的事件窗口只能保存有限的历史事件版本,是不可靠的。当写请求较多的时候、client 与 server 网络出现波动等异常时,很容易导致事件丢失,client 不得不触发大量的 expensive 查询操作,以获取最新的数据及版本号,才能持续监听数据。

特别是对于重度依赖 Watch 机制的 Kubernetes 来说,显然是无法接受的。因为这会导致控制器等组件频繁的发起 expensive List Pod 等资源操作,导致 APIServer/etcd 出现高负载、OOM 等,对稳定性造成极大的伤害。

etcd v3 的 MVCC 机制,正如上一节课所介绍的,就是为解决 etcd v2 Watch 机制不可靠而诞生。相比 etcd v2 直接保存事件到内存的环形数组中,etcd v3 则是将一个 key 的历史修改版本保存在 boltdb 里面。boltdb 是一个基于磁盘文件的持久化存储,因此它重启后历史事件不像 etcd v2 一样会丢失,同时你可通过配置压缩策略,来控制保存的历史版本数,在压缩篇我会和你详细讨论它。

最后 watch 命令中的版本号具有什么作用呢?

版本号是 etcd 逻辑时钟,当 client 因网络等异常出现连接闪断后,通过版本号,它就可从 server 端的 boltdb 中获取错过的历史事件,而无需全量同步,它是 etcd Watch 机制数据增量同步的核心。

可靠的事件推送机制

再看第三个问题,当 client 和 server 端出现短暂网络波动等异常因素后,导致事件堆积时,server 端会丢弃事件吗?若你监听的历史版本号 server 端不存在了,你的代码该如何处理?

第三个问题的本质是可靠事件推送机制,要搞懂它,我们就得弄懂 etcd Watch 特性的整体架构、核心流程,下图是 Watch 特性整体架构图。

etcd的Watch原理

当你通过 etcdctl 或 API 发起一个 watch key 请求的时候,etcd 的 gRPCWatchServer收到 watch 请求后,会创建一个 serverWatchStream, 它负责接收 client 的 gRPC Stream 的 create/cancel watcher 请求 (recvLoop goroutine),并将从 MVCC 模块接收的 Watch 事件转发给 client(sendLoop goroutine)。

当 serverWatchStream 收到 create watcher 请求后,serverWatchStream 会调用MVCC 模块的 WatchStream 子模块分配一个 watcher id,并将 watcher 注册到 MVCC的 WatchableKV 模块。

在 etcd 启动的时候,WatchableKV 模块会运行 syncWatchersLoop 和syncVictimsLoop goroutine,分别负责不同场景下的事件推送,它们也是 Watch 特性可靠性的核心之一。

从架构图中你可以看到 Watch 特性的核心实现是 WatchableKV 模块,下面我就为你抽丝剥茧,看看"etcdctl watch hello -w=json --rev=1"命令在 WatchableKV 模块是如何处理的?面对各类异常,它如何实现可靠事件推送?

etcd核心解决方案是复杂度管理,问题拆分

它通过将 watcher 划分为synced/unsynced/victim 三类,将问题进行了分解,并通过多个后台异步循环goroutine 负责不同场景下的事件推送,提供了各类异常等场景下的 Watch 事件重试机制,尽力确保变更事件不丢失、按逻辑时钟版本号顺序推送给 client。

高效事件匹配机制

介绍完可靠的事件推送机制后,最后我们再看第四个问题,如果你创建了上万个 watcher监听 key 变化,当 server 端收到一个写请求后,etcd 是如何根据变化的 key 快速找到监听它的 watcher 呢?一个个遍历 watcher 吗?

显然一个个遍历 watcher 是最简单的方法,但是它的时间复杂度是 O(N),在 watcher 数较多的场景下,会导致性能出现瓶颈。更何况 etcd 是在执行一个写事务结束时,同步触发事件通知流程的,若匹配 watcher 开销较大,将严重影响 etcd 性能。

那使用什么数据结构来快速查找哪些 watcher 监听了一个事件中的 key 呢?

也许你会说使用 map 记录下哪些 watcher 监听了什么 key 不就可以了吗? etcd 的确使用 map 记录了监听单个 key 的 watcher,但是你要注意的是 Watch 特性不仅仅可以监听单 key,它还可以指定监听 key 范围、key 前缀,因此 etcd 还使用了如下的区间树

etcd的Watch原理

当收到创建 watcher 请求的时候,它会把 watcher 监听的 key 范围插入到上面的区间树中,区间的值保存了监听同样 key 范围的 watcher 集合 /watcherSet。

当产生一个事件时,etcd 首先需要从 map 查找是否有 watcher 监听了单 key,其次它还需要从区间树找出与此 key 相交的所有区间,然后从区间的值获取监听的 watcher 集合。

区间树支持快速查找一个 key 是否在某个区间内,时间复杂度 O(LogN),因此 etcd 基于map 和区间树实现了 watcher 与事件快速匹配,具备良好的扩展性。文章来源地址https://www.toymoban.com/news/detail-434170.html

到了这里,关于etcd的Watch原理的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 前端 | (二)各种各样的常用标签 | 尚硅谷前端html+css零基础教程2023最新

    学习来源 :尚硅谷前端html+css零基础教程,2023最新前端开发html5+css3视频 系列笔记 : 【HTML4】(一)前端简介 【HTML4】(二)各种各样的常用标签 【HTML4】(三)表单及HTML4收尾 【CSS2】(四)CSS基础及CSS选择器 【CSS2】(五)CSS三大特性及常用属性 【CSS2】(六)CSS盒子模型

    2024年02月16日
    浏览(54)
  • etcd的Watch原理

    在 Kubernetes 中,各种各样的控制器实现了 Deployment、StatefulSet、Job 等功能强大的 Workload。控制器的核心思想是监听、比较资源实际状态与期望状态是否一致,若不一致则进行协调工作,使其最终一致。 那么当你修改一个 Deployment 的镜像时,Deployment 控制器是如何高效的感知到

    2024年02月02日
    浏览(24)
  • 【kubernetes】Etcd集群部署与验证

    前言 :二进制部署kubernetes集群在企业应用中扮演着非常重要的角色。无论是集群升级,还是证书设置有效期都非常方便,也是从事云原生相关工作从入门到精通不得不迈过的坎。通过本系列文章,你将从虚拟机准备开始,到使用二进制方式从零到一搭建起安全稳定的高可用

    2024年02月10日
    浏览(59)
  • [Kubernetes] etcd的集群基石作用

    1. 配置存储 etcd作为一个高度可靠的分布式键值存储系统,存储了Kubernetes集群的完整配置和状态数据。集群的元数据,包括节点信息、命名空间、部署、副本集、服务、持久卷声明等,全部存储在etcd中。 2. 数据一致性 etcd使用raft一致性算法保证了数据的强一致性,确保了在

    2024年04月24日
    浏览(35)
  • 【kubernetes系列】Kubernetes之job和cronjob控制器

    本章节将分享kubernetes中的job控制器和cronjob控制器,这是用于另外两种场景的pod控制器。 对于Deployment、ReplicaSet、ReplicationController等类型的控制器而言,它希望pod保持预期数目、持久运行下去,除非用户明确删除,否则这些对象一直存在,它们针对的是耐久性任务,如web服务

    2024年02月11日
    浏览(46)
  • Kubernetes Etcd不可用日志:NOSPACE 的问题修复

            两套k8s集群同一天同时出现etcd集群空间超过配额, kubectl get cs 时发现所有的 etcd 均返回503报错,查看etcd的告警发现有 NO SPACE 的信息且  etcdctl --endpoints=${ETCD_ENDPOINT} --cert=${ETCD_CERTFILE} --key=${ETCD_KEYFILE} --cacert=${ETCD_CAFILE} endpoint status  中的DB SIZE大于2GiB。       

    2024年02月08日
    浏览(31)
  • Kubernetes 准入控制器

    Kubernetes 极大地提高了当今生产中后端集群的速度和可管理性。由于灵活、可扩展、易用,Kubernetes 已成为容器编排的事实标准。Kubernetes 还提供了一系列保护功能。而 Admission Controllers(准入控制器) 是一组安全相关的插件,启用后能进一步使用 Kubernetes 更高级的安全功能。

    2024年02月06日
    浏览(40)
  • kubernetes-控制器

    目录 一、replicaset 二、deployment 1、版本迭代 2、回滚 3、滚动更新策略 4、暂停与恢复 三、daemonset 四、statefulset 五、job 六、cronjob ReplicaSet用于保证指定数量的 Pod 副本一直运行 replicaset是通过标签匹配pod replicaset自动控制副本数量,pod可以自愈 回收资源 Deployment 的主要作用是实

    2024年02月06日
    浏览(43)
  • 【云原生 | 从零开始学Kubernetes】二十三、Kubernetes控制器Statefulset

    该篇文章已经被专栏《从零开始学k8s》收录 上一篇文章:kubernetes持久化存储下 点击跳转 StatefulSet 是为了管理有状态服务的问题而设计的 对于StatefulSet中的Pod,每个Pod挂载自己独立的存储,如果一个Pod出现故障,从其他节点启动一个同样名字的Pod,要挂载上原来Pod的存储继续

    2024年02月03日
    浏览(33)
  • Kubernetes Pod控制器

    Pod控制器及其功用 Pod控制器,又称之为工作负载(workload),是用于实现管理pod的中间层,确保pod资源符合预期的状态,pod的资源出现故障时,会尝试进行重启,当根据重启策略无效,则会重新新建pod的资源 Deployment 部署无状态应用 负责创建和管理 ReplicaSet , 维护 Pod 副本数

    2024年02月12日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包