跳到主要内容

28.etcdswap

PR #265

Use etcd compare and swap to update the list of pods, to remove a race.

// CompareAndSwapObj marshals obj via json, and stores under key so long as index matches the previous modified index
func (h *EtcdHelper) CompareAndSwapObj(key string, obj interface{}, index uint64) error {
data, err := json.Marshal(obj)
if err != nil {
return err
}
_, err = h.Client.CompareAndSwap(key, string(data), 0, "", index)
return err
}

func (registry *EtcdRegistry) updateManifests(machine string, manifests []api.ContainerManifest, index uint64) error {
if index != 0 {
return registry.helper().CompareAndSwapObj(makeContainerKey(machine), manifests, index)
} else {
return registry.helper().SetObj(makeContainerKey(machine), manifests)
}
}

func (registry *EtcdRegistry) runPod(pod api.Pod, machine string) error {
manifests, index, err := registry.loadManifests(machine)
if err != nil {
return err
}

key := makePodKey(machine, pod.ID)
data, err := json.Marshal(pod)
if err != nil {
return err
}
_, err = registry.etcdClient.Create(key, string(data), 0)

manifest, err := registry.manifestFactory.MakeManifest(machine, pod)
if err != nil {
return err
}
for {
manifests = append(manifests, manifest)
err = registry.updateManifests(machine, manifests, index)
if util.IsEtcdConflict(err) {
manifests, index, err = registry.loadManifests(machine)
if err != nil {
return err
}
continue
}
return err
}
}

CompareAndSwapObj:这是EtcdHelper结构的一个方法,用于在Etcd中通过比较和替换(CAS)的方式更新对象。它接受一个键(key)、一个对象和一个索引作为输入参数。首先,这个方法会将对象序列化为JSON格式,然后使用Etcd客户端的CompareAndSwap方法尝试更新Etcd中对应的键值。这个更新只有在给定的索引与Etcd中当前的修改索引匹配时才会成功。

updateManifests:这是EtcdRegistry结构的一个方法,用于更新指定机器上的容器清单(manifests)。如果提供了一个非零的索引,它会使用CompareAndSwapObj方法尝试更新Etcd中的容器清单;否则,它会使用SetObj方法直接设置Etcd中的容器清单。

runPod:这也是EtcdRegistry结构的一个方法,用于在指定的机器上运行一个Pod。这个方法首先会加载指定机器上的容器清单和其对应的修改索引,然后创建一个对应Pod的键值对。接着,这个方法会使用manifestFactory创建一个新的容器清单,并尝试使用updateManifests方法更新Etcd中的容器清单。如果更新失败并且错误原因是Etcd的冲突(例如,容器清单在此期间被其他客户端修改了),那么这个方法会重新加载容器清单和修改索引,并尝试更新。这个过程会不断重复,直到更新成功或者遇到非冲突的错误为止。

这段代码的主要目的是在分布式环境中,使用Etcd作为后端存储来保证并发安全,确保在多个客户端同时操作数据时,数据的一致性和完整性都能得到保证。

PR #283,289

Move stringSet to util.StringSet Add a NewStringSet() function

PR #286

Separate scheduler from registry [scheduler 终于有自己独立的包了]

目前咱们的 调度组件 还不是独立的二进制,算法也比较简单,日后会慢慢完善哒!

提示

这是一道练习题,它要求你创建一个新的调度器,该调度器将使用随机算法来选择机器运行Pod。你需要创建一个名为RandomScheduler的结构体,并实现Scheduler接口。这是一个很好的练习题,因为它能帮助你熟悉Go语言中接口的使用,并了解如何在Go语言中实现随机选择算法。

下面是你需要完成的任务:

// TODO: 导入需要的包

// RandomScheduler chooses machines randomly.
type RandomScheduler struct {
rand *rand.Rand
}

// TODO: 创建一个新的RandomScheduler实例。记得初始化rand字段。

// TODO: 实现Schedule方法。这个方法应该从minionLister提供的机器列表中随机选择一台机器。

// 提示: 你可以使用rand.Intn函数来生成随机数。

完成这个练习后,你应该能创建一个新的RandomScheduler实例,并使用它来随机选择机器运行Pod。记住,你需要确保Schedule方法能正确处理可能发生的错误,例如minionLister无法列出机器。