Table of Contents
1. 章节介绍
在介绍完Informer机制后,可以发现如果想自定义控制器非常简单,我们直接注册handler就行。但是绝大部分k8s原生控制器中,handler并没有直接处理。而是统一遵守一套:
Add , update, Del -> queue -> run -> runWorker -> syncHandler 处理的模式。
例如 namespaces控制器中:
// 1.先是定义了一个限速队列 queue: workqueue.NewNamedRateLimitingQueue(nsControllerRateLimiter(), "namespace"), // 2.然后add, update都是入队列 // configure the namespace informer event handlers namespaceInformer.Informer().AddEventHandlerWithResyncPeriod( cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { namespace := obj.(*v1.Namespace) namespaceController.enqueueNamespace(namespace) }, UpdateFunc: func(oldObj, newObj interface{}) { namespace := newObj.(*v1.Namespace) namespaceController.enqueueNamespace(namespace) }, }, resyncPeriod, ) // 3.然后controller.run,启动多个协程 // Run starts observing the system with the specified number of workers. func (nm *NamespaceController) Run(workers int, stopCh <-chan struct{}) { for i := 0; i < workers; i++ { go wait.Until(nm.worker, time.Second, stopCh) } <-stopCh } // 4. worker处理一个个数据 func (nm *NamespaceController) worker() { // 得到对象 key, quit := nm.queue.Get() // 处理完对象 defer nm.queue.Done(key) err := nm.syncNamespaceFromKey(key.(string)) if err == nil { // no error, forget this entry and return nm.queue.Forget(key) return false } }
可以看出来这一套的一个好处:
(1)利用了Indexer本地缓存机制,queue里面只包括 key就行。数据indexer都有
(2)workqueue除了一个缓冲机制外,还有着错误重试的机制
因此这一节分析一下,client-go提供了哪些workqueue
2. workerqueue介绍
client-go 的 util/workqueue
包里主要有三个队列,分别是普通队列,延时队列,限速队列,后一个队列以前一个队列的实现为基础,层层添加新功能,我们按照 Queue、D