写点什么

“高冷”的 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:521669

评论

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

GitHub标星3-5K+【Android校招面试指南,flutter中文本框的长度

android 程序员 移动开发

恒源云(GPUSHARE)_云GPU服务器如何使用Tmux?

恒源云

深度学习

Groovy脚本基础全攻略,重磅

android 程序员 移动开发

HashMap 源码解析二、put 相关函数,android原生开发教程

android 程序员 移动开发

Hook 技术初探,【2021Android最新学习路线

android 程序员 移动开发

Fragment极度懒加载-+-Layout子线程预加载,奇妙的APP启动速度优化思路

android 程序员 移动开发

GDP大跳水,“溢价阶层,kotlinandroid开发教程

android 程序员 移动开发

如何实现高效运维?来谈谈性能优化那些事(含直播回顾 Q&A)

墨天轮

oracle 性能优化

Git各指令的本质,真是通俗易懂啊,h5移动端开发进行定位

android 程序员 移动开发

Gson 解析 Json 容错才是关键,举几个常用的实例!,android开发视频百度网盘

android 程序员 移动开发

GitHub标星3,Android面试

android 程序员 移动开发

Google禁止Android-11-自定义-Toast-了?,android开发实战数据

android 程序员 移动开发

HTTPS详解,谈谈我认为的高级Android开发到底应该是怎样的

android 程序员 移动开发

FrameWork内核解析之PackageMS启动(一)下篇,android开发电子书

android 程序员 移动开发

Kubernetes + 焱融 SaaS 数据服务平台,个性化需求支持就没输过

焱融科技

云计算 分布式 高性能 公有云 文件存储

Framework学习(十一)WindowManager体系,学习指南

android 程序员 移动开发

Fresco实践总结,阿里P7大牛亲自教你

android 程序员 移动开发

🍃【Spring专题】「实战系列」重新回顾一下Spring框架的异步执行调用的原理和实战

洛神灬殇

spring 异步编程 异步调度 11月日更

IOC架构设计之控制反转和依赖注入(一),2021大厂Android面试经验

android 程序员 移动开发

Framework学习(十)Content Provider启动过程,android快速开发

android 程序员 移动开发

Gradle多维度使用,h5开发移动端

android 程序员 移动开发

GitHub标星9K的Google官方MVP+Rxjava项目详解,靠这份资料我从6K变成了40K

android 程序员 移动开发

Handler源码分析之二 异步消息的处理,2021金三银四面试季

android 程序员 移动开发

Gbox开源:比RN和WebView更轻的高性能动态化业务容器,解决首页动态化的痛点

android 程序员 移动开发

移动端1px解决方案

CRMEB

GitHub 上优质项目整理,推荐一个GitHub项目

android 程序员 移动开发

GitHub标星3(1),腾讯Android开发面试记录

android 程序员 移动开发

Glide源码学习五:回调与监听,Android快速转战Kotlin教程

android 程序员 移动开发

IOC架构设计之Dagger2架构设计(三),进阶加薪全靠它

android 程序员 移动开发

Framework学习(七)AMS家族,kotlin开发思维

android 程序员 移动开发

Framework掌握不熟?字节跳动大牛带你系统化学习,小白以及计算机类学生的福音

android 程序员 移动开发

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