Client-go之util(DeltaFIFO补充之Resync机制)

参考https://github.com/cloudnativeto/sig-k8s-source-code/issues/11

一 DeltaFIFO队列为什么需要Resync

为什么需要 Resync 机制呢?因为在处理 SharedInformer 事件回调时,可能存在处理失败的情况,定时的 Resync 让这些处理失败的事件有了重新 onUpdate 处理的机会。
主要的目的是为了不丢数据,处理 resync 机制还有边缘触发与水平获取的设计,一起来保证不丢事件、数据同步并能及时响应事件。
在这里插入图片描述
图来自于《Programming Kubernetes》

二 代码实现

1. Resync

// 重新同步将为每个项目发送一个同步事件
func (f *DeltaFIFO) Resync() error {
	f.lock.Lock()
	defer f.lock.Unlock()

	if f.knownObjects == nil {
		return nil
	}
// ListKeys返回当前在FIFO中的对象的所有键的列表。
	keys := f.knownObjects.ListKeys()
	for _, k := range keys {
		if err := f.syncKeyLocked(k); err != nil {
			return err
		}
	}
	return nil
}

2. ListKeys

// ListKeys返回当前在FIFO中的对象的所有键的列表。
func (f *DeltaFIFO) ListKeys() []string {
	f.lock.RLock()
	defer f.lock.RUnlock()
	list := make([]string, 0, len(f.items))
	for key := range f.items {
		list = append(list, key)
	}
	return list
}

3. syncKeyLocked

func (f *DeltaFIFO) syncKeyLocked(key string) error {
	obj, exists, err := f.knownObjects.GetByKey(key)
	if err != nil {
		klog.Errorf("Unexpected error %v during lookup of key %v, unable to queue object for sync", err, key)
		return nil
	} else if !exists {
		klog.Infof("Key %v does not exist in known objects store, unable to queue object for sync", key)
		return nil
	}

	//如果我们正在执行Resync(),并且已经为该对象排队了一个事件,我们将忽略该对象的Resync。 
	//这是为了避免竞争,其中重新同步带有对象的先前值(因为对对象的事件进行排队不会触发更改基础存储<knownObjects>。
	id, err := f.KeyOf(obj)
	if err != nil {
		return KeyError{obj, err}
	}
	//如果队列中已存在 则不进行resync
	if len(f.items[id]) > 0 {
		return nil
	}

	if err := f.queueActionLocked(Sync, obj); err != nil {
		return fmt.Errorf("couldn't queue object: %v", err)
	}
	return nil
}

4. queueActionLocked

// queueActionLocked追加到对象的增量列表中。 呼叫者必须先锁定。
func (f *DeltaFIFO) queueActionLocked(actionType DeltaType, obj interface{}) error {
	id, err := f.KeyOf(obj)
	if err != nil {
		return KeyError{obj, err}
	}
	//初始化一个fifo 并且给我们对应的obj 添加进items
	//items map[string]Deltas
	newDeltas := append(f.items[id], Delta{actionType, obj})
	//去重
	newDeltas = dedupDeltas(newDeltas)
	//如果对应obj 的deltas 长度大于0
	if len(newDeltas) > 0 {
		//判断是否存在
		if _, exists := f.items[id]; !exists {
		//如果不存在先在队列中添加
			f.queue = append(f.queue, id)
		}
		//然后重新赋给items对应key 的value
		f.items[id] = newDeltas
		//唤醒监听在队列的goroutine
		f.cond.Broadcast()
	} else {
//我们需要将其从地图中删除(如果队列中没有其他项目,则它们将被忽略)。
		delete(f.items, id)
	}
	return nil
}

三 总结

resync => listkeys
   	   => synckeylocked => queueActionLocked

listkeys拿到当前在FIFO中的对象的所有键的列表
synckeylocked 判断需要做同步的obj 是否有事件在队列中 如果有丢弃,没有的话就调用queueactionlocked
queueactionlocked 主要是做队列的插入以及分发

Resync 机制的引入,定时将 Indexer 缓存事件重新同步到 Delta FIFO 队列中,在处理 SharedInformer 事件回调时,让处理失败的事件得到重新处理。并且通过入队前判断 FIFO 队列中是否已经有了更新版本的 event,来决定是否丢弃 Indexer 缓存不进行 Resync 入队。在处理 Delta FIFO 队列中的 Resync 的事件数据时,触发 onUpdate 回调来让事件重新处理。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
可以使用client-go库中的`Patch`方法来部分更新Kubernetes资源的`spec`字段。具体操作步骤如下: 1. 导入必要的包 ```go import ( "encoding/json" "fmt" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/kubernetes" "k8s.io/client-go/rest" "k8s.io/client-go/util/retry" ) ``` 2. 创建Kubernetes客户端 ```go config, err := rest.InClusterConfig() if err != nil { panic(err.Error()) } clientset, err := kubernetes.NewForConfig(config) if err != nil { panic(err.Error()) } ``` 3. 构造需要更新的`Patch`对象 ```go type patch struct { Spec struct { Replicas int32 `json:"replicas"` } `json:"spec"` } // 将需要更新的字段构造成Patch对象 updatePatch := patch{} updatePatch.Spec.Replicas = 3 patchBytes, err := json.Marshal(updatePatch) if err != nil { panic(err.Error()) } ``` 4. 执行部分更新操作 ```go // 定义资源名称和名称空间 name := "deployment-name" namespace := "default" // 创建资源标识 patchMeta := metav1.ObjectMeta{ Name: name, Namespace: namespace, } // 使用client-go的Patch方法进行部分更新 _, err = clientset.AppsV1().Deployments(namespace).Patch(context.TODO(), name, types.StrategicMergePatchType, patchBytes, metav1.PatchOptions{}) if err != nil { if errors.IsNotFound(err) { fmt.Printf("Deployment %s in namespace %s not found\n", name, namespace) } else { panic(err.Error()) } } ``` 这样就可以使用client-go库来部分更新Kubernetes资源的`spec`字段了。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来自万古的忧伤

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值