一图读懂 k8s informer
概述
为什么要有 k8s informer
我们都知道可以使用 k8s 的 Clientset 来获取所有的原生资源对象,那么怎么能持续的获取集群的所有资源对象,或监听集群的资源对象数据的变化呢?这里不需要轮询去不断执行 List 操作,而是调用 Watch 接口,即可监听资源对象的变化,当资源对象发生变化,客户端即可通过 Watch 接口收到资源对象的变化。
Watch 接口虽然可以直接使用,但一般情况下很少直接使用,因为往往由于集群中的资源较多,我们需要自己在客户端去维护一套缓存,而这个维护成本比较大。
也是因为如此,client-go 提供了自己的实现机制,Informers 应运而生。
什么是 k8s informer
informers 实现了持续获取集群的所有资源对象、监听集群的资源对象变化功能,并在本地维护了全量资源对象的内存缓存,以减少对 apiserver、对 etcd 的请求压力。Informers 在启动的时候会首先在客户端调用 List 接口来获取全量的对象集合,然后通过 Watch 接口来获取增量的对象,然后更新本地缓存。
此外 informers 也有很强的健壮性,当长期运行的 watch 连接中断时,informers 会尝试拉起一个新的 watch 请求来恢复连接,在不丢失任何事件的情况下恢复事件流。另外,informers 还可以配置一个重新同步的周期参数,每间隔该周期,informers 就会重新 List 全量数据。
在 informers 的使用上,通常每个 GroupVersionResource(GVR)只实例化一个 informers,但有时候我们在一个应用中往往会在多个地方对同一种资源对象都有 informer 的需求,所以就有了共享 informer,即 SharedInformerFactory。所以可以通过使用 SharedInformerFactory 来实例化 informers,这样本地内存缓存就只有一份,通知机制也只有一套,大大提高了效率,减少了资源浪费。
一图读懂 k8s informer
这里先给出一张 k8s informer 的详细架构图;
从图中可以看出,k8s informer 主要包括以下几个部分:
1.Reflector
(1)Reflector 从 kube-apiserver 中 list 资源对象列表,然后调用 DeltaFIFO 的 Replace 方法将 object 包装成 Sync/Deleted 类型的 Delta 丢进 DeltaFIFO 中;
(2)Reflector 从 kube-apiserver 中 watch 资源对象的变化,然后调用 DeltaFIFO 的 Add/Update/Delete 方法将 object 包装成 Added/Updated/Deleted 类型的 Delta 丢到 DeltaFIFO 中;
2.DeltaFIFO
DeltaFIFO 中存储着一个 map 和一个 queue;
(1)其中 queue 可以看成是一个先进先出队列,一个 object 进入 DeltaFIFO 中,会判断 queue 中是否已经存在该 object key,不存在则添加到队尾;
(2)map 即 map[object key]Deltas,是 object key 和 Deltas 的映射,Deltas 是 Delta 的切片类型,Delta 中存储着 DeltaType 和 object;另外,Deltas 最末尾的两个 Deleted 类型的 Delta 会被去重;
3.Controller
Controller 从 DeltaFIFO 的 queue 中 pop 一个 object key 出来,并从 DeltaFIFO 的 map 中获取其对应的 Deltas 出来进行处理,遍历 Deltas,根据 object 的变化类型更新 Indexer 本地缓存,并通知 Processor 相关对象有变化事件发生:
(1)如果 DeltaType 是 Deleted,则调用 Indexer 的 Delete 方法,将 Indexer 本地缓存中的 object 删除,并构造 deleteNotification struct,通知 Processor 做处理;
(2)如果 DeltaType 是 Added/Updated/Sync,调用 Indexer 的 Get 方法从 Indexer 本地缓存中获取该对象,存在则调用 Indexer 的 Update 方法来更新 Indexer 缓存中的该对象,随后构造 updateNotification struct,通知 Processor 做处理;如果 Indexer 中不存在该对象,则调用 Indexer 的 Add 方法将该对象存入本地缓存中,并构造 addNotification struct,通知 Processor 做处理;
4.Processor
Processor 根据 Controller 的通知,即根据对象的变化事件类型(addNotification、updateNotification、deleteNotification),调用相应的 ResourceEventHandler(addFunc、updateFunc、deleteFunc)来处理对象的变化。
5.Indexer
Indexer 中有 informer 维护的指定资源对象的相对于 etcd 数据的一份本地内存缓存,可通过该缓存获取资源对象,以减少对 apiserver、对 etcd 的请求压力。
informer 所维护的缓存依赖于 threadSafeMap 结构体中的 items 属性,其本质上是一个用 map 构建的键值对,资源对象都存在 items 这个 map 中,key 为资源对象的 namespace/name 组成,value 为资源对象本身,这些构成了 informer 的本地缓存。
Indexer 除了维护了一份本地内存缓存外,还有一个很重要的功能,便是索引功能了。索引的目的就是为了快速查找,比如我们需要查找某个 node 节点上的所有 pod、查找某个命名空间下的所有 pod 等,利用到索引,可以实现快速查找。关于索引功能,则依赖于 threadSafeMap 结构体中的 indexers 与 indices 属性。
6.ResourceEventHandler
用户根据自身处理逻辑需要,注册自定义的的 ResourceEventHandler,当对象发生变化时,将触发调用对应类型的 ResourceEventHandler 来做处理。
k8s informer 详细分析
之前的文章也对 k8s informer 进行了一系列的详细分析,有兴趣的可以看一下对 k8s informer 的详细分析,这里给出 k8s client-go/k8s informer 分析系列的链接导航:
(1)informer 概要分析;https://xie.infoq.cn/article/c60958e7d079709b1c4789440
(2)informer 之初始化与启动分析;https://xie.infoq.cn/article/2981447bf7b1ea1534ef19399
(3)informer 之 Reflector 分析;https://xie.infoq.cn/article/9298871421f997d12f8dd921c
(4)informer 之 DeltaFIFO 分析;https://xie.infoq.cn/article/21b3aac095d9431b4c8a2169e
(5)informer 之 Controller&Processor 分析;https://xie.infoq.cn/article/50611346f8aba835c5c8f06b9
(6)informer 之 Indexer 分析;https://xie.infoq.cn/article/84f8e71d111e3ff59c3ee7d2d
版权声明: 本文为 InfoQ 作者【良凯尔】的原创文章。
原文链接:【http://xie.infoq.cn/article/f9837d375de6bbe52b92b306a】。文章转载请联系作者。
评论