K8s 源码剖析及debug实战之 Kube-Scheduler(五):优选算法详解

文章目录

  • 0. 引言
  • 1. 回顾
  • 2. PrioritizeNodes
  • 3. 有哪些优选算法
  • 4. selectHost
  • 5. 总结
  • 6. 参考


0. 引言

欢迎关注本专栏,本专栏主要从 K8s 源码出发,深入理解 K8s 一些组件底层的代码逻辑,同时借助 debug Minikube 来进一步了解 K8s 底层的代码运行逻辑细节,帮助我们更好了解不为人知的运行机制,让自己学会如何调试源码,玩转 K8s。

本专栏适合于运维、开发以及希望精进 K8s 细节的同学。同时本人水平有限,尽量将本人理解的内容最大程度的展现给大家~

前情提要:
《K8s 源码剖析及debug实战(一):Minikube 安装及源码准备》
《K8s 源码剖析及debug实战(二):debug K8s 源码》
《K8s 源码剖析及debug实战之 Kube-Scheduler(一):启动流程详解》
《K8s 源码剖析及debug实战之 Kube-Scheduler(二):终于找到了调度算法的代码入口》
《K8s 源码剖析及debug实战之 Kube-Scheduler(三):debug 到预选算法门口了》
《K8s 源码剖析及debug实战之 Kube-Scheduler(四):预选算法详解》

文中采用的 K8s 版本是 v1.16。上篇介绍了预选算法的主要逻辑,本文继续介绍 K8s 的 Kube-Scheduler 源码的优选算法的具体逻辑。

1. 回顾

还记得这张图吗,目前我们在看「执行调度算法」这里,并且这里的预选算法的主要逻辑已经讲解完了。
在这里插入图片描述
再来看下调度的大体流程,重点关注的只剩下一个 PrioritizeNodes 方法了

func (g *genericScheduler) Schedule(pod *v1.Pod, pluginContext *framework.PluginContext) (result ScheduleResult, err error) {// 1. 检查pvc是否存在,不是很重要if err := podPassesBasicChecks(pod, g.pvcLister); // 2. 运行预过滤插件,一般不需要关注preFilterStatus := g.framework.RunPreFilterPlugins(pluginContext, pod)// 3. 更新node的信息,以最新的node缓存信息作为后续过滤、计算优先级的基础if err := g.snapshot(); err != nil {return result, err}// 4. 重要!!!关键方法,调度预选,predicate过滤不符合的nodefilteredNodes, failedPredicateMap, filteredNodesStatuses, err := g.findNodesThatFit(pluginContext, pod)// 5. 运行后置过滤插件,一般不需要关注postfilterStatus := g.framework.RunPostFilterPlugins(pluginContext, pod, filteredNodes, filteredNodesStatuses)// 6. 没找到一个符合要求的node,报错!if len(filteredNodes) == 0 {}// 7. 只找到一个符合要求的node,直接返回!if len(filteredNodes) == 1 {}// 8. 重要!!!上面如果找到多个node,那需要按照priority策略筛选priorityList, err := PrioritizeNodes(pod, g.nodeInfoSnapshot.NodeInfoMap, metaPrioritiesInterface, g.prioritizers, filteredNodes, g.extenders, g.framework, pluginContext)// 9. 好了,最终选一个node吧!host, err := g.selectHost(priorityList)
}

注意这里在 debug 代码的时候,需要把上面的代码第7点 if len(filteredNodes) == 1 {} 注释掉,因为 Minikube 目前只创建了一个 node,在这里就返回了。如果需要 debug PrioritizeNodes 这个方法,需要注释第7点。

2. PrioritizeNodes

老规矩,我把这个方法的主要逻辑提炼一下,方便看清楚全貌:

func PrioritizeNodes(pod *v1.Pod, nodeNameToInfo map[string]*schedulernodeinfo.NodeInfo, meta interface{}, priorityConfigs []priorities.PriorityConfig, nodes []*v1.Node, extenders []algorithm.SchedulerExtender, framework framework.Framework, pluginContext *framework.PluginContext (schedulerapi.HostPriorityList, error) {// 用了 Map-Reduce 模式,简单来说是:分布式计算的分离+归约思想,先并行计算,然后再聚集产生最终结果// 1. 定义了优先级打分的func,直接执行for i := range priorityConfigs {if priorityConfigs[i].Function != nil {...}}// 2. 并行执行 Map 方法,计算打分workqueue.ParallelizeUntil(context.TODO(), 16, len(nodes), func(index int) {for i := range priorityConfigs {// 注意,只有没有定义func的,才用 Map-Reduce 模式if priorityConfigs[i].Function != nil {continue}results[i][index], err = priorityConfigs[i].Map(pod, meta, nodeInfo)...}})// 3. 执行 Reduce 方法,聚合、归一化结果for i := range priorityConfigs {go func(index int) {if err := priorityConfigs[index].Reduce(pod, meta, nodeNameToInfo, results[index]); err != nil {}...}(i)}// 4. 一般不需要关注。执行额外的打分插件,默认的K8s没有,除非自己定义scoresMap, scoreStatus := framework.RunScorePlugins(pluginContext, pod, nodes)// 5. 按照func的权重,计算结果for i := range nodes {for j := range priorityConfigs {result[i].Score += results[j][i].Score * priorityConfigs[j].Weight}...}// 6. 一般不需要关注。这是扩展点,允许用户通过自定义逻辑来增强或替代默认调度器功能。它主要用于满足那些需要更复杂、定制化调度策略的场景。if len(extenders) != 0 && nodes != nil {...}return result, nil
}

从上面的第5步可以看到,打分关注两个地方,一个是 priority-func 计算出来的 score,一个是 priority-func 本身的 weight,其中 results 是一个二维表格,如下:

打分函数Node0Node1Node2
Priority-Func0s(0,0)s(0,1)s(0,2)
Priority-Func1s(1,0)s(1,1)s(1,2)
Priority-Funcns(n,0)s(n,1)s(n,2)

其中 s(x,y) 表示,第 x 个 Priority-Func 给 第 y 个 Node 打分的结果。

因此对于一个 Node,他的最终得分就是所有的 Priority-Func 得分 * weight 之和的结果。例如,假设,Priority-Funci 的 权重是 Wi,上表中 Node1 最终的得分如下:

finalNode1 = s(0,1)*W0 + s(1,1)*W1 + ... + s(n,1)*Wn

下面展示一下中间的 debug 的过程:
在这里插入图片描述
results 值:
在这里插入图片描述
最终得分:
在这里插入图片描述

3. 有哪些优选算法

pkg/scheduler/algorithm/priorities 目录下有优选算法的实现,当然看 pkg/scheduler/algorithm/priorities/priorities.go 有全部的定义 :
在这里插入图片描述

  • LeastRequestedPriority:最低请求优先级。根据 CPU
    和内存的使用率来决定优先级,使用率越低优先级越高,也就是说优先调度到资源利用率低的节点,这个优先级函数能起到把负载尽量平均分到集群的节点上。默认权重为1

  • BalancedResourceAllocation:资源平衡分配。这个优先级函数会把 pod 分配到 CPU 和 memory 利用率差不多的节点(计算的时候会考虑当前 pod 一旦分配到节点的情况)。默认权重为 1

  • SelectorSpreadPriority:尽量把同一个 service、replication controller、replicaSet 的 pod 分配到不同的节点,这些资源都是通过 selector 来选择 pod 的。默认权重为 1

  • CalculateAntiAffinityPriority:尽量把同一个 service 下面 label 相同的 pod 分配到不同的节点

  • ImageLocalityPriority:根据镜像是否已经存在的节点上来决定优先级,节点上存在要使用的镜像,而且镜像越大,优先级越高。这个函数会尽量把 pod 分配到下载镜像花销最少的节点

  • NodeAffinityPriority:NodeAffinity,默认权重为 1

  • InterPodAffinityPriority:根据 pod 之间的亲和性决定 node 的优先级,默认权重为 1

  • NodePreferAvoidPodsPriority:默认权重是 10000,把这个权重设置的那么大,就以为这一旦该函数的结果不为 0,就由它决定排序结果

  • TaintTolerationPriority:默认权重是 1

4. selectHost

PrioritizeNodes 优选方法执行完成之后,会返回 node列表,在 selectHost 方法需要选择一个最终的节点作为调度的结果。这里的方法非常简单:

func (g *genericScheduler) selectHost(priorityList schedulerapi.HostPriorityList) (string, error) {if len(priorityList) == 0 {return "", fmt.Errorf("empty priorityList")}maxScore := priorityList[0].Scoreselected := priorityList[0].HostcntOfMaxScore := 1for _, hp := range priorityList[1:] {if hp.Score > maxScore {maxScore = hp.Scoreselected = hp.HostcntOfMaxScore = 1} else if hp.Score == maxScore {cntOfMaxScore++if rand.Intn(cntOfMaxScore) == 0 {// Replace the candidate with probability of 1/cntOfMaxScoreselected = hp.Host}}}return selected, nil
}

简单看一下就明白,选择 score 最大的,如果存在多个 score 一样都是最大,则随机选一个作为 host 节点!

5. 总结

到目前为止,预选和优选的流程就讲解完了,我把到目前为止的整体调度流程大致展示下:
在这里插入图片描述
后续把调度计算后的其他流程讲解下~

6. 参考

《K8s 源码剖析及debug实战(一):Minikube 安装及源码准备》
《K8s 源码剖析及debug实战(二):debug K8s 源码》
《K8s 源码剖析及debug实战之 Kube-Scheduler(一):启动流程详解》
《K8s 源码剖析及debug实战之 Kube-Scheduler(二):终于找到了调度算法的代码入口》
《K8s 源码剖析及debug实战之 Kube-Scheduler(三):debug 到预选算法门口了》
《K8s 源码剖析及debug实战之 Kube-Scheduler(四):预选算法详解》

欢迎关注本人,我是喜欢搞事的程序猿; 一起进步,一起学习;

也欢迎关注我的wx公众号:一个比特定乾坤
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/595811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙应用中图片的显示(Image组件)

目录 1、加载图片资源 1.1、存档图类型数据源 a.本地资源 b.网络资源 c.Resource资源 d.媒体库file://data/storage e.base64 1.2、多媒体像素图片 2、显示矢量图 3、添加属性 3.1、设置图片缩放类型 3.2、设置图片重复样式 3.3、设置图片渲染模式 3.4、设置图…

Go语言基本数据类型

Go语言基本数据类型 1.整型2.浮点型3.复数4.布尔型5.字符串窥探字符串类型字符串内建函数UTF-8编码字符串处理相关的四个包字符串和数字的转换 6.常量 1.整型 Go语言同时提供了有符号和无符号类型的整数运算。这里有int8、int16、int32和int64四种截然不同大小的有符号整数类型…

基于springboot公租房申请管理系统

开发语言:Java 框架:springboot JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven…

柯桥小语种学习,留学韩语 生活日常口语 语法

① N이다/A/V/았ㄹ/을지도 모르다 说不定 이미 도착했을 지도 모르니까 전화해 봐요 说不定已经到了,打电话试试 주말에 세일이 있을지도 모르니까 주말에 가 보자 周末说不定会搞活动,我们周末去吧 ② ㄴ/은/는/았었는/ㄹ/을지 모르다 不知道 처음이…

【webstorm中通过附加方式打开一个项目,这个项目本身有git,但是却看不到git的解决方法】

1、如图所示 设置-》版本控制-》未注册的根,选中后,再点加号,就可以了 2、如图所示 版本控制-》直接点加号-》选中项目路径,vcs选择git,点击确定就可以了

prometheus grafana mysql监控配置使用

文章目录 前传bitnami/mysqld-exporter:0.15.1镜像出现了问题.my.cnf可以用这个"prom/mysqld-exporter:v0.15.0"镜像重要的事情mysql监控效果外传 前传 prometheus grafana的安装使用:https://nanxiang.blog.csdn.net/article/details/135384541 本文说…

【电商项目实战】沙箱支付模拟支付功能

🎉🎉欢迎来到我的CSDN主页!🎉🎉 🏅我是Java方文山,一个在CSDN分享笔记的博主。📚📚 🌟推荐给大家我的专栏《电商项目实战》。🎯🎯 &am…

芯片SIC8833可开发打气泵方案

无线车载打气泵方案由一块PCBA板集成其所需的功能,其充气原理是发动机通过两根三角带驱动气泵曲轴,进而驱动活塞进行打气,打出的气体通过导气管导入储气筒。另一方面储气筒又通过一根导气管将储气筒内的气体导入固定在气泵上的调压阀内&#…

ClickHouse基础知识(四):ClickHouse 引擎详解

1. 表引擎的使用 表引擎是 ClickHouse 的一大特色。可以说, 表引擎决定了如何存储表的数据。包括: ➢ 数据的存储方式和位置,写到哪里以及从哪里读取数据。 默认存放在/var/lib/clickhouse/data ➢ 支持哪些查询以及如何支持。 ➢ 并发数…

6.vue学习笔记(style绑定+监听器+表单的输入绑定)

文章目录 1.style绑定2.监听器3.表单的输入绑定3.1.复选框3.2.修饰符3.2.1 .lazy 1.style绑定 数据绑定的一个常见需求场景是操纵元素的 CSS style列表,因为style是attribute,我们可以和其他attribute一样使用v-bind将它们和动态字符串绑定。 但是&…

vue-cli创建项目时由esLint校验导致报错或警告的问题及解决

vue-cli创建项目时由esLint校验导致报错或警告的问题及解决 一、万能办法 一、万能办法 //就是在报错的JS文件中第一行写上 /* eslint-disable */链接: https://www.yii666.com/blog/288808.html 其它的方法我遇见了再补充

快速搭建知识付费小程序,3分钟即可开启知识变现之旅

产品服务 线上线下课程传播 线上线下活动管理 项目撮合交易 找商机找合作 一对一线下交流 企业文化宣传 企业产品销售 更多服务 实时行业资讯 动态学习交流 分销代理推广 独立知识店铺 覆盖全行业 个人IP打造 独立小程序 私域运营解决方案 公域引流 营销转化 …

深度学习基础知识神经网络

神经网络 1. 感知机 感知机(Perceptron)是 Frank Rosenblatt 在1957年提出的概念,其结构与MP模型类似,一般被视为最简单的人工神经网络,也作为二元线性分类器被广泛使用。通常情况下指单层的人工神经网络&#xff0c…

ModuleNotFoundError: No module named ‘numpy.testing.decorators‘

文章目录 报错信息报错原因解决方案 关注公众号:『AI学习星球』 算法学习、4对1辅导、论文辅导或核心期刊可以通过公众号或➕v:codebiubiubiu滴滴我 报错信息 ModuleNotFoundError: No module named numpy.testing.decorators 报错原因 新版本已经去…

how2heap-2.23-03-fastbin_dup_consolidate

#include <stdio.h> #include <stdint.h> #include <stdlib.h> #include <string.h>int main() {void* p1 malloc(0x10);strcpy(p1, "AAAAAAAA");void* p2 malloc(0x10);strcpy(p2, "BBBBBBBB");fprintf(stderr, "申请两个…

手机怎么边看视频边记笔记或备忘录?

在这个信息爆炸的时代&#xff0c;我们经常需要通过看培训视频、听网课来不断充实自己。但是&#xff0c;手机屏幕那么小&#xff0c;如何才能在做笔记的同时&#xff0c;又不错过视频的每一个细节呢&#xff1f; 以前&#xff0c;我总是为此头疼。一手拿着手机看视频&#xf…

【嵌入式】About USB Powering

https://www.embedded.com/usb-type-c-and-power-delivery-101-power-delivery-protocol/https://www.embedded.com/usb-type-c-and-power-delivery-101-power-delivery-protocol/ Type-C接口有多强&#xff1f;PD协议又是什么&#xff1f;-电子发烧友网由于Type-C接口自身的强…

c++牛客总结

一、c/c语言基础 1、基础 1、指针和引用的区别 指针是一个新的变量&#xff0c;指向另一个变量的地址&#xff0c;我们可以通过这个地址来修改该另一个变量&#xff1b; 引用是一个别名&#xff0c;对引用的操作就是对变量本身进行操作&#xff1b;指针可以有多级 引用只有一…

Linux Perf 介绍

文章目录 前言 二、安装Perf三、二级命令3.1 perf list3.2 perf record/report3.3 perf stat3.4 perf top 四、使用火焰图进行性能分析4.1 下载火焰图可视化生成器4.2 使用perf采集数据4.3 生成火焰图参考资料 前言 perf是一款Linux性能分析工具&#xff0c;内置在Linux内核的…

virtualbox新建Ubuntu虚拟机

1、下载virtualbox 2、下载Ubuntu镜像 https://ubuntu.com/blog/desktop virtualbox安装好后&#xff0c;点击新建 选择linux类型 选择内存2~4G都行 选择先不添加虚拟硬盘 创建硬盘&#xff0c;管理点击虚拟介质管理 点击创建&#xff0c;选择创建类型为vmdk&#xff0…