5. informer源码分析-概要分析

k8s client-go k8s informers 实现了持续获取集群的所有资源对象监听集群的资源对象变化功能,并在本地维护了全量资源对象的内存缓存,以减少对 apiserver、对 etcd 的请求压力。Informers 在启动的时候会首先在客户端调用 List 接口来获取全量的对象集合,然后通过 Watch 接口来获取增量的对象,然后更新本地缓存

1. k8s informer 概述

我们都知道可以使用 k8s 的 Clientset 来获取所有的原生资源对象,那么怎么能持续的获取集群的所有资源对象,或监听集群的资源对象数据的变化呢?这里不需要轮询去不断执行 List 操作,而是调用 Watch 接口,即可监听资源对象的变化,当资源对象发生变化,客户端即可通过 Watch 接口收到资源对象的变化。

Watch 接口虽然可以直接使用,但一般情况下很少直接使用,因为往往由于集群中的资源较多,我们需要自己在客户端去维护一套缓存,而这个维护成本比较大。

也是因为如此,client-go 提供了自己的实现机制,Informers 应运而生。informers 实现了持续获取集群的所有资源对象、监听集群的资源对象变化功能,并在本地维护了全量资源对象的内存缓存,以减少对 apiserver、对 etcd 的请求压力。Informers 在启动的时候会首先在客户端调用 List 接口来获取全量的对象集合,然后通过 Watch 接口来获取增量的对象,然后更新本地缓存

此外 informers 也有很强的健壮性,当长期运行的 watch 连接中断时,informers 会尝试拉起一个新的 watch 请求来恢复连接,在不丢失任何事件的情况下恢复事件流。另外,informers 还可以配置一个重新同步的周期参数,每间隔该周期,informers 就会重新 List 全量数据

在 informers 的使用上,通常每个 GroupVersionResource(GVR)只实例化一个 informers,但有时候我们在一个应用中往往会在多个地方对同一种资源对象都有 informer 的需求,所以就有了共享 informer,即 SharedInformerFactory。所以可以通过使用 SharedInformerFactory 来实例化 informers,这样本地内存缓存就只有一份,通知机制也只有一套,大大提高了效率,减少了资源浪费。

1.1 k8s informer 架构

在这里插入图片描述

1.2 k8s informer 包含部件

k8s client-go informer 主要包括以下部件:

  • Reflector:Reflector 从 kube-apiserver 中 list&watch 资源对象,然后调用 DeltaFIFO 的 Add/Update/Delete/Replace 方法将资源对象及其变化包装成 Delta 并将其丢到 DeltaFIFO 中;
  • DeltaFIFO:DeltaFIFO 中存储着一个 map 和一个 queue,即map[object key]Deltas 以及 object key 的 queue,Deltas 为 Delta 的切片类型,Delta 装有对象及对象的变化类型(Added/Updated/Deleted/Sync) ,Reflector 负责 DeltaFIFO 的输入,Controller 负责处理 DeltaFIFO 的输出;
  • Controller:Controller 从 DeltaFIFO 的 queue 中 pop 一个 object key 出来,并获取其关联的 Deltas 出来进行处理,遍历 Deltas,根据对象的变化更新 Indexer 中的本地内存缓存,并通知 Processor,相关对象有变化事件发生;
  • Processor:Processor 根据对象的变化事件类型,调用相应的 ResourceEventHandler 来处理对象的变化;
  • Indexer:Indexer 中有 informer 维护的指定资源对象的相对于 etcd 数据的一份本地内存缓存,可通过该缓存获取资源对象,以减少对 apiserver、对 etcd 的请求压力;
  • ResourceEventHandler:用户根据自身处理逻辑需要,注册自定义的的 ResourceEventHandler,当对象发生变化时,将触发调用对应类型的 ResourceEventHandler 来做处理。

根据 informer 架构,对 k8s informer 的分析将分为以下几部分进行,本篇为概要分析:
(1)informer概要分析;
(2)informer之初始化与启动分析;
(3)informer之Reflector分析;
(4)informer之DeltaFIFO分析;
(5)informer之Controller&Processor分析;
(6)informer之Indexer分析;


2. informer 使用示例代码

使用大致过程如下:
(1)构建与 kube-apiserver 通信的 config 配置;
(2)初始化与 apiserver 通信的 clientset;
(3)利用 clientset 初始化 shared informer factory 以及 pod informer;
(4)注册 informer 的自定义 ResourceEventHandler;
(5)启动 shared informer factory,开始 informer 的 list & watch 操作;
(6)等待 informer 从 kube-apiserver 同步资源完成,即 informer 的 list 操作获取的对象都存入到 informer 中的 indexer 本地缓存中;
(7)创建 lister,可以从 informer 中的 indexer 本地缓存中获取对象;

func main() {// 自定义与kube-apiserver通信的config配置master := "192.168.1.10" // apiserver urlkubeconfig := "/.kube/config"config, err = clientcmd.BuildConfigFromFlags(master, kubeconfig)if err != nil {klog.Fatalf("Failed to create config: %v", err)}// 或使用k8s serviceAccount机制与kube-apiserver通信// config, err = rest.InClusterConfig()// 初始化与apiserver通信的clientsetclientset, err := kubernetes.NewForConfig(config)if err != nil {klog.Fatalf("Failed to create client: %v", err)}// 初始化shared informer factory以及pod informerfactory := informers.NewSharedInformerFactory(clientset, 30*time.Second)podInformer := factory.Core().V1().Pods()informer := podInformer.Informer()// 注册informer的自定义ResourceEventHandlerinformer.AddEventHandler(cache.ResourceEventHandlerFuncs{AddFunc:    xxx,UpdateFunc: xxx,DeleteFunc: xxx,})// 启动shared informer factory,开始informer的list & watch操作stopper := make(chan struct{})go factory.Start(stopper)// 等待informer从kube-apiserver同步资源完成,即informer的list操作获取的对象都存入到informer中的indexer本地缓存中 // 或者调用factory.WaitForCacheSync(stopper)if !cache.WaitForCacheSync(stopper, informer.HasSynced) {runtime.HandleError(fmt.Errorf("Timed out waiting for caches to sync"))return}// 创建listerpodLister := podInformer.Lister()// 从informer中的indexer本地缓存中获取对象podList, err := podLister.List(labels.Everything())if err != nil {fmt.Println(err)}}

以上只是对 K8s informer 做了简单的介绍,以及简单的写了一下如何使用 informer 的示例代码,后面将开始对 informer 的各个部件做进一步的源码分析。

从图中可以看出,k8s informer主要包括以下几个部分:

2.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.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 会被去重;

DeltaType 有4种,分别是 Added、Updated、Deleted、Sync

2.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 做处理;

2.4.Processor

Processor 根据 Controller 的通知,即根据对象的变化事件类型(addNotification、updateNotification、deleteNotification),调用相应的 ResourceEventHandler(addFunc、updateFunc、deleteFunc)来处理对象的变化。

2.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 属性。

2.6.ResourceEventHandler

用户根据自身处理逻辑需要,注册自定义的的 ResourceEventHandler,当对象发生变化时,将触发调用对应类型的 ResourceEventHandler 来做处理。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/714086.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++中boost库的安装及使用(Windows)

Boost库的安装及使用 引言使用现有的boost库安装及使用引言 C++开发中经常会用到boost库,本文记录一下Windows上boost在visual studio2019上的使用。 Boost库是一个跨平台的C++库集合,旨在为C++开发者提供一系列高质量的通用功能。不同的Visual Studio(VS)版本并不要求安…

日常科研中经常使用的命令

Linux目录树状结构 1. Windows是磁盘分区,Linux不区分盘符,所有文件都在根目录斜线下面; 2. 根目录显示不同,Linux是一个斜线,而windows是盘符,然后冒号; 3. 分割目录Linux用斜线&#xff0c…

React编写组件时,如何省略.tsx后缀

省略.tsx后缀 当tsconfig.json配置了,需要重启后才会生效 {"compilerOptions": {"allowJs": true,"jsx": "react-jsx",} }当进行以上配置后,导入组件时添加后缀,Eslint报错如下: An im…

【算法集训】基础算法:基础排序 - 冒泡排序

一、基本理解 贴上图解,更容易理解代码:https://visualgo.net/zh/sorting 冒泡排序(Bubble Sort)又称为泡式排序,是一种简单的排序算法。 核心思想: 它重复地走访过要排序的数列,一次比较两个元素,如果它…

性能比较:in和exists

当在Hive SQL中使用NOT IN和NOT EXISTS时,性能差异主要取决于底层数据的组织方式、数据量大小、索引的使用情况以及具体查询的复杂程度。下面是对这两种方法的性能分析: 1. NOT IN:- 工作原理:NOT IN子查询会逐个比较主查询中的值…

化肥工业5G智能制造工厂数字孪生可视化平台,推进化肥行业数字化转型

化肥工业5G智能制造工厂数字孪生可视化平台,推进化肥行业数字化转型。随着科技的不断发展,数字化转型已经成为各行各业发展的必然趋势。在化肥工业领域,5G智能制造工厂数字孪生可视化平台的应用正在逐渐普及,为行业数字化转型提供…

Java 循环结构 - while ,do…while 及 for,

目录 Java中有三种主要的循环结构: while 循环 实例 do…while 循环 实例 for循环 实例 三种循环之间的区别 增强 for 循环 实例 break 关键字 语法 实例 continue 关键字 语法 实例 顺序结构的程序语句只能被执行一次。 如果您想要同样的操作执行…

租用云服务器租时要注意的问题有哪些?

随着云计算的不断发展,对云计算服务器的需求也越来越大。 那么,我们应该如何以正确的态度和方法来选择云服务器呢? 租用云服务器需要注意哪些问题? 1.了解您需要的云服务类型 了解您的云计算需求将使您了解您正在寻求的服务类型…

web运行时安全

1.输入验证 对传递的数据的格式、长度、类型(前端和后端都要)进行校验。 对黑白名单校验:比如前端传递了一个用户名,可以搜索该用户是否在白名单或者黑名单列表。 针对黑名单校验,比如: // 手机号验证…

让两个电脑通信的方法(TCP连接,UDP连接,C/S架构)

目录 TCP-面向连接UDP-面向无连接C/S架构服务器和客户端的工作过程C/S架构例子 让两个电脑通信的方法是 在C/S的基础上,采用TCP和UDP的方式连接 TCP-面向连接 UDP-面向无连接 C/S架构 服务器和客户端的工作过程 C/S架构例子 服务器与客户端通信的过程类似公司与客户…

微信小程序云开发教程——墨刀原型工具入门(添加交互事件)

引言 作为一个小白,小北要怎么在短时间内快速学会微信小程序原型设计? “时间紧,任务重”,这意味着学习时必须把握微信小程序原型设计中的重点、难点,而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…

殿堂级Flink源码极精课程预售

一、为什么我们要读源码? 1、让个人技术快速成长: 优秀的开源框架,底层的源码设计思想也非常优秀,同时还有含有大量的设计模式和并发编程技术,优秀的解决方案,熟读源码对猿们技术提升有很大帮助 2、新技术学习能力: Java开源码框架的源码熟读后,若出现…

第一篇:参考资料地址

javaGuide JavaGuide(Java学习&面试指南) | JavaGuide 清华学生总结的 小林coding labuladong labuladong 的算法笔记 | labuladong 的算法笔记 【华仔说技术】kafka的系列文章 https://mp.weixin.qq.com/mp/appmsgalbum?__bizMzg3MTcxMDgxNA…

【Datawhale组队学习:Sora原理与技术实战】Sora技术原理

Sora能力边界探索 最大支持60秒高清视频生成,以及基于已有短视频的前后扩展,同时保持人物/场景的高度一致性如奶茶般丝滑过渡的视频融合能力同一场景的多角度/镜头的生成能力具有动态摄像机运动的视频。随着摄像机的移动和旋转,人和其 他场景…

x-pack的破解方式和免费jar包!!可直接用!!

原理介绍 我们平时为es安装x-pack组件,用elasticsearch-plugin install x-pack ,安装成功后。 1.cd $es目录/pulgins/x-pack 里面有一个x-pack-5.6.2.jar ,将jar包反编译,然后将里面的licence的程序改下。再编译成jar包。 2…

通过笔记本桥接打印机组成网络打印机其它电脑与之相连各种问题汇总

根据描述需要一台低配闲置笔记本(有无线网卡),一台普通台式打印机(不带WIFI)就可以组成网络打印机,能省1000块不? 1. 让笔记本安装驱动使其可以打印。 2. 让笔记本上的打印机共享,…

解决 MacOS Sonoma 14 系统下修改用户名无法进入系统的历史Bug

苹果系统祖传Bug概述 在MacOS中如果在系统偏好设置/用户和群组中尝试修改用户名或用户ID,当且仅当只有一个管理员账号的时候重启,就可能面临到无法进入操作系统,即使出现了登录框,但是一直是 loading状态在这个期间,你…

javaScript 深浅拷贝

javaScript深浅拷贝 浅拷贝 自己创建一个新的对象,来接受你要重新复制或引用的对象值。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象,但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个…

Python 编程中的迭代器、生成器和装饰器探究【第110篇—迭代器】

Python 编程中的迭代器、生成器和装饰器探究 在Python编程中,迭代器(Iterators)、生成器(Generators)和装饰器(Decorators)是三个强大的概念,它们为代码的可读性、效率和灵活性提供…

PaddleOCR的部署教程(实操环境安装、数据集制作、实际应用案例)

文章目录 前言 PaddleOCR简介 一、PaddleOCR环境搭建 因为我之前安装过cuda和cudnn,查看cuda的版本根据你版本安装合适的paddlepaddle版本(之前没有安装过cuda的可以看我这篇文章Ubuntu20.04配置深度学习环境yolov5最简流程) 1.创建一个…