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

相关推荐
Eternal-Student9 分钟前
【docker 保存】将Docker镜像保存为一个离线的tar归档文件
运维·docker·容器
码农小丘18 分钟前
一篇保姆式centos/ubuntu安装docker
运维·docker·容器
灼烧的疯狂2 小时前
K8S + Jenkins 做CICD
容器·kubernetes·jenkins
wenyue11213 小时前
Revolutionize Your Kubernetes Experience with Easegress: Kubernetes Gateway API
容器·kubernetes·gateway
梅见十柒5 小时前
wsl2中kali linux下的docker使用教程(教程总结)
linux·经验分享·docker·云原生
Python私教5 小时前
ubuntu搭建k8s环境详细教程
linux·ubuntu·kubernetes
运维&陈同学6 小时前
【zookeeper01】消息队列与微服务之zookeeper工作原理
运维·分布式·微服务·zookeeper·云原生·架构·消息队列
O&REO7 小时前
单机部署kubernetes环境下Overleaf-基于MicroK8s的Overleaf应用部署指南
云原生·容器·kubernetes
politeboy7 小时前
k8s启动springboot容器的时候,显示找不到application.yml文件
java·spring boot·kubernetes
运维小文8 小时前
K8S资源限制之LimitRange
云原生·容器·kubernetes·k8s资源限制