理解kubernetes’ tools/cache包: part 7

本文深入探讨了Kubernetes中sharedIndexInformer结构的工作原理,详细解释了如何通过Run函数、DeltaFIFO、Controller和Reflector组件实现资源的同步与事件处理流程。

在本系列的part 6中(如果需要,可以从头开始),我们得到了一个相当完整的sharedIndexInformer结构视图及其导致的所有概念。

现在是时候看看这一切的行为方面了。

在下图中,我使用了UML 2.0构造。 具体来说,填充箭头表示同步调用,实线上的空心箭头表示异步调用,虚线上的空心箭头表示返回值。 标记为alt的帧是遵循UML 2.0的条件分支点。 最后,我简化了一些刻板印象,我希望这些刻板印象是合情合理的。

这里写图片描述

此图以在sharedIndexInformer上调用Run函数的某人或某事开始。 Run函数创建一个新的DeltaFIFO,传递MetaNamespaceKeyFunc作为其KeyFunc,以及sharedIndexInformer的Indexer(它也是一个KeyLister和一个KeyGetter,但你不能只看代码)。

然后,Run函数创建一个新的Controller,我在part 2中详细介绍了它,并异步调用它的run函数。 sharedIndexInformer的Run函数现在阻塞,直到显式关闭。

Controller的run函数创建了一个Reflector,为了本系列的目的,您可以手动过滤:相信通过使用其嵌入式ListerWatcher,它可以准确地将Kubernetes资源放入其存储中,这恰好是之前创建的DeltaFIFO。

在这一点上,我们在高层次上拥有一台Rube Goldberg机器,可将Kubernetes资源复制到DeltaFIFO中。 例如,如果新的Pod出现在Kubernetes中,那么它会显示在DeltaFIFO中。

现在Controller的运行进入一个无限直到显式停止的循环,它每秒调用Controller的processLoop函数。

processLoop函数通过Reflector将单个线程中存储items的DeltaFIFO出队。 换句话说,DeltaFIFO是(如名称所示)缓冲队列,其中生产者通过Reflector实际上是Kubernetes本身,并且消费者(有效地)在构建时提供给Controller的任何功能

那么在构建时,该特定Controller提供了哪些功能? sharedIndexInformer的handleDeltas函数

因此,handleDeltas函数是一个队列排除器,并且出于许多行为分析的目的,我们可以方便地忽略之前的所有内容。 我们知道,当调用此函数时,它已从(有效)Kubernetes收到一组添加,更改,完全替换或删除。 这是它的样子:

func (s *sharedIndexInformer) HandleDeltas(obj interface{}) error {
    s.blockDeltas.Lock()
    defer s.blockDeltas.Unlock()

    // from oldest to newest
    for _, d := range obj.(Deltas) {
        switch d.Type {
        case Sync, Added, Updated:
            isSync := d.Type == Sync
            s.cacheMutationDetector.AddObject(d.Object)
            if old, exists, err := s.indexer.Get(d.Object); err == nil && exists {
                if err := s.indexer.Update(d.Object); err != nil {
                    return err
                }
                s.processor.distribute(updateNotification{oldObj: old, newObj: d.Object}, isSync)
            } else {
                if err := s.indexer.Add(d.Object); err != nil {
                    return err
                }
                s.processor.distribute(addNotification{newObj: d.Object}, isSync)
            }
        case Deleted:
            if err := s.indexer.Delete(d.Object); err != nil {
                return err
            }
            s.processor.distribute(deleteNotification{oldObj: d.Object}, false)
        }
    }
    return nil
}

根据它正在处理的事情,它可以向另一个队列添加,更新或删除事件,这次是由驾驶整个列车的sharedIndexInformer创建的Indexer。 一旦Add,Update或Delete调用返回,它就会调用sharedIndexInformer的关联sharedProcessor上的distribute函数

sharedProcessor的分发函数将通知转发给其相应的processorListeners,有效地将通知多路复用。 因此,如果给定的Delta对象是添加,则将调用processorListener的add函数。

processorListener add函数只是将传入通知放在名为addCh的同步队列(Go通道)上。 在这一点上,我们的通知之行暂时结束。

同时,回到sharedIndexInformer,回想一下它的Run方法仍在使用中。 在创建DeltaFIFO(现在正在入队和出队)和Controller(间接入队并耗尽它)之后,它执行的第三个有意义的事情是在单独的线程上调用其sharedProcessor上的run函数

sharedProcessor运行函数产生另外两个线程,然后挂起,直到被告知关闭。 第一个线程调用sharedProcessor的每个processorListener上的run函数。 第二个线程在每个processorListener上调用pop方法。 我们先来看一下processListener的run函数。

processListener的run函数只是从其nextCh同步队列(Go通道)中拉出任何通知,并且根据它的类型,最终在用户提供的ResourceEventHandler上调用OnUpdate,OnAdd或OnDelete。 这很简单,我可以在这里重现它:

func (p *processorListener) run() {
    defer utilruntime.HandleCrash()

    for next := range p.nextCh {
        switch notification := next.(type) {
        case updateNotification:
            p.handler.OnUpdate(notification.oldObj, notification.newObj)
        case addNotification:
            p.handler.OnAdd(notification.newObj)
        case deleteNotification:
            p.handler.OnDelete(notification.oldObj)
        default:
            utilruntime.HandleError(fmt.Errorf("unrecognized notification: %#v", next))
        }
    }
}

那么什么东西放在nextCh channel?pop函数。 此函数一直运行,直到被告知显式关闭,并将传入的通知从其addCh同步队列(Go通道)中拉出并将它们放在nextCh通道上

那么什么把东西放在addCh channel呢? 查看几段并回想起这是我们Kubernetes事件之旅的逻辑结束:表示事件的通知由processorListener的add函数放置在addCh上,由sharedProcessor的distribute函数调用。

这似乎是结束这篇文章的时候了。 我建议您查看序列图的完整大小版本,并在重新阅读该系列时将其打印出来或保留在您旁边,此包中的许多结构将更有意义。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值