侧边栏壁纸
博主头像
问道

问道的小花园,总能给你带来惊喜

  • 累计撰写 68 篇文章
  • 累计创建 35 个标签
  • 累计收到 4 条评论

kubernetes二次开发系列(2):informer机制

问道
2023-02-01 / 0 评论 / 0 点赞 / 705 阅读 / 3,628 字 / 正在检测是否收录...
温馨提示:
本文最后更新于 2023-02-01,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

kubernetes使用informer机制来保证消息的实时性、可靠性、顺序性等,Kubernetes的其他组件都是通过client-go的Informer机制与Kubernetes API Server进行通信的。

image.png

主要流程如下:

  1. Reflector通过List获取集群的所有对象,并放到本地store缓存起来
  2. 然后Reflector通过Watch时刻监听集群的事件
  3. 如果获得集群事件就把这个事件发送到Delta FIFO
  4. controller从Delta FIFO中依次pop出事件并交给informer的回调函数HandleDeltas
  5. indexer将事件存储在本地的缓存中
  6. distribute负责将资源对象分发到具体的处理函数
  7. Rsync会把本地的缓存的资源对象同步到DeltaFIFO

比如我们要删除一个叫demo的pod,那么其主要流程如下:

  1. 首先是Reflector通过Watch收到要删除名叫demo的pod事件,然后将这个事件发送给Delta FIFO
  2. 从DeltaFIFO中pop这个事件并交给indexer进行本地处理,首先会存储这个事件,其次会从本地store中删除这个pod
  3. 回调函数会调用distribute去处理不同的对象

从上面可以看到其主要组件有以下几个。

(1)、Reflector

Reflector负责List&Watch指定的kubernetes资源,当Watch到监控的资源发生变化时,就会触发相应的变更事件。比如Added(资源添加)事件、Updated(资源更新)事件、Deleted(资源删除)事件,并将其资源对象存放到本地缓存DeltaFIFO中。

(2)、DeltaFIFO

DeltaFIFO就是一个资源对象存储的一个队列。

(3)、indexer

Indexer是client-go用来存储资源对象并自带索引功能的本地存储,Reflector从DeltaFIFO中将消费出来的资源对象存储至Indexer。Indexer与Etcd集群中的数据完全保持一致。client-go可以很方便地从本地存储中读取相应的资源对象数据,而无须每次从远程Etcd集群中读取,以减轻Kubernetes API Server和Etcd集群的压力。

(4)、informer

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

informer模式

APIServer是集群负载提升后最容易遇到瓶颈的地方,多集群改造是我们最后的手段。但是我们必须提前做一些事情来避免一些集群性能问题。是的,在处理 client-go 时,请遵循其informer模式。

informer的实现很复杂,但它的作用很明显:保持对集群资源的持续访问,通过缓存和事件缓解 APIServer 压力。

Kubernetes Informer 模式可以分为两部分:一是涉及控制器(operator)开发,二是在 client-go 等客户端程序中实现。

Informer

http://k8s.io)\client-go\informers\core\v1\pod.go):每一个Kubernetes资源上都实现了Informer机制。每一个Informer上都会实现Informer和Lister方法,例如PodInformer,代码示例如下(staging\src[k8s.io](

定义不同资源的Informer,允许监控不同资源的资源事件。比如监控Pod的资源事件,当Pod有新增、删除、修改等事件的时候,client-go中的Watch能及时收到资源对象的变更信息。

Shared Informer

同一个资源的informer可能会被实例化多次,比如一个Pod可能会被deployment的Informer实例化,也可能会被replicaset实例化,如果一个informer一个Reflector,就会导致有许许多多的Reflector做相同的事情,会导致api server负载过重。所以client-go提供了一种shared informer机制,就是同一资源的Informer共享一个Reflector。

http://k8s.io)\client-go\informers\factory.go):其中Informers字段的定义如下(staging\src[k8s.io](

可以看到informers字段是一个map类型,其中Key是资源类型,value是SharedIndexInformer。

http://k8s.io)\client-go\informers\factory.go):而InformerFor方法添加了不同资源的infomer,如下(staging\src[k8s.io](

  • 首先获取资源类型,如果存在则直接返回
  • 获取rsync的时间,如果没有自定义则使用默认的时间
  • 然后创建一个新的informer,更新Informers字段

最后通过Shared Informer的Start方法使f.informers中的每个informer通过goroutine持久运行。

Reflector

Reflector主要通过List&Watch来获取监控集群资源,其主要有两部分:List和Watch。其中List就是列出集群的资源,基于HTTP短链接实现。Watch是监听资源事件,是基于HTTP长连接实现。

Reflector的结构体定义如下,代码路径staging\src**k8s.io\client-go\tools\cache\reflector.go**:

可以看到Reflector定义了一个listerWatcher,而ListerWatcher是一个接口,定义如下,代码路径:staging\src**k8s.io\client-go\tools\cache\listwatch.go**:

而Lister和Watcher也是一个接口,其分别需要实现List和Watch方法,定义如下:

而ListWatch实现了这两个方法,定义如下:

而ListFunc和WatchFunc是定义的两个类型,如下:

WorkQueue

WorkQueue称为工作队列,Kubernetes的WorkQueue队列与普通FIFO(先进先出,First-In,First-Out)队列相比,实现略显复杂,它的主要功能在于标记和去重,并支持如下特性。

● 有序:按照添加顺序处理元素(item)。

● 去重:相同元素在同一时间不会被重复处理,例如一个元素在处理之前被添加了多次,它只会被处理一次。

● 并发性:多生产者和多消费者。

● 标记机制:支持标记功能,标记一个元素是否被处理,也允许元素在处理时重新排队。

● 通知机制:ShutDown方法通过信号量通知队列不再接收新的元素,并通知metric goroutine退出。

● 延迟:支持延迟队列,延迟一段时间后再将元素存入队列。

● 限速:支持限速队列,元素存入队列时进行速率限制。限制一个元素被重新排队(Reenqueued)的次数。

● Metric:支持metric监控指标,可用于Prometheus监控。

WorkQueue支持3种队列,并提供了3种接口,不同队列实现可应对不同的使用场景,分别介绍如下。

● Interface:FIFO队列接口,先进先出队列,并支持去重机制。

● DelayingInterface:延迟队列接口,基于Interface接口封装,延迟一段时间后再将元素存入队列。

● RateLimitingInterface:限速队列接口,基于DelayingInterface接口封装,支持元素存入队列时进行速率限制。

Interface
http://k8s.io)\client-go\util\workqueue\queue.go)Interface是FIFO队列,是最基础的队列,限速和延迟队列都是基于它来实现的。其提供一下方法(源码:staging\src[k8s.io](

RateLimitingInterface

RateLimitingInterface是限速队列,基于延迟队列和FIFO队列接口封装,在原有功能上增加了AddRateLimited、Forget、NumRequeues方法。限速队列的重点不在于RateLimitingInterface接口,而在于它提供的4种限速算法接口(RateLimiter)。其原理是,限速队列利用延迟队列的特性,延迟某个元素的插入时间,达到限速目的。

0

评论区