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

相关推荐
金刚猿10 小时前
01_虚拟机中间件部署_root 用户安装 docker 容器,配置非root用户权限
docker·中间件·容器
JH_Kong10 小时前
解决 WSL 中 Docker 权限问题:从踩坑到完整修复
docker·容器
陈桴浮海12 小时前
Kustomize实战:从0到1实现K8s多环境配置管理与资源部署
云原生·容器·kubernetes
张小凡vip13 小时前
Kubernetes--k8s中部署redis数据库服务
redis·kubernetes
Hello.Reader14 小时前
Flink Kubernetes HA(高可用)实战原理、前置条件、配置项与数据保留机制
贪心算法·flink·kubernetes
ShiLiu_mtx15 小时前
k8s - 7
云原生·容器·kubernetes
MonkeyKing_sunyuhua18 小时前
docker compose up -d --build 完全使用新代码打包的方法
docker·容器·eureka
醇氧19 小时前
【docker】mysql 8 的健康检查(Health Check)
mysql·docker·容器
匀泪1 天前
云原生(LVS NAT模式集群实验)
服务器·云原生·lvs
70asunflower1 天前
用Docker创建不同的容器类型
运维·docker·容器