list-watch机制
list-watch有两部分组成,分别是list和watch。list非常好理解,就是调用资源的list API罗列资源,基于HTTP短链接实现;watch则是调用资源的watch API监听资源变更事件,基于HTTP 长链接实现
Watch API和apiserver保持一个长链接,接收资源的状态变更事件并做相应处理。如果仅调用watch API,若某个时间点连接中断,就有可能导致消息丢失,所以需要通过list API和resourceversion(根据版本)解决消息丢失的问题。
workqueue机制
workqueue 提供的一个保障就是,如果是同一个object,比如同一个 pod,被多次加到 workqueue 里,在 dequeue 时,它只会出现一次。防止会有同一个 object 被多个 worker 同时处理。
普通队列workqueue:
防止 hot loop:它保证了一个 item 被 reenqueued 后,不会马上被处理
限速队列RateLimitingQueue,它相比普通的 workqueue 多了以下的功能:
-
限流:可以限制一个 item 被 reenqueued 的次数。(维护了一个
delaying_queue,并用heap将等待时间最小的item加入到workqueue去处理) -
防止 hot loop:它保证了一个 item 被 reenqueued 后,不会马上被处理,(
processing存在正在处理的item)
延时队列RateLimiter:
-
根据元素错误次数逐渐累加等待时间,然后加入到延时队列
informer核心
1.ListWatch监听apiserver的资源变化,Lister一般用于首次获取某资源(如Pod)的全量信息,而Watcher用于持续获取该资源的增量变化信息
2.reflector使用listerWatcher获取资源,并将其保存在队列DeltaFIFO
3.DeltaFIFO是一个生产者-消费者队列,生产者为Reflector,消费者为Pop()函数,消费的数据一方面存储到Indexer中,另一方面可以通过informer的handler进行处理
4.Local Store是本地缓存,Indexer是含有索引能力的本地缓存,本质是能根据id、名字等key获取对象的map
5.workqueue用于保存DeltaFIFO中增量变化的对象,由worker将当前状态的对象处理成期望状态的对象。
*注:SharedInformer.Run启动了两个chan,s.c.Run为controller的入口,s.c.Run函数中会Pop DeltaFIFO中的元素,并根据DeltaFIFO的元素的类型(Sync/Added/Updated/Deleted)进两类处理,一类会使用indexer.Update,indexer,Add,indexer.Delete对保存的在Store中的数据进行处理;另一类会根据DeltaFIFO的元素的类型将其封装为sharedInformer内部类型updateNotification,addNotification,deleteNotification,传递给s.processor.Listeners.addCh,后续给注册的pl.handler处理。
informer工作流程
1.reflector通过ListWatch的list获取资源的全量信息,包括监听对象最新的resourceVersion。将获取的资源信息存入indexer
2.reflector通过ListWatch的watch监听对象resourceVersion之后的所有变化,并将变化存入DeltaFIFO。
3.Informer的controller不断地pop DeltaFIFO的变化,根据变化更新indexer对应的数据,根据变化调用回调函数handler去处理,即将变化的对象放入workqueue
4.controller不断地从workqueue取出对象,通过sync方法将对象从当前状态处理成期望状态。
使用informer创建controller
1.创建控制器,informer,lister,workqueue
2.启动控制器:启动informer初始化indexer,本地缓存同步完数据后启动work监听workqueue
3.当收到变更事件后,worker调用sync方法将对象从当前状态处理成期望状态。