K8S informer机制
一、informer介绍
Kubernetes基于声明式API的设计理念,所谓声明式API,即告诉Kubernetes Controller资源对象的期望状态,这样为Kubernetes在事件通知后,动作执行前这段过程里提供了更多的容错空间与扩展空间。这就需要Kubernetes Controller能够知道资源对象的当前状态,通常需要访问API Server才能获得资源对象,当Controller越来越多时,会导致API Server负载过大。
Kubernetes使用Informer代替Controller去访问API Server,Controller的所有操作都和Informer进行交互,而Informer并不会每次都去访问API Server。Informer使用ListAndWatch的机制,在Informer首次启动时,会调用LIST API获取所有最新版本的资源对象,然后再通过WATCH API来监听这些对象的变化,并将事件信息维护在一个只读的缓存队列中提升查询的效率,同时降低API Server的负载
除了ListAndWatch,Informer还可以注册相应的事件,之后如果监听到的事件变化就会调用对应的EventHandler,实现回调。Informer主要包含以下组件。
1) Controller:Informer的实施载体,可以创建reflector及控制processLoop。processLoop将DeltaFIFO队列中的数据pop出,首先调用Indexer进行缓存并建立索引,然后分发给processor进行处理。
2) Reflector:Informer并没有直接访问k8s-api-server,而是通过一个叫Reflector的对象进行api-server的访问。Reflector通过ListAndWatch监控指定的 kubernetes 资源,当资源发生变化的时候,例如发生了 Added 资源添加等事件,会将其资源对象存放在本地缓存 DeltaFIFO 中。
3) DeltaFIFO:是一个先进先出的缓存队列,用来存储 Watch API 返回的各种事件,如Added、Updated、Deleted 。
4) Indexer:Indexer使用一个线程安全的数据存储来存储对象和它们的键值。需要注意的是,Indexer中的数据与etcd中的数据是完全一致的,这样client-go需要数据时,无须每次都从api-server获取,从而减少了请求过多造成对api-server的压力。一句话总结:Indexer是用于存储+快速查找资源。
5) Processor:记录了所有的回调函数(即 ResourceEventHandler)的实例,并负责触发回调函数
二、informer机制流程图
Informer负责与Kubernetes APlServer进行Watch操作, Watch的资源,可以是Kubernetes内置资源对象,也可以是CRD。
Informer是一个带有本地缓存以及素引机制的核心工具包,当请求为查询操作的时候.会优先从本地缓存内去查找数据,而创建、更新、删除,这类的操作,则会根据事 件通知写入到 例 列D el taFI FO中 , 应的事件处理过后,更新本地缓存,使本地缓存与ETCD的数据保持一致。
informer抽象出来的这个缓存层,将查询相关操作的压力接收了下来,这样就不必每次都去调用APIServer的接口,减轻了APIServer的数据交互压力。
从上图就能看出来, Informer是有多个组件构成的。下面咱们就先简单了解一下都是什么组件,后面在详细的介绍一下这些组件。
• Reflector:使用List-Watch来保证本地缓存数据的、准确性、顺序性和一致性的, List对应资源的全量列表数据, Watch负责变化部分的数据, Watch指 定的 Kubemes资源,当watch的资源 发生 变化时,触发变更的事件,比如Added, Updated和Deleted事件,并将资源对象的变化事件存放到本地队列DeltaFIFO中。
• DetalFFO:是一个增量队列。记录了资源变化的过程, Reflector就相当于队列的生产者。这个组件可以拆分为两部分来理解,FFO就是一个 队列,拥有 队列 基本 方法,例如ADD,UPDATE,DELETE,POP,CLOSE等, Delta是一个资源对象存储,保存存储对象的消费类型,比如Added, Updated, Deleted等。
• indexer:用来存储资源对象并自带索引功能的本地存储, Reflector从DetaFIFO中将消费出来的资源对象存储到Indexer, Indery与Etcd中的数据完全保持一 致。从而 client- go可以本 地读取,减少Kubernetes APIServer的数据交互压力。
三、Reflector组件
Reflector是Client-Go中,用来监听指定资源的组件,当资源发生变化的时候,例如增加、更新、删除等操作的时候,会以事件的形式存入本地队列,然后有对应的方法处理。
在Reflector中,核心的部分就是List-Watch,其他功能基本上也是围绕这它来搞的。
在实例化Relector的过程中,有一个ListerWatcher的接口对象,这个结构对象有两个方法,分别是List和Watch,这两个方法就实现了咱们前面介绍的List-Watch功能,如果还没有了解过,可以看下上次视频内容,这边就不过多的介绍了。
下面咱们来说说 Reflector 的核心逻辑,其实它的核心逻辑可以简单归为三部分。
• List:调用List方法获取资源全部列表数据,“转换为资源对象列表,然后保存到本地缓存中。
• 定时同步:定时器定时触发同步机制,定时更新缓存数据,在Reflector的结构体对象中,是可以配置定时同步的周期时间的。
• Watch:监听资源的变化,并且调用对应的事件处理函数来进行处理。
Reflector组件对于数据更新同步,都是基于ResourceVersion来进行的,每个资源对象都会有ResourceVersion这个属性,当数据发生变化的时候, ResourceVersion也将会以递增的形式更新,这样就确保了变更事件的顺序性。
Watch资源对象的时候,ResourceVersion可以根据我们的需求,进行配置。
• ResourceVersion未设置的时候,从最新版本开始监听。
。为了建立初始状态, Watch从起始资源版本中存在的所有资源实例的合成“添加”事件开始。以下所有监视事件都针对在Watch开始的资源版本之后发生的 所有更改。
• ResourceVersion设置为"0"的时候,则表示从任意版本开始监听。
。以这种方式初始化的监视可能会返回任意陈旧的数据。首选可用的最新资源版本,但不是必需的。允许任何起始资源版本。由于分区或过时的缓存, Watch可能从客户端之前观察到的更旧的资源版本开始,特别是在高可用性配置中。不能容忍这种明显倒带的客户不应该用这种语义启动Watch。
。为了建立初始状态, Watch从起始资源版本中存在的所有资源实例的合成“添加”事件开始。以下所有监视事件都针对在watch开始的资源版本之后发生的所有更改。
• ResourceVersion从指定版本开始监听。
。监视事件适用于提供的资源版本之后的所有更改。Watch不会以所提供资源版本的合成“添加”事件启动。由于客户端提供了资源版本,因此假定客户端已 经具有起始资源版本的初始状态。
ResburceVersion不仅是在Reflector中有重要的应用, Update机制或Patch机制也是会基于ResourceVersion来比较两个资源对象,确定是否有 变化的。
当Watch资源断开的时候, Reflector会重新进行List-Watch以确保数据的可靠性。
同时Watch使用HTTP的长链接的形式进行资源的监听,保证了数据实时性的同时,还减轻Kubernetes APIServer的访问压力。
四、DeltaFIFO
DeltaFIFO是一个增量的本地队列,记录了资源对象的变化过程。它的生产者就是Reflector组件。将监听的对象,同步到DeltaFIFO中。
DeltaFIFO是分为两部分的。分别FIFO和Delta。FIFO就是一个先入先出的本地队列, Delta则是资源对象的变化,例如增加、删除、修改等。
FIFO负责接收Reflector传递过来的事件,并将其按照顺序存储,然后等待事件的处理函数进行处理,同时若出现多个相同的事件,则只会被处理一次。
FIFO既然是一个队列那么就肯定有队列相关的操作方法,在这里就是通过Queue这个接口对象,来实现队列所需的方法的,同时还根据需求拓展了一些其他的方法。例如:Pop、AddIfNotPresent等。
Delta有两个属性,分别是Type和Object。
• Type就表示这个事件的类型,就比如说Added表示增加, Updated表示更新等等。
• Object是一个interface类型的,它就表示一个具体Kubernetes资源对象,例如:Pod、Service等。
五、Indexer
Indexer是啥呢?
通过字面意思我们可以看出它叫做“索引器”对吧。它其实就是informer中LocalStore的部分。Indexer本身是一个存储,同时在存储的基础上扩展了索引的功能。
Reflector通过DeltaFiFO一系列的操作后,然后更新存储到indexer中。
Inderer中的数据,与Etcd中的数据是完全一致的,当Cient-Qo需要获取数据的时候,则无法每次都从APIServer中仅取,从而减轻了APIServer的 请求压力。
在更深入了解indexer之前,我们还需要知道indexer中几个非常重要的概念。
• IndexFunc:索引器函数,用于计算一个资源对象的索引值列表,可以根据需求定义其他的,比如根据Label标签, Arnotation等属性来生成索引值列 表。
• Index:存储数据,要查找某个命名空间下面的Pod,那就要让Pod按照其命名空间进行索引,对应的Index类型就是 map(namespace) sets. pod,
• Indexers:存储索引器, key为索引器名称, value为索引器的实现函数,例如:map["namespace"]MetaNamespaceIndexFunc,
• Indices:存储缓存器, key为索引器名称, value为缓存的数据,例如:map["namespace"]map[namespace]sets. pod,
最容易混淆的是Indexers和Indices这两个概念,我们可以这样理解:Indevers是存储索引(生成素引错)的, Indices里面是存储的真正的数据(对象键)。
K8S informer机制的更多相关文章
- 如何高效掌控K8s资源变化?K8s Informer实现机制浅析
作者 王成,腾讯云研发工程师,Kubernetes contributor,从事数据库产品容器化.资源管控等工作,关注 Kubernetes.Go.云原生领域. 概述 进入 K8s 的世界,会发现有很 ...
- 一图读懂k8s informer client-go
概述 为什么要有k8s informer 我们都知道可以使用k8s的Clientset来获取所有的原生资源对象,那么怎么能持续的获取集群的所有资源对象,或监听集群的资源对象数据的变化呢?这里不需要轮询 ...
- 《k8s-1.13版本源码分析》- Informer 机制
源码分析系列文章已经开源到github,地址如下: github:https://github.com/farmer-hutao/k8s-source-code-analysis gitbook:ht ...
- Kubernetes 降本增效标准指南 | 基于K8s 扩展机制构建云上成本控制系统
作者 王玉君,腾讯云后台高级开发工程师,负责腾讯云原生系统开发及建设. 晏子怡,腾讯云容器产品经理,在K8s弹性伸缩.资源管理领域有丰富的实战经验. 导语 Kubernetes 作为 IaaS 和 P ...
- K8S访问机制
pod -> endpoint -> service -> namespace -> svc.cluster.local .....在 a 名称空间,访问 b 名称空间的 b1 ...
- 如何接入 K8s 持久化存储?K8s CSI 实现机制浅析
作者 王成,腾讯云研发工程师,Kubernetes contributor,从事数据库产品容器化.资源管控等工作,关注 Kubernetes.Go.云原生领域. 概述 进入 K8s 的世界,会发现有很 ...
- 16.深入k8s:Informer使用及其源码分析
转载请声明出处哦~,本篇文章发布于luozhiyun的博客:https://www.luozhiyun.com 由于这部分的代码是在client-go 中,所以使用的源码版本是client-go 1. ...
- K8s 系列(四) - 浅谈 Informer
1. 概述 进入 K8s 的世界,会发现有很多的 Controller,它们都是为了完成某类资源(如 pod 是通过 DeploymentController, ReplicaSetControlle ...
- k8s client-go源码分析 informer源码分析(1)-概要分析
k8s informer概述 我们都知道可以使用k8s的Clientset来获取所有的原生资源对象,那么怎么能持续的获取集群的所有资源对象,或监听集群的资源对象数据的变化呢?这里不需要轮询去不断执行L ...
- K8s 如何提供更高效稳定的编排能力?K8s Watch 实现机制浅析
关于我们 更多关于云原生的案例和知识,可关注同名[腾讯云原生]公众号~ 福利: ①公众号后台回复[手册],可获得<腾讯云原生路线图手册>&<腾讯云原生最佳实践>~ ②公 ...
随机推荐
- Appium常见属性和命令
from appium import webdriverimport time, tracebackdesired_caps = {}desired_caps['platformName'] = 'A ...
- vue框架08 vue3
vue3的介绍 # vue项目的版本,新项目使用vue3,部分老项目使用vue2 # vue3的变化 1.性能的提升 - 打包大小减少41% - 初次渲染快55%,更新渲染块133% - 内存减少54 ...
- Pygame的基本应用(14周)
制作一个跳跃的小球游戏 创建一个游戏窗口,然后在窗口内创建一个小球.以一定的速度移动小球,当小球碰到游戏窗口的边缘时,小球弹回,继续移动.代码如下: import sysimport p ...
- Golang依赖管理工具: go module 详解
Golang依赖管理工具: go module (go1.11+) 大多数语言都会有包管理工具,像Node有npm,PHP有composer,Java有Maven和Gradle. 可是,Go语言一直缺 ...
- vue实现全部防抖
// 全局注册防抖 Vue.component("ElButton").mixin({ data() { return { debounce: false ...
- git---全局设置用户名、密码、邮箱
# git config命令的–global参数,用了这个参数,表示你这台机器上所有的Git仓库都会使用这个配置,当然也可以对某个仓库指定不同的用户名和Email地址. # 1.查看git配置信息 $ ...
- Docker部署Springboot+Vue项目
1 docker使用nginx部署vue项目 1.1 打包vue项目 npm run build vue项目路径下会增加一个dist文件夹,里面就是网页文件 1.2 使用docker 拉取nginx ...
- leecode64. 最小路径和(动态规划)
64. 最小路径和 给定一个包含非负整数的 m x n 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小. 说明:每次只能向下或者向右移动一步. 示例 1: 输入:gri ...
- python 小顶堆
from heapq import *heap=[]for i in range(10,1,-1): heappush(heap,i)print(heap)print(heappop(heap))pr ...
- Java笔记_构造方法/构造器
构造方法/构造器(constructor) 怎么来的?之前在创建对象时,是先把一个对象创建好后,再给这个对象的属性赋值,如果现在要求在创建一个对象时,就直接指定这个对象的属性,该怎么做?此时就可以 ...