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,一经查实,立即删除!

相关文章

【Linux】Linux 基础命令 crontab命令

1.crontab命令 crond 是linux下用来周期性的执行某种任务或等待处理某些事件的一个守护进程,与windows下的计划任务类似,当安装完成操作系统后,默认会安装此服务 工具,并且会自动启动crond进程,crond进程每分钟会定期检查是否有要执行的任务,如果有要执行的任务,则自动…

鸿蒙应用中图片的显示(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…

程序员常用的学习网站有哪些?10大网站整理

1、CSDN -专业IT技术社区(https://www.csdn.net/) 中国专业IT社区CSDN (Chinese Software Developer Network) 创立于1999年,致力于为中国软件开发者提供知识传播、在线学习、职业发展等全生命周期服务。全力为IT开发者打造分享技术心得、讨…

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

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

客户回馈机制常用的ChatGPT通用提示词模板

客户回馈计划制定:如何制定客户回馈计划,明确回馈的目标和策略? 回馈方式选择:如何选择合适的回馈方式,如积分、折扣、礼品等? 回馈标准设定:如何设定回馈的标准,确保公平性和合理…

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

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

Java实战:Swing版记事本

文章目录 一、实战概述二、运行效果三、涉及知识点四、实现步骤(一)创建Java项目(二)准备图片素材(三)存放帮助文件(四)创建包与类1、继承JFrame类2、声明变量3、添加主方法4、编写初始化图形用户界面方法5、编写保存文件方法 - saveFile()6、编写打开文件方法 - openF…

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 本文说…

一个简易的SpringAOP实例

1、引入依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.…

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

&#x1f389;&#x1f389;欢迎来到我的CSDN主页&#xff01;&#x1f389;&#x1f389; &#x1f3c5;我是Java方文山&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;推荐给大家我的专栏《电商项目实战》。&#x1f3af;&#x1f3af; &am…

芯片SIC8833可开发打气泵方案

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

orangepi 3b安装 miniconda,后安装 opencv-python

参考 https://docs.conda.io/projects/miniconda/en/latest/ 下载miniconda wget https://repo.anaconda.com/miniconda/Miniconda3-py311_23.11.0-2-Linux-aarch64.sh -O ~/miniconda3/miniconda.sh mkdir -p ~/miniconda3 #wget https://repo.anaconda.com/miniconda/Mi…

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

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

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

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

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

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

easycode 插件配置文件

easycode是一个idea生成文件的插件&#xff0c;以下是我的一个项目中配置信息&#xff0c;需要的可以拿走&#xff0c;保存成json文件导入即可 {"author" : "XXX","version" : "1.2.8","userSecure" : "","…

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

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

spark解决scala.matchError问题

在代码里处理match问题的时候报scala.matchError问题 处理方式很简单 我们在做match{case }的时候&#xff0c;有时候会忽略需要加一个总管所有未匹配上的情况&#xff0c;也就是缺少 case _ > … 这样的条件&#xff0c;加上就好了&#xff0c;基本用不到这一层&#xff0c…