一,SharedInformer组件结构
-
蓝色代表接口,其他颜色代表实现类
-
SharedInformer对外暴露的接口声明,sharedIndexInformer是内部实现类,最核心的组件indexer,Controller -
controller是接口Controller实现,主要职责维护队列生命周期管理,以及processLoop不断消费队列消息 -
Relector通过client-go的listWatcher不断拉取对象变化数据,然后加入store -
DeltaFIFO在controller,Relector中表现为不同的接口,这样数据在Relector以存储方式加入,在controller中以队列形式处理
二,根据数据流向进行源码走读
- 源码走读只贴了与数据流转相关的代码,其他代码用省略号...表示
- 省略了stop相关控制代码
- 省略了失败重试代码
- 省略了resourceVersion相关代码
- 其他例如日志代码等等非核心逻辑代码
2.1 Relector读取数据
func (r *Reflector) Run(stopCh <-chan struct{}) {
...
if err := r.ListAndWatch(stopCh); err != nil {
r.watchErrorHandler(r, err)
}
...
}
Reflector 启动(Run)的时候会调用Reflector的ListAndWatch方法
func (r *Reflector) ListAndWatch(stopCh <-chan struct{}) error {
...
if fallbackToList {
err = r.list(stopCh)
if err != nil {
return err
}
}
...
return r.watch(w, stopCh, resyncerrc)
}
- 首先调用
list方法,拉取所有数据 - 然后调用
watch,监听数据变化 - 实际上还有
watchList方法,它与list的调用互斥,有兴趣的可自行研究
func (r *Reflector) list(stopCh <-chan struct{}) error {
...
//分页拉取数据封装,避免一次性拉取数据过多,对apiserver造成io压力过大
list, paginatedResult, err = pager.List(context.Background(), options)
...
if err := r.syncWith(items, resourceVersion); err != nil {
return fmt.Errorf("unable to sync list result: %v", err)
}
...
}
func (r *Reflector) syncWith(items []runtime.Object, resourceVersion string) error {
found := make([]interface{}, 0, len(items))
for _, item := range items {
found = append(found, item)
}
return r.store.Replace(found, resourceVersion)
}
list拉取数据后会调用syncWith方法syncWith将数据同步给store(实际上是DeltaFIFO)
func (r *Reflector) watch(w watch.Interface, stopCh <-chan struct{}, resyncerrc chan error) error {
...
for {
...
if w == nil {
...
w, err = r.listerWatcher.Watch(options)
...
}
err = watchHandler(start, w, r.store, r.expectedType, r.expectedGVK, r.name, r.typeDescription, r.setLastSyncResourceVersion, nil, r.clock, resyncerrc, stopCh)
w.Stop()
w = nil
//判断错误是否continue重试
...
}
}
func watchHandler(start time.Time,
w watch.Interface,
store Store,
expectedType reflect.Type,
expectedGVK *schema.GroupVersionKind,
name string,
expectedTypeName string,
setLastSyncResourceVersion func(string),
exitOnInitialEventsEndBookmark *bool,
clock clock.Clock,
errc chan error,
stopCh <-chan struct{},
) error {
...
loop:
for {
select {
case <-stopCh:
return errorStopRequested
case err := <-errc:
return err
case event, ok := <-w.ResultChan():
...
switch event.Type {
case watch.Added:
err := store.Add(event.Object)
...
case watch.Modified:
err := store.Update(event.Object)
...
case watch.Deleted:
err := store.Delete(event.Object)
...
...
}
}
...
}
watcher会根据eventType来调用store的不同方法
2.2 controller相关代码
//controller启动
func (c *controller) Run(stopCh <-chan struct{}) {
...
//创建Reflector
r := NewReflectorWithOptions(
c.config.ListerWatcher,
c.config.ObjectType,
c.config.Queue,
ReflectorOptions{
ResyncPeriod: c.config.FullResyncPeriod,
TypeDescription: c.config.ObjectDescription,
Clock: c.clock,
},
)
...
var wg wait.Group
//启动Reflector,拉取数据
wg.StartWithChannel(stopCh, r.Run)
//速率控制调用processLoop
wait.Until(c.processLoop, time.Second, stopCh)
wg.Wait()
}
func (c *controller) processLoop() {
for {
obj, err := c.config.Queue.Pop(PopProcessFunc(c.config.Process))
...
}
}
- 创建Reflector
- 启动
Reflector,拉取数据 - 调用
processLoop processLoop会调用controller中config的Process方法
2.3 sharedIndexInformer相关代码
func (s *sharedIndexInformer) Run(stopCh <-chan struct{}) {
...
//用indexer构建fifo队列
fifo := NewDeltaFIFOWithOptions(DeltaFIFOOptions{
KnownObjects: s.indexer,
EmitDeltaTypeReplaced: true,
Transformer: s.transform,
})
cfg := &Config{
Queue: fifo,
ListerWatcher: s.listerWatcher,
...
Process: s.HandleDeltas,
...
}
func() {
s.startedLock.Lock()
defer s.startedLock.Unlock()
//创建controller
s.controller = New(cfg)
s.controller.(*controller).clock = s.clock
s.started = true
}()
...
//启动controller
s.controller.Run(stopCh)
}
//被controller的processLoop调用
func (s *sharedIndexInformer) HandleDeltas(obj interface{}, isInInitialList bool) error {
s.blockDeltas.Lock()
defer s.blockDeltas.Unlock()
if deltas, ok := obj.(Deltas); ok {
return processDeltas(s, s.indexer, deltas, isInInitialList)
}
return errors.New("object given as Process argument is not Deltas")
}
func processDeltas(
handler ResourceEventHandler,
clientState Store,
deltas Deltas,
isInInitialList bool,
) error {
for _, d := range deltas {
obj := d.Object
switch d.Type {
case Sync, Replaced, Added, Updated:
if old, exists, err := clientState.Get(obj); err == nil && exists {
if err := clientState.Update(obj); err != nil {
return err
}
handler.OnUpdate(old, obj)
} else {
if err := clientState.Add(obj); err != nil {
return err
}
handler.OnAdd(obj, isInInitialList)
}
case Deleted:
if err := clientState.Delete(obj); err != nil {
return err
}
handler.OnDelete(obj)
}
}
return nil
}
-
sharedIndexInformer启动过程中会用indexer创建fifo队列,并将队列和HandleDeltas赋值给controller的config -
controller的processLoop消费来自Reflector数据事件,会触发sharedIndexInformer的HandleDeltas方法调用 -
HandleDeltas方法会调用clientState以及handler处理数据,clientState实际上是indexer,handler实际上是sharedIndexInformer自身,这样对象变化时可以通过事件消费触发缓存indexer更新,以及通知sharedIndexInformer数据变化