@@ -18,7 +18,7 @@ type Queue interface {
1818
1919 AddIfNotPresent (interface {}) error 
2020
21-  //  当队列中第一批元素都  Pop 后,返回 true。
21+  //  当队列中第一批对象都  Pop 后,返回 true。
2222 HasSynced () bool 
2323 Close ()
2424}
@@ -56,10 +56,10 @@ type FIFO struct {
5656 //  对象弹出(Pop)顺序队列,队列中各对象 Key 是**唯一**的
5757 queue []string 
5858
59-  //  首先调用 Delete/Add/Update 或 Replace() 添加的第一批元素都  Pop 后为 true
59+  //  首先调用 Delete/Add/Update 或 Replace() 添加的第一批对象都  Pop 后为 true
6060 populated bool 
6161
62-  //  Replace() 添加的第一批元素的数目 
62+  //  Replace() 添加的第一批对象的数目 
6363 initialPopulationCount int 
6464
6565 //  添加或减少 obj 用到的,生成 obj 标识 key 的函数
@@ -89,7 +89,7 @@ func NewFIFO(keyFunc KeyFunc) *FIFO {
8989
9090## ` Add() `  方法 
9191
92- 只有缓存中没有该对象时,才将它加入弹出(Pop )队列,这样可以保证该对象在未被 Pop 前只会由一个  worker 处理:
92+ 只有缓存中没有该对象时,才将它加入弹出(f.queue )队列,这样可以保证该对象在未被弹出前只会被一个  worker 处理:
9393
9494```  go 
9595//  来源于 k8s.io/client-go/tools/cache/fifo.go
@@ -281,10 +281,11 @@ func (f *FIFO) Resync() error {
2812814 .  DeltaFIFO 的 Pop/Get() 方法,返回的不是对象最新值,而是 Deltas 类型的对象事件列表。
282282
283283DeltaFIFO 适用的情况:
284+ 2842851 .  你希望最多一个 worker 处理某个对象的事件(与 FIFO 类似,对象在 Queue 中是唯一的);
2852862 .  当处理该对象时,可以获得自上次以来该对象的所有事件,如 Add/Updat/Delete(FIFO 只缓存和弹出该对象的最新值);
2862873 .  你可以处理删除对象的事件(FIFO 不支持该功能,它不会弹出被删除的对象);
287- 4 .  你想周期处理所有的对象(调用  Resync 方法,将 knownObjects 中的对象同步到 DeltaFIFO 中);
288+ 4 .  你想周期处理所有的对象( Reflector 周期调用  Resync()  方法,将 knownObjects 中的对象同步到 DeltaFIFO 中);
288289
289290DeltaFIFO 是一个生产者-消费者队列,生产者是 [ Reflector] ( 3.reflector.md ) ,消费者主要是 [ controller/sharedInformer/sharedIndexInformer] ( 4.controller-informer.md ) 。
290291
@@ -294,136 +295,106 @@ DeltaFIFO 是一个生产者-消费者队列,生产者是 [Reflector](3.reflec
294295//  来源于 k8s.io/client-go/tools/cache/delta_fifo.go
295296func  NewDeltaFIFO (keyFunc  KeyFunc , knownObjects  KeyListerGetter ) *DeltaFIFO  {
296297 f  :=  &DeltaFIFO{
298+  //  对象事件缓存,对象 Key 为 map key,map value 为事件列表类型 Deltas;
297299 items: map [string ]Deltas{},
300+  //  对象弹出队列,缓存的是对象 Key,后续 Pop 方法按续弹出;
298301 queue: []string {},
299302 keyFunc: keyFunc,
303+  //  对象缓存,DeltaFIFO 的消费者 controller 根据从 DeltaFIFO 弹出的 Deltas 对象进行更新;
300304 knownObjects: knownObjects,
301305 }
302306 f.cond .L  = &f.lock 
303307 return  f
304308}
305309``` 
306310
307- 传入的 ` knownObjects `  是实现了 ` KeyListerGetter `  接口的 ` Store `  或 ` Index ` (一般是 [ cache] ( 1.store-indexer-cache.md ) ),它缓存 DeltaFIFO 已知的所有对象。
308- 309- DelaFIFO 只调用 ` knownObjects `  缓存的两个** 只读** 方法,** 不会对他进行更新** :
310- +  ` f.knownObjects.GetByKey(id) ` :按照 id 获取对象;
311- +  ` f.knownObjects.ListKeys() ` :列出所有对象的 Key;
312- 313- 各种 ` Informer `  的创建函数,如 ` NewInformer、NewIndexInformer、NewSharedInformer、NewSharedIndexInformer ` ,会依次创建 ` knownObjects `  缓存(` struct cache `  类型)、` FIFO/DeltaFIO `  和 [ ` controller ` ] ( 4.controller-informer.md ) 。
311+ 传入的 ` knownObjects `  缓存了 DeltaFIFO 已知的所有对象,DelaFIFO ** 不对它进行更新** ,只是用它来查找对象。
314312
315- ` controller `  使用  ` DeltaFIFO `  作为队列,再将它传给创建的  [ Reflector ] ( 3.reflector.md ) , ** Reflecter 是 FIFO/DeltaFIO 的生产者 ** 。 
313+ ###  DeltaFIFO 的生产者和消费者  
316314
317- ** ` controller `  是 ` FIFO/DeltaFIFO `  的消费者,它同时负责更新 ` knownObjects `  缓存** :
318- 1 .  从 FIFO 弹出对象;
319- 2 .  更新 knownObjects 缓存;
320- 3 .  再调用注册的 OnUpdate/OnAdd/OnDelete 回调函数;
315+ 后续文章会介绍,创建各种 ` Informer ` (如 ` Informer、IndexInformer、SharedInformer、SharedIndexInformer ` )时,初始化函数会依次创建 ` knownObjects `  缓存、` DeltaFIO `  和 [ ` controller ` ] ( 4.controller-informer.md ) 。` controller `  再将 ` DeltaFIFO `  传给 [ Reflector] ( 3.reflector.md ) ,** Reflector 的 ` ListAndWatch() `  方法是 DeltaFIFO 的生产者** :
321316
322- 所以,controller 用从 DetalFIFO 弹出的 Deltas 更新(取决于 Delta 中记录的事件类型) ` knownObjects `  缓存,缓存的更新时间** 晚于**  FIFO。
317+ 1 .  List etcd 中(通过 kube-apiserver,下同)特定类型的所有对象,然后调用 DeltaFIFO 的 ` Replace() `  方法,将他们同步到 DeltaFIFO;
318+ 2 .  根据配置的 Resync 时间,** 周期调用**  DeltaFIFO 的 ` Resync() `  方法(见后文),将 knownObjects 中的对象更新到 DeltaFIFO 中;
319+ 3 .  阻塞 Watch etcd,根据事件的类型分别调用 DeltaFIFO 的 Add/Update/Delete 方法,将对象更新到 DeltaFIFO;
323320
324- 各种 ` Informer ` 、` controller `  使用 DeltaFIFO 的细节可以参考 [ Reflector] ( 3.reflector.md )  和 [ ` controller ` ] ( 4.controller-informer.md )  文档。
325- 326- ## Add() 和 Update() 方法  
321+ Watch etcd 会** 周期性的** 超时(因为设置了 timeout),当 ` ListAndWatch() `  出错返回时,Reflector 会等待一段时间再执行它,从而周期的将 ` etcd `  中的特定类型对象** 的全部对象** 同步到 ` DeltaFIFO ` 。
327322
328-  ``` go 
329-  // 来源于 k8s.io/client-go/tools/cache/delta_fifo.go 
330-  func (f *DeltaFIFO) Add(obj interface{}) error { 
331-   f.lock.Lock() 
332-   defer f.lock.Unlock() 
333-   f.populated = true 
334-   return f.queueActionLocked(Added, obj) 
335-  } 
336-  ``` 
323+ ** ` controller `  是 ` DeltaFIFO `  的消费者,它用 DeltaFIFO 弹出的对象更新 ` knownObjects `  缓存,然后调用注册的 OnUpdate/OnAdd/OnDelete 回调函数** 。详情参考 [ Reflector] ( 3.reflector.md )  和 [ controller 和 Informer] ( 4.controller-informer.md )  文档。
337324
338- ` Update() `  方法和 ` Add() `  方法类似,它最终调用 ` f.queueActionLocked(Updated, obj) `  方法。
339- 340- ## queueActionLocked() 方法  
341- 342- queueActionLocked(actionType DeltaType, obj interface{}) ->
343- 344- 1 .  如果事件类型为 Sync,而且 obj 对应的事件列表中最后一个事件为 Delete,则直接返回。
345- 2 .  合并 obj 连续重复的 Delete 事件为一个;
346- 3 .  如果 f.items[ id]  中没有该元素,则将它的 id append 到 f.queue; <-- 唯一更新 f.queue 的时机。
347- 4 .  将 obj 合并后的事件保存到 f.items[ id]  <-- 将 obj 当前事件与历史事件合并;
348- 349- 什么时候 ` f.items[id] `  不存在呢?
350- 351- 1 .  DeltaFIFO 刚创建,元素第一次产生 Add/Update/Delete/Sync 事件;
352- 2 .  后续调用 f.Pop() 方法,弹出 id 对应的事件列表;
353- 354- ## Delete() 方法  
325+ ### 记录对象事件的 Delta、Deltas 和 DeletedFinalStateUnknown 类型  
355326
356- Delete() 方法可能** 直接返回** ,也可能调用方法 ` f.queueActionLocked(Deleted, obj) `  为对象生成 ` Deleted `  事件。取决于 ` f.knownObjects.GetByKey(id) `  和 ` f.items[id] `  是否均均找不到对象。
357- 358- 注意:Delete() 方法** 不将对象从事件缓存 f.items 和弹出队列 f.queue 删除** (FIFO 的 Deleta() 方法会将对象从缓存中删除),只是可能生成 Deleted 事件。DeltaFIFO 的消费者 ` controller `  根据弹出的事件更新 f.knownObjects 缓存。
327+ DeltaFIFO 使用 Delta 类型记录对象的事件类型和发生** 事件后** 的对象值:
359328
360- ## Get/GetByKey/List/ListKeys() 方法  
329+ ```  go 
330+ type  Delta  struct  {
331+  //  DeltaType 可能是:Added、Deleted、Updated、Sync
332+ 	Type  DeltaType 
333+ 	Object  interface {}
334+ }
335+ ``` 
361336
362- 都是从内部缓存 f.items 中(非外部缓存 f. knownObjects)返回对象的 Deltas 或 Key 列表; 
337+ 有一种特殊情况:当 Reflecter 重复执行  ` ListAndWatch() `  方法时,List etcd 获取的对象集合 set1 可能与  knownObjects 缓存中的对象集合 set2  ** 不一致 ** ,调用的 Replace() 方法会发现这种情况,将位于 set1 但不在 set2 中的对象生成  ` DeletedFinalStateUnknown `  类型事件: 
363338
364- ## Replace() 方法  
339+ ```  go 
340+ type  DeletedFinalStateUnknown  struct  {
341+  //  对象的 Key
342+  Key  string 
343+  //  knownObjects 缓存中的对象值
344+ 	Obj  interface {}
345+ }
346+ ``` 
365347
366- Replace(list  [ ] interface{}, resourceVersion string) 
348+ 之所以不用 Type 为 Deleted 的 Delta 来表示,是因为:etcd 中没有该对象,Reflector  ** 不知道 ** 这个对象的当前值,所以只能用一个有别与 Deleted Delta 类型的特殊类型来表示这种情况。 
367349
368- 1 .  遍历 list 中的元素,为每个元素生成 Sync 事件,f.queueActionLocked(Sync, item)
369- 2 .  遍历 f.knownObjects.ListKeys() 中的元素,对于不在传入的 list 中的元素,生成 Delete 事件,添加的元素类型为 DeletedFinalStateUnknown(非 Delta 类型):
350+ ** 有且只有**  ` Replace() `  方法才会产生 ` DeletedFinalStateUnknown `  类型事件。
370351
371-  f.queueActionLocked(Deleted, DeletedFinalStateUnknown{k, deletedObj}) 
352+ ##  Add() 和 Update() 方法 
372353
373- 3 .  如果 f.Replace() 方法是在创建 DeltaFIFO 后第一次调用的方法(Add/Update/Delete 之前,此时 f.populated 为 false),则设置:
374-  设置 f.populated 为 true;
354+ ```  go 
355+ //  来源于 k8s.io/client-go/tools/cache/delta_fifo.go
356+ func  (f  *DeltaFIFO ) Add  (obj  interface {}) error  {
357+  f.lock .Lock ()
358+  defer  f.lock .Unlock ()
359+  f.populated  = true 
360+  //  Added 类型事件;
361+  return  f.queueActionLocked (Added, obj)
362+ }
363+ ``` 
375364
376-  f.initialPopulationCount = len(list) + queuedDeletions,其中 queuedDeletions 为生成 DeletedFinalStateUnknown 的对象数目 ;
365+ ` Update() `  方法和  ` Add() `  方法类似,差别在于产生的是  ` Updated `  Delta 类型事件 ;
377366
378- ## Delta 和 DeletedFinalStateUnknown 事件  
367+ ## queueActionLocked() 方法  
379368
380- 前面介绍过, ** Reflecter 是 FIFO/DeltaFIO 的生产者 ** , ** ` controller `  是  ` FIFO/DeltaFIFO `  的消费者,它同时负责更新  ` knownObjects `  缓存 ** :
369+ 该方法将对象的事件存入事件队列 f.items,如果事件队列中没有该对象则还将对象(Key)加入弹出队列(f.queue),另外它还做如下操作 :
381370
382- Reflecter 的 ListAndWatch() 方法负责更新内部的 DeltaFIO(具体参考:[ 3.reflector.md] ( 3.reflector.md ) ):
371+ 1 .  如果事件类型为 Sync,且对象的事件列表中最后一个事件类型为 Deleted,则直接返回(没有必要再同步一个已删除的对象);
372+ 2 .  连续重复的 Deleted 事件为一个;
383373
384- 1 .  从 kube-apiserver List 特定类型的所有对象,然后调用 DeltaFIFO 的 Replace() 方法;
385- 2 .  根据配置的 Resync 时间,周期调用 DeltaFIFO 的 Resync() 方法;
386- 3 .  后续的 Watch 阶段,会根据事件的类型,调用 DeltaFIFO 的 Add/Update/Delete 方法;
374+ ## Delete() 方法  
387375
388- Reflecter 的 ` Run() `  方法调用 ` ListAndWatch() `  方法,如果没有出错则一直阻塞,当出错时,会等待 r.period 时间(** 期间没有 Watch,可能会丢事件** ),再次执行 ListAndWatch() 方法获取特定类型所有对象并 Watch。
376+ 如果 ` f.knownObjects `  对象缓存和事件队列 ` f.items `  中均没有待删除的对象,则** 直接返回** ,否则为对象生成 ` Deleted `  Delta 事件(非` DeletedFinalStateUnknown `  类型)。
377+ 378+ 不同于 FIFO 的 Deleta() 方法会将对象从缓存中删除,DeltaFIFO 的 Delete() 方法** 不将对象从事件缓存 f.items 和弹出队列 f.queue 删除** 。而是由 DeltaFIFO 的消费者 ` controller `  根据弹出的 Deltas 对象,将对象从对象缓存 f.knownObjects 中删除。
389379
390- ```  go 
391- func  (r  *Reflector ) Run (stopCh <-chan struct{}) {
392- 	klog.V (3 ).Infof (" Starting reflector %v  (%s ) from %s " expectedType , r.resyncPeriod , r.name )
393- 	wait.Until (func () {
394- 		if  err  :=  r.ListAndWatch (stopCh); err != nil  {
395- 			utilruntime.HandleError (err)
396- 		}
397- 	}, r.period , stopCh)
398- }
399- ``` 
380+ ## Get/GetByKey/List/ListKeys() 方法  
400381
401- 所以,Reflecter 可能会 ** 多次调用 **  DeltaFIFO 的 Replace() 方法。 
382+ 都是从内部事件缓存 f.items 中返回对象的 Deltas 或 Key 列表; 
402383
403- 有且只有  Replace() 方法可能生成 DeletedFinalStateUnknown 事件,如: 
384+ ##  Replace() 方法  
404385
405- 1 .  Reflecter 重新执行 ListAndWatch() 方法的 Sleep r.period 期间丢了该对象的 Delete 事件(所以对象还在 f.knownObjects 中);
406- 2 .  Reflecter 执行 ListAndWatch() 方法从 kube-apiserver LIST 该类型资源对象的结果中没有该对象;
386+ ` Replace(list []interface{}, resourceVersion string) ` 
407387
408- ```  go 
409- type  Delta  struct  {
410- 	Type  DeltaType 
411- 	Object  interface {}
412- }
413- type  DeletedFinalStateUnknown  struct  {
414- 	Key  string 
415- 	Obj  interface {}
416- }
417- ``` 
388+ 1 .  遍历 list 中的对象,为每个对象生成 ` Sync `  事件;
389+ 2 .  遍历 f.knownObjects.ListKeys() 中的对象,对于不在传入的 list 中的对象,生成 ` Deleted `  事件,对象类型为 ` DeletedFinalStateUnknown ` (非 Delta 类型);
418390
419- +  Delta 代表正常的事件,包含事件类型和元素,Object 是事件产生后的状态;
420- +  DeletedFinalStateUnknown 代表删除事件,Key 为对象的 id;
391+ Reflecter 周期调用 Replace() 方法将 etcd 中的特定类型的所有对象同步到 DeltaFIFO 中。` controller `  用 DeltaFIFO 弹出的对象更新 ` knownObjects `  缓存,详情参考 [ Reflector] ( 3.reflector.md )  和 [ controller 和 Informer] ( 4.controller-informer.md )  文档。
421392
422393## Resync() 方法  
423394
424- 遍历 f.knownObjects.ListKeys() 中的元素 : 
425-   对于某个元素  id,如果 f.items[id] 有值(长度 > 0),则跳过;
426-  否则,生成 Sync 事件:f.queueActionLocked(Sync, obj) 
395+ 遍历 f.knownObjects.ListKeys() 中的对象 :
396+  对于某个对象  id,如果 f.items[ id]  有值(长度 > 0),则跳过;
397+  否则,生成 Sync 事件:f.queueActionLocked(Sync, obj)
427398
428399综上,** Replace() 和 Rsync() 方法会会生成 Sync 事件** 。
429400
@@ -437,7 +408,7 @@ Pop(process PopProcessFunc)
437408
438409## HasSyncd() 方法  
439410
440- 创建 FIFO/DealtaFIFO 后,如果首先调用的是 ` Replace() `  方法,则 ` f.populated `  被设置为 ` true ` ,` f.initialPopulationCount `  被设置为传入的对象数量。当这一批对象都被弹出完毕时( 包含弹出前被删除的对象),` HasSynced() `  方法返回 ` true ` :
411+ 创建 FIFO/DealtaFIFO 后,如果首先调用的是 ` Replace() `  方法,则 ` f.populated `  被设置为 ` true ` ,` f.initialPopulationCount `  被设置为传入的对象数量。当这一批对象都被弹出完毕时( 包含弹出前被删除的对象),` HasSynced() `  方法返回 ` true ` :
441412
442413```  go 
443414//  来源于 k8s.io/client-go/tools/cache/fifo.go
@@ -450,10 +421,45 @@ func (f *DeltaFIFO) HasSynced() bool {
450421
451422另外,如果在调用 ` Replace() `  方法前,** 首先** 调用了 ` Add/Update/Delete/AddIfNotPresent() `  方法,则 ` HasSynced() `  方法也会返回 ` true ` 。
452423
453- 后面会介绍,FIFO 的主要使用者是 ` Refector ` ,它在启动后:
424+ ## DeltaFIFO 和 knownObjects 对象缓存的同步  
425+ 426+ 1 .  Reflector 从 etcd List 出对象后,调用 DeltaFIFO 的 Replace() 方法为传入的对象生成 Sync 事件,此时 knownObjects 为空;
427+ 2 .  controller 从 DeltaFIFO 弹出对象的事件列表 Deltas,遍历 Deltas,根据 Delta 中的事件类型更新 knownObjects,从而实现 DeltaFIFO 和 knownObjects 缓存中的对象一致:
428+ 429+  controller 每次** 启动** 时,因为 knownObjects 为空且事件类型为 Sync,所以对从 etcd 同步来的所有对象,都先调用一次 clientState 的 ** Add() 方法和注册的 OnAdd() 回调函数** 。
430+ 431+  ```  go 
432+  //  来源于:k8s.io/client-go/tools/cache/controller.go
433+  for  _ , d  :=  range  obj.(Deltas) {
434+  switch  d.Type  {
435+  //  Replace() 方法生成的 Sync 事件涉及到的对象,
436+  case  Sync, Added, Updated:
437+  if  old , exists , err  :=  clientState.Get (d.Object ); err == nil  && exists {
438+  if  err  :=  clientState.Update (d.Object ); err != nil  {
439+  return  err
440+  }
441+  h.OnUpdate (old, d.Object )
442+  } else  {
443+  if  err  :=  clientState.Add (d.Object ); err != nil  {
444+  return  err
445+  }
446+  h.OnAdd (d.Object )
447+  }
448+  case  Deleted:
449+  if  err  :=  clientState.Delete (d.Object ); err != nil  {
450+  return  err
451+  }
452+  h.OnDelete (d.Object )
453+  }
454+  }
455+  ```
456+ 457+ 3 . 但是,Reflector 的 Watch  可能会出现**丢失事件**的情况(如 ListAndWatch  出错返回后,Reflector 会 Sleep  一段时间再执行它,期间 etcd 的对象变化事件丢失),这样再次 List  到的对象集合与 knownObjects 缓存中的对象集合不一致。
458+ 459+  Replace () 方法会为 knownObjects 缓存中多余的对象生成 Deleted  类型的 ` DeletedFinalStateUnknown` 
460+ 461+ 4 . ListAndWatch () 方法起一个 goroutine,周期的调用 Resync () 方法将 knownObjects 中的对象更新到 DeltaFIFO ,为何要这么做呢?
454462
455- 1 .  首先从 kube-apiserver LIST 某类型对象,然后调用 FIFO 的 Replace() 方法,传入对象列表,实现将** 某类型的所有对象** 同步到缓存中;
456- 2 .  再从 kube-apiserver Watch 该类型对象的变化事件,如 Update/Delete,按需调用 FIFO 的 Add/Delete/Update 方法;
457- 3 .  周期从 kube-apiserver 中 Rsync 该类型的所有对象,传给 FIFO/DeltaFIFO 的 Replace() 方法;
463+  在前文我们提到 DeltaFIFO  的使用场景之一是:**"你想周期处理所有的对象"**,但对象一旦从 DeltaFIFO  中弹出,如果没有产生新的 Watch  事件,就不会对它再调用注册的回调函数。而周期执行 Resync () 方法的目的就是**为对象产生新的 Sync  事件**,从而有机会再次调用处理函数。基于此,Resync 时,如果对象已经在 f.items  中,则有机会被弹出,所以不需要为它生成 Sync  事件。
458464
459- 所以,对于  ` Refector `  的调用方而言, ` HasSynce `  结果为  ` true `  表示对象都已经 ** 完整同步过一次和且被处理完毕 ** 。 
465+  但是这里会有一个问题:如果当前对象的最后一个 
0 commit comments