K8s 系列(四) - 浅谈 Informer

1. 概述

进入 K8s 的世界,会发现有很多的 Controller,它们都是为了完成某类资源(如 pod 是通过 DeploymentController, ReplicaSetController 进行管理)的调谐,目标是保持用户期望的状态。

K8s 中有几十种类型的资源,如何能让 K8s 内部以及外部用户方便、高效的获取某类资源的变化,就是本文 Informer 要实现的。本文将从 Reflector(反射器)、DeletaFIFO(增量队列)、Indexer(索引器)、Controller(控制器)、SharedInformer(共享资源通知器)、processorListener(事件监听处理器)、workqueue(事件处理工作队列) 等方面进行解析。

本文及后续相关文章都基于 K8s v1.22

在这里插入图片描述

2. 从 Reflector 说起

Reflector 的主要职责是从 apiserver 拉取并持续监听(ListAndWatch) 相关资源类型的增删改(Add/Update/Delete)事件,存储在由 DeltaFIFO 实现的本地缓存(local Store) 中。

首先看一下 Reflector 结构体定义:

// staging/src/k8s.io/client-go/tools/cache/reflector.go
type Reflector struct {
   
	// 通过 file:line 唯一标识的 name
	name string

	// 下面三个为了确认类型
	expectedTypeName string
	expectedType     reflect.Type
	expectedGVK      *schema.GroupVersionKind

	// 存储 interface: 具体由 DeltaFIFO 实现存储
	store Store
	// 用来从 apiserver 拉取全量和增量资源
	listerWatcher ListerWatcher

	// 下面两个用来做失败重试
	backoffManager         wait.BackoffManager
	initConnBackoffManager wait.BackoffManager

	// informer 使用者重新同步的周期
	resyncPeriod time.Duration
	// 判断是否满足可以重新同步的条件
	ShouldResync func() bool
	
	clock clock.Clock
	
	// 是否要进行分页 List
	paginatedResult bool
	
	// 最后同步的资源版本号,以此为依据,watch 只会监听大于此值的资源
	lastSyncResourceVersion string
	// 最后同步的资源版本号是否可用
	isLastSyncResourceVersionUnavailable bool
	// 加把锁控制版本号
	lastSyncResourceVersionMutex sync.RWMutex
	
	// 每页大小
	WatchListPageSize int64
	// watch 失败回调 handler
	watchErrorHandler WatchErrorHandler
}

从结构体定义可以看到,通过指定目标资源类型进行 ListAndWatch,并可进行分页相关设置。

第一次拉取全量资源(目标资源类型) 后通过 syncWith 函数全量替换(Replace) 到 DeltaFIFO queue/items 中,之后通过持续监听 Watch(目标资源类型) 增量事件,并去重更新到 DeltaFIFO queue/items 中,等待被消费。

watch 目标类型通过 Go reflect 反射实现如下:

// staging/src/k8s.io/client-go/tools/cache/reflector.go
// watchHandler watches w and keeps *resourceVersion up to date.
func (r *Reflector) watchHandler(start time.Time, w watch.Interface, resourceVersion *string, errc chan error, stopCh <-chan struct{
   }) error {
   

	...
	if r.expectedType != nil {
   
		if e, a := r.expectedType, reflect.TypeOf(event.Object); e != a {
   
			utilruntime.HandleError(fmt.Errorf("%s: expected type %v, but watch event object had type %v", r.name, e, a))
			continue
		}
	}
	if r.expectedGVK != nil {
   
		if e, a := *r.expectedGVK, event.Object.GetObjectKind().GroupVersionKind(); e != a {
   
			utilruntime.HandleError(fmt.Errorf("%s: expected gvk %v, but watch event object had gvk %v", r.name, e, a))
			continue
		}
	}
	.
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值