[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参数设定。

相关推荐
Zsr10233 分钟前
POD控制器:集群的“自动化运维管家”
docker·容器·kubernetes
汪碧康7 分钟前
一文掌握k8s容器的资源限制
docker·云原生·容器·golang·kubernetes·k8s·xkube
可爱又迷人的反派角色“yang”9 分钟前
k8s(七)
java·linux·运维·docker·云原生·容器·kubernetes
optimistic_chen10 分钟前
【Docker入门】namespace 空间隔离
linux·运维·docker·容器·空间隔离
骇客野人10 分钟前
Linux通过自动脚本自动化推送k8s Docker镜像
linux·kubernetes·自动化
Java程序员威哥14 分钟前
Spring Boot 3.x 云原生终极适配:GraalVM 原生镜像构建 + Serverless 生产级部署(完整实战+最优模板)
java·开发语言·spring boot·后端·云原生·serverless·maven
萧曵 丶14 分钟前
Kubernetes(k8s)搭建指南
云原生·容器·kubernetes
周壮10 小时前
01 一探究竟:从架构的演变看微服务化架构
微服务·云原生·架构
周壮11 小时前
04 服务治理:Nacos 如何实现微服务服务治理
微服务·云原生·架构
雨落秋垣11 小时前
简单的在宝塔面板的Docker环境中为网站同时启用IPv6支持
云原生·eureka