client-go 之informer理解

client-go之Informer体系

文章通过类图依赖关系图梳理了client-go tools包中的informer体系结构,并总结出了客户端调用时的注意事项以及原因。

0、Infromer类图体系概览图:

在这里插入图片描述

一、SharedInformer接口主要功能:

  • 给其客户端提供一个给定资源对象集合的最终一致性访问接口

1、内部维护了一个本地缓存,通过GetStore()暴露,该接口的实现sharedIndexInformer同时通过GetIndexer()暴露,接口SharedIndexInformer包含了SharedInformer;

2、本地缓存刚开始是空的,在调用Run()过程中被填充或更新,Run()保证本地缓存和ApiServer的最终一致性

3、存放在Store中的对象格式为:namespace/name,客户端可以使用MetaNamespaceKeyFunc(obj)方法获取对象的Key值,使用SplitMetaNamespaceKey(key)获得key的组成部分

4、添加对象事件监听器AddEventHandler、AddEventHandlerWithResyncPeriod

二、SharedIndexInformer接口实现sharedIndexInformer三大组件

1、Indexer:索引化的本地缓存

2、Controller控制器:使用ListWatcher批量List资源对象以及Watch资源对象通知事件并Push到DeltaFIFO中

3、sharedProcessor:该组件用于分发资源对象通知事件到informer的所有客户端(ResourceEventHandler)

三、SharedIndexInformer接口实现sharedIndexInformer构造方法

NewSharedInformer(lw ListerWatcher, exampleObject runtime.Object, defaultEventHandlerResyncPeriod time.Duration) SharedInformer 
调用 
NewSharedIndexInformer( ListerWatcher, runtime.Object, defaultEventHandlerResyncPeriod time.Duration, Indexers) SharedIndexInformer 

四、核心SharedInformer调用关系梳理

1、上游调用链: client-go/informers

// 1、客户端首先创建InformerFactory工厂
func NewSharedInformerFactoryWithOptions(client kubernetes.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory

// 2、工厂包含各个API对象的Informer,以创建Event informer举例
func (f *sharedInformerFactory) Events() events.Interface {
	return events.New(f, f.namespace, f.tweakListOptions)
}

// 3、得到指定API对象的各个版本的Informer的总接口
func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface {
	return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
}

// 4、客户端指定资源组版本获得该资源组的Informer的接口
func (g *group) V1() v1.Interface {
	return v1.New(g.factory, g.namespace, g.tweakListOptions)
}

// 5、客户端调用步骤4中资源组接口获取该资源组下指定资源对象的Informer
	// factory.Events().V1().Events()
func (v *version) Events() EventInformer {
	return &eventInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
	// factory.Events().V1().Events().Informer()
func (f *eventInformer) Informer() cache.SharedIndexInformer {
	// 回调工厂方法的InformerFor,给指定API对象创建SharedIndexInformer
	return f.factory.InformerFor(&corev1.Pod{}, f.defaultInformer)
}

func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer {
	// 注册该API对象的Informer到工厂中
	informerType := reflect.TypeOf(obj)
	informer, exists := f.informers[informerType]
	f.informers[informerType] = informer
	return informer
}

// 6、步骤5中回调工厂的InformerFor方法时传入defaultInformer方法进行回调
// 调用1
func (f *eventInformer) defaultInformer(client kubernetes.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
	return NewFilteredEventInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
// 使用到了 type Indexers map[string]IndexFunc 并赋值为 cache.NamespaceIndex=cache.MetaNamespaceIndexFunc
// 调用2
func NewFilteredEventInformer(kubernetes.Interface, namespace string, time.Duration, cache.Indexers, TweakListOptionsFunc) cache.SharedIndexInformer

// 7、客户端启动工厂方法:遍历所有注册的informer,开启协程进行数据同步
func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) {
	f.lock.Lock()
	defer f.lock.Unlock()

	for informerType, informer := range f.informers {
		if !f.startedInformers[informerType] {
			go informer.Run(stopCh)
			f.startedInformers[informerType] = true
		}
	}
}

2、下游调用链: 主要使用到了底层cache包中的功能

调用
NewIndexer(keyFunc KeyFunc, indexers Indexers) Indexer
调用
NewThreadSafeStore(indexers Indexers, indices Indices) ThreadSafeStore

五、总结

1、客户端使用Informer方式:

根据上游调用链的分析,我们使用Informer工厂,需要保证工厂的InformerFor方法被回调,才能保证指定资源对象的Informer被创建,有以下两种常规方式启动工厂:

方式1:

	// 步骤1,创建工厂
	factory := informers.NewSharedInformerFactoryWithOptions(clientSet, 10*time.Second, informers.WithTweakListOptions(func(options *metaV1.ListOptions) {
		options.LabelSelector = labels.Everything().String()
	}))
	
	// 步骤2,使用工厂创建指定API对象的Informer,必须调用到Informer()方法,该方法会回调到工厂方法的InformerFor
	factory.Apps().V1().Deployments().Informer()
	
	// 步骤3,使用factory启动informer,该方法是异步,里面会遍历所有的Informer,并调用informer的Run方法,Run方法核心功能就是开启资源对象的本地缓存
	factory.Start(stopChan)
	
	// 步骤4,等待该工厂里的所有启动过的informer完成数据缓存到本地
	factory.WaitForCacheSync(stopChan)

方式2:

// 步骤1: 创建工厂
	f := informers.NewSharedInformerFactory(clientSet, 0)
// 步骤2: 注册informer	
	deploymentSharedIndexInformer := f.Apps().V1().Deployments().Informer()
// 步骤3: 启动informer
	go deploymentSharedIndexInformer.Run(stopInformerChan)
// 步骤4: 等待informer完成本地数据缓存
	cache.WaitForNamedCacheSync("deploymentInformerController", stopInformerChan, deploymentSharedIndexInformer.HasSynced)

2、设计层面

依赖接口而不依赖实现:面向接口编程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值