QCon北京「鸿蒙专场」火热来袭!即刻报名,与创新同行~ 了解详情
写点什么

“高冷”的 Kubernetes Informer 一探究竟

  • 2020-03-04
  • 本文字数:2522 字

    阅读完需:约 8 分钟

“高冷”的 Kubernetes Informer 一探究竟

今天给到大家介绍一下 Client-go 中的一个非常关键的工具包 Informer。 Informer 内部实现极其复杂,详细介绍的文章也很少,很多人反馈比较难用。但不得不承认它也是一个设计精良、安全可靠的组件,值得我们去一探究竟。

Informer 简介

Informer 基础功能


Informer 是 Client-go 中的一个核心工具包。在 Kubernetes 源码中,如果 Kubernetes 的某个组件,需要 List/Get Kubernetes 中的 Object,在绝大多 数情况下,会直接使用 Informer 实例中的 Lister()方法(该方法包含 了 Get 和 List 方法),而很少直接请求 Kubernetes API。Informer 最基本 的功能就是 List/Get Kubernetes 中的 Object。


如下图所示,仅需要十行左右的代码就能实现对 Pod 的 List 和 Get。


Informer 高级功能


Client-go 的首要目标是满足 Kubernetes 的自身需求。Informer 作为其中的核心工具包,面对 Kubernetes 极为复杂业务逻辑,如果仅实现 List/Get 功能,根本无法满足 Kubernetes 自身需求。因此,Informer 被设计为一个灵活而复杂的工具包,除 List/Get Object 外,Informer 还可以监听事件并触发回调函数等,以实现更加复杂的业务逻辑。

Informer 设计思路

Informer 设计中的关键点


为了让 Client-go 更快地返回 List/Get 请求的结果、减少对 Kubenetes API 的直接调用,Informer 被设计实现为一个依赖 Kubernetes List/Watch API 、可监听事件并触发回调函数的二级缓存工具包。


更快地返回 List/Get 请求,减少对 Kubenetes API 的直接调用


使用 Informer 实例的 Lister() 方法, List/Get Kubernetes 中的 Object 时,Informer 不会去请求 Kubernetes API,而是直接查找缓存在本地内存中的数据(这份数据由 Informer 自己维护)。通过这种方式,Informer 既可以更快地返回结果,又能减少对 Kubernetes API 的直接调用。


依赖 Kubernetes List/Watch API


Informer 只会调用 Kubernetes List 和 Watch 两种类型的 API。Informer 在初始化的时,先调用 Kubernetes List API 获得某种 resource 的全部 Object,缓存在内存中; 然后,调用 Watch API 去 watch 这种 resource,去维护这份缓存; 最后,Informer 就不再调用 Kubernetes 的任何 API。


用 List/Watch 去维护缓存、保持一致性是非常典型的做法,但令人费解的是,Informer 只在初始化时调用一次 List API,之后完全依赖 Watch API 去维护缓存,没有任何 resync 机制。


笔者在阅读 Informer 代码时候,对这种做法十分不解。按照多数人思路,通过 resync 机制,重新 List 一遍 resource 下的所有 Object,可以更好的保证 Informer 缓存和 Kubernetes 中数据的一致性。


咨询过 Google 内部 Kubernetes 开发人员之后,得到的回复是:


> 在 Informer 设计之初,确实存在一个 relist 无法去执 resync 操作, 但后来被取消了。原因是现有的这种 List/Watch 机制,完全能够保证永远不会漏掉任何事件,因此完全没有必要再添加 relist 方法去 resync informer 的缓存。这种做法也说明了 Kubernetes 完全信任 etcd。


可监听事件并触发回调函数


Informer 通过 Kubernetes Watch API 监听某种 resource 下的所有事件。而且,Informer 可以添加自定义的回调函数,这个回调函数实例(即 ResourceEventHandler 实例)只需实现 OnAdd(obj interface{}) OnUpdate(oldObj, newObj interface{}) 和 OnDelete(obj interface{}) 三个方法,这三个方法分别对应 informer 监听到创建、更新和删除这三种事件类型。


在 Controller 的设计实现中,会经常用到 informer 的这个功能。 Controller 相关文章请见此文《如何用 client-go 拓展 Kubernetes 的 API》。


二级缓存


二级缓存属于 Informer 的底层缓存机制,这两级缓存分别是 DeltaFIFO 和 LocalStore。


这两级缓存的用途各不相同。DeltaFIFO 用来存储 Watch API 返回的各种事件 ,LocalStore 只会被 Lister 的 List/Get 方法访问 。


虽然 Informer 和 Kubernetes 之间没有 resync 机制,但 Informer 内部的这两级缓存之间存在 resync 机制。


以上是 Informer 设计中的一些关键点,没有介绍一些太细节的东西,尤其对于 Informer 两级缓存还未做深入介绍。下一章节将对 Informer 详细的工作流程做一个详细介绍。

Informer 详细解析

Informer 内部主要组件


Informer 中主要包含 Controller、Reflector、DeltaFIFO、LocalStore、Lister 和 Processor 六个组件,其中 Controller 并不是 Kubernetes Controller,这两个 Controller 并没有任何联系;Reflector 的主要作用是通过 Kubernetes Watch API 监听某种 resource 下的所有事件;DeltaFIFO 和 LocalStore 是 Informer 的两级缓存;Lister 主要是被调用 List/Get 方法;Processor 中记录了所有的回调函数实例(即 ResourceEventHandler 实例),并负责触发这些函数。


Informer 关键逻辑解析


我们以 Pod 为例,详细说明一下 Informer 的关键逻辑:


1.Informer 在初始化时,Reflector 会先 List API 获得所有的 Pod


2.Reflect 拿到全部 Pod 后,会将全部 Pod 放到 Store 中


3.如果有人调用 Lister 的 List/Get 方法获取 Pod, 那么 Lister 会直接从 Store 中拿数据



4.Informer 初始化完成之后,Reflector 开始 Watch Pod,监听 Pod 相关 的所有事件;如果此时 pod_1 被删除,那么 Reflector 会监听到这个事件


5.Reflector 将 pod_1 被删除 的这个事件发送到 DeltaFIFO


6.DeltaFIFO 首先会将这个事件存储在自己的数据结构中(实际上是一个 queue),然后会直接操作 Store 中的数据,删除 Store 中的 pod_1


7.DeltaFIFO 再 Pop 这个事件到 Controller 中


8.Controller 收到这个事件,会触发 Processor 的回调函数



9.LocalStore 会周期性地把所有的 Pod 信息重新放到 DeltaFIFO 中


Informer 总结

Informer 的内部原理比较复杂、不太容易上手,但 Informer 却是一个非常稳定可靠的 package,已被 Kubernetes 广泛使用。但是,目前关于 Informer 的文章不是很多,如果文章中有表述不正确的地方,希望各位读者悉心指正。


作者介绍:李昂,曾经就职于七牛,参与七牛大数据产品的开发工作,加入才云科技后,主要负责 Devops 的相关工作,才云科技云平台容器工程师。


本文转载自才云 Caicloud 公众号。


原文链接:https://mp.weixin.qq.com/s/3vlclIP-rSbWH4bplduexA


2020-03-04 20:521820

评论

发布
暂无评论
发现更多内容

虚拟化管理软件比较(Eucalyptus, OpenNebula, OpenStack, OpenQRM,XenServer, Oracle VM, CloudStack,ConVirt)

hanaper

“区块链+农业”推动产业“提档升级”

CECBC

以太坊的黄金时代:模块化的区块链范式的开端

CECBC

在线2-36任意进制转换工具

入门小站

工具

自我提升:高效能人士的 7 个习惯学习笔记(二)

程序员架构进阶

效率 自我管理 自我提升 10月月更

重置不良的编程陋习

devpoint

编码习惯 10月月更

使用 Ansible 部署 Elasticsearch 集群

Se7en

linux之iftop命令

入门小站

Linux

最长回文子串 -- 三种解答

秦怀杂货店

数据结构 算法 最长回文子串

机器人自主学习新进展,百度飞桨发布四足机器人控制强化学习新算法

百度大脑

人工智能 飞桨

用时三个月,阿里P8大佬总结出来的最深《Java性能优化全攻略》限时分享!

Java 架构 面试 程序人生 编程语言

Serverless 工程实践 | Serverless 应用优化与调试秘诀

阿里巴巴云原生

阿里云 Serverless 云原生

看山聊 Java:检查日期字符串是否合法

看山

Java 10月月更

私有分布式账本技术还是公共区块链?

CECBC

手把手带你玩转 JS | 引航计划|大前端

三掌柜

大前端 引航计划 引航 技术专题合集

阿里P8最全总结PDF:Tomcat+虚拟机+Spring全家桶+MyBatis源码等

Java 架构 面试 程序人生 编程语言

架构实战营模块九作业 - 毕业设计

王晓宇

架构实战营

看完阿里大牛的数据结构学习笔记,我直接手撕了500道Leetcode题

Java 程序员 架构 面试 算法

引航计划|大前端|优质合集手把手带你玩转移动开发

三掌柜

大前端 引航计划 引航

内网域渗透分析(实战总结)

网络安全学海

网络安全 信息安全 渗透测试 WEB安全 漏洞挖掘

偷瞄大佬书签栏,16个C++必备学习网站,建议收藏

奔着腾讯去

c++

如何区分封闭图形的内部和外部

Changing Lin

10月月更

设计微博系统中"微博评论"的高性能高可用计算架构

Rabbit

VNC服务安装配置与使用

耳东@Erdong

vnc 10月月更

代码检查规则:Java语言案例详解

百度开发者中心

Java 最佳实践 案例分享 代码检查规则

MyBatis 批量插入数据的 3 种方法!

王磊

Java mybatis springboot

接棒运动赛事!工厂里也有热血竞技?

白洞计划

还在郁郁寡欢?啃完666页Java面试高频宝典,十月保你定级腾讯T3-2

Java 架构 面试 程序人生 编程语言

都2021年了,还在算法上折跟头?这本《字节跳动面试必问算法秘籍》送给你!

Java 架构 面试 程序人生 编程语言

新一代容器平台ACK Anywhere,来了

阿里巴巴中间件

阿里云 云原生 中间件 ACK ACK Anywhere

认识流媒体协议,从 RTSP 协议解析开始!

声网

协议 RTSP

“高冷”的 Kubernetes Informer 一探究竟_文化 & 方法_才云科技_InfoQ精选文章