[k8s源码]8.deltaFIFO

deltaFIFO

DeltaFIFO: 这是一个特殊类型的队列,它结合了FIFO(先进先出)队列的特性和增量(Delta)处理的能力。DeltaFIFO 中是按顺序存储的,但它们不必严格按照发生的顺序逐个处理。这种设计提供了处理的灵活性和优化的机会,允许控制器根据实际需求选择最有效的处理策略。这是 DeltaFIFO 设计的一个重要特性,使其能够高效地处理复杂的资源变化场景。

Delta 实际上是一个结构体(struct),它在 Kubernetes 的 client-go 库中定义。

Go 复制代码
type Delta struct {
    Type   DeltaType
    Object interface{}
}

interface{} 允许 Delta 结构体存储任何类型的 Kubernetes 对象,不仅仅是 Pod。这使得 Delta 结构体可以用于所有类型的 Kubernetes 资源。

Go 复制代码
type DeltaFIFO struct {
    // 用于存储对象键的队列
    queue []string
    
    // 存储每个键对应的 Delta 列表
    items map[string][]Delta
    
    // 其他字段,如锁、条件变量等
}

DeltaType 的可能值:

const (

Added DeltaType = "Added"

Updated DeltaType = "Updated"

Deleted DeltaType = "Deleted"

// 可能还有其他类型,如 Sync

)

可以看到图中一个key对应一个delta值,当需要使用存储的对象时,通常需要进行类型断言:

Go 复制代码
if pod, ok := delta.Object.(*v1.Pod); ok {
    // 使用 pod 对象
}
Go 复制代码
// 存储 Pod
podDelta := Delta{
    Type: Added,
    Object: &v1.Pod{Metadata: metav1.ObjectMeta{Name: "mypod"}},
}

// 存储 Service
serviceDelta := Delta{
    Type: Updated,
    Object: &v1.Service{Metadata: metav1.ObjectMeta{Name: "myservice"}},
}
controller消费

Controller 通过调用 DeltaFIFO 的 Pop 方法来消费队列中的项目。这个方法通常在控制器的主循环中被调用。

Go 复制代码
func (c *Controller) processNextItem() bool {
    obj, shutdown := c.queue.Get()
    if shutdown {
        return false
    }

    defer c.queue.Done(obj)
    err := func(obj interface{}) error {
        deltas, ok := obj.(cache.Deltas)
        if !ok {
            return fmt.Errorf("expected cache.Deltas, got %v", obj)
        }
        
        for _, delta := range deltas {
            switch delta.Type {
            case cache.Added:
                // 首先更新 Indexer
                if err := c.indexer.Add(delta.Object); err != nil {
                    return err
                }
                // 然后调用事件处理函数
                c.handleAddition(delta.Object)
            case cache.Updated:
                // 首先更新 Indexer
                if err := c.indexer.Update(delta.Object); err != nil {
                    return err
                }
                // 然后调用事件处理函数
                c.handleUpdate(delta.Object)
            case cache.Deleted:
                // 首先更新 Indexer
                if err := c.indexer.Delete(delta.Object); err != nil {
                    return err
                }
                // 然后调用事件处理函数
                c.handleDeletion(delta.Object)
            }
        }
        return nil
    }(obj)

    if err != nil {
        utilruntime.HandleError(err)
        c.queue.AddRateLimited(obj)
        return true
    }
    c.queue.Forget(obj)
    return true
}

初始化阶段:

创建 Informer(通常是 SharedInformer)

创建 Controller

将 Controller 的事件处理函数注册到 Informer

数据流动:

a. API 服务器 -> Reflector:

Reflector 通过 client-go API 监听 Kubernetes API 服务器

获取资源对象(如 Pod)的变化

b. Reflector -> DeltaFIFO:

Reflector 将这些变化(Delta)放入 DeltaFIFO 队列

c. DeltaFIFO -> Controller:

Controller 的 processLoop 方法从 DeltaFIFO 队列中取出数据

使用 Pop 方法,该方法包含一个 process 回调函数

d. Controller -> Indexer:

process 回调函数处理 Delta

更新 Indexer(本地缓存)

e. Controller -> 事件处理:

调用相应的事件处理函数(如 OnAdd, OnUpdate, OnDelete)

Go 复制代码
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")
}

// Multiplexes updates in the form of a list of Deltas into a Store, and informs
// a given handler of events OnUpdate, OnAdd, OnDelete
func processDeltas(
	// Object which receives event notifications from the given deltas
	handler ResourceEventHandler,
	clientState Store,
	deltas Deltas,
	isInInitialList bool,
) error {
	// from oldest to newest
	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
}

Resync机制会将Indexer本地存储中的资源对象同步到DeltaFIFO中,并将这些资源对象设置为Sync的操作类型。Resync函数在Reflector中定时执行,它的执行周期由NewReflector函数传入的resyncPeriod参数设定。

相关推荐
学Linux的语莫37 分钟前
kompose、docker转k8s
docker·容器·kubernetes
阿里云云原生1 小时前
探秘 AgentRun丨流量一大就瘫痪?如何解决 AI 模型调用之痛
云原生
是Yu欸2 小时前
从Ascend C算子开发视角看CANN的“软硬协同”
c语言·开发语言·云原生·昇腾·ascend·cann·开放社区
光头熊2 小时前
一次 nerdctl prune -a 导致 Kubernetes 节点不可用的复盘
kubernetes
码界奇点2 小时前
基于微服务架构的企业身份与访问管理系统设计与实现
微服务·云原生·架构·车载系统·毕业设计·源代码管理
一点晖光5 小时前
docker配置npm环境变量出现问题
docker·容器·npm
一分半心动5 小时前
windows docker desktop 安装VibeVoice
运维·docker·容器
LucidX5 小时前
Docker核心操作实战
运维·docker·容器
隔壁阿布都5 小时前
Docker Compose中的网络管理
运维·docker·容器
yuxb737 小时前
kubernetes弹性伸缩
笔记·kubernetes