图解kubernetes资源QOS机制实现原理
QOS是k8s中一种资源保护机制,其主要是针对不可压缩资源比如的内存的一种控制技术,比如在内存中其通过为不同的Pod和容器构造OOM评分,并且通过内核的策略的辅助,从而实现当节点内存资源不足的时候,内核可以按照策略的优先级,优先kill掉哪些优先级比较低(分值越高优先级越低)的Pod,今天来分析下背后的实现
1.关键基础特性
1.1 一切皆文件
在Linux中一切皆文件,控制CGroup本身也是通过配置文件进行的,这是我创建的一个内存Lmits为200M的Pod的容器的配置
# pwd /sys/fs/cgroup # cat ./memory/kubepods/pod8e172a5c-57f5-493d-a93d-b0b64bca26df/f2fe67dc90cbfd57d873cd8a81a972213822f3f146ec4458adbe54d868cf410c/memory.limit_in_bytes 209715200
1.2 内核内存配置
这里我们重点关注内存相关的两个配置:VMOvercommitMemory其值为1,表示运行分配所有的物理内存资源,注意不包括SWAP资源VMPanicOnOOM其值为0:表示当内存不足的时候触发oom_killer进行选择部分进程进行kill,QOS也是通过影响其kill流程来实现的
func setupKernelTunables(option KernelTunableBehavior) error { desiredState := map[string]int{ utilsysctl.VMOvercommitMemory: utilsysctl.VMOvercommitMemoryAlways, utilsysctl.VMPanicOnOOM: utilsysctl.VMPanicOnOOMInvokeOOMKiller, utilsysctl.KernelPanic: utilsysctl.KernelPanicRebootTimeout, utilsysctl.KernelPanicOnOops: utilsysctl.KernelPanicOnOopsAlways, utilsysctl.RootMaxKeys: utilsysctl.RootMaxKeysSetting, utilsysctl.RootMaxBytes: utilsysctl.RootMaxBytesSetting, }
2.QOS打分机制与判定实现
QOS打分机制主要是根据Requests和limits里面的资源限制来进行类型判定与打分的,我们就来快速看下这部分的实现
2.1 根据容器判定QOS类型
2.1.1 构建容器列表
遍历所有的容器列表,注意这里会包含所有的初始化容器和业务容器
requests := v1.ResourceList{} limits := v1.ResourceList{} zeroQuantity := resource.MustParse("0") isGuaranteed := true allContainers := []v1.Container{} allContainers = append(allContainers, pod.Spec.Containers...) // 追加所有的初始化容器 allContainers = append(allContainers, pod.Spec.InitContainers...)
2.1.2 处理Requests和limits
这里遍历所有的Requests和Limits限制的资源,分别加入到不同的资源集合汇总,其中判定是不是Guaranteed主要是根据limits里面的资源是否包含CPU和内存两种资源,都包含才可能是Guaranteed
for _, container := range allContainers { // process requests for name, quantity := range container.Resources.Requests { if !isSupportedQoSComputeResource(name) { continue } if quantity.Cmp(zeroQuantity) == 1 { delta := quantity.DeepCopy() if _, exists := requests[name]; !exists { requests[name] = delta } else { delta.Add(requests[name]) requests[name] = delta } } } // process limits qosLimitsFound := sets.NewString() for name, quantity := range container.Resources.Limits { if !isSupportedQoSComputeResource(name) { continue } if quantity.Cmp(zeroQuantity) == 1 { qosLimitsFound.Insert(string(name)) delta := quantity.DeepCopy() if _, exists := limits[name]; !exists { limits[name] = delta } else { delta.Add(limits[name]) limits[name] = delta } } } if !qosLimitsFound.HasAll(string(v1.ResourceMemory), string(v1.ResourceCPU)) { // 必须是全部包含cpu和内存限制 isGuaranteed = false } }
2.1.3 BestEffort
如果Pod里面的容器没有任何requests和limits的限制则就是BestEffort
if len(requests) == 0 && len(limits) == 0 { return v1.PodQOSBestEffort }
2.1.4 Guaranteed
要是Guaranteed必须是资源相等,并且限定的数量相同
// Check is requests match limits for all resources. if isGuaranteed { for name, req := range requests { if lim, exists := limits[name]; !exists || lim.Cmp(req) != 0 { isGuaranteed = false break } } } if isGuaranteed && len(requests) == len(limits) { return v1.PodQOSGuaranteed }
2.1.5 Burstable
如果不是上面两种就是最后一种burstable了
return v1.PodQOSBurstable
2.2 QOS OOM打分机制
2.2.1 OOM打分机制
其中guaranteedOOMScoreAdj是-998其实这跟OOM实现有关系,一台node节点上主要是三部分组成:kubelet主进程、docker进程、业务容器进程,而OOM的打分里面-1000表示该进程不会被oom所kill, 那一个业务进程最少也就只能是-999因为你不能保证自己的业务永远不会出现问题,所以在QOS里面-999其实就是kubelet和docker进程所保留的,剩下的才能作为业务容器分配(分值越高越容易被kill)
// KubeletOOMScoreAdj is the OOM score adjustment for Kubelet KubeletOOMScoreAdj int = -999 // DockerOOMScoreAdj is the OOM score adjustment for Docker DockerOOMScoreAdj int = -999 // KubeProxyOOMScoreAdj is the OOM score adjustment for kube-proxy KubeProxyOOMScoreAdj int = -999 guaranteedOOMScoreAdj int = -998 besteffortOOMScoreAdj int = 1000
2.2.2 关键Pod
关键Pod是一种特殊的存在,它可以是Burstable或者BestEffort类型的Pod,但是OOM打分却可以跟Guaranteed一样,这种类型的Pod主要包含三种:静态Pod、镜像Pod和高优先级Pod
if types.IsCriticalPod(pod) { return guaranteedOOMScoreAdj }
判定实现
func IsCriticalPod(pod *v1.Pod) bool { if IsStaticPod(pod) { return true } if IsMirrorPod(pod) { return true } if pod.Spec.Priority != nil && IsCriticalPodBasedOnPriority(*pod.Spec.Priority) { return true } return false }
2.2.3 Guaranteed与BestEffort
这两种类型都有各自默认的值分别为Guaranteed(-998)和BestEffort(1000)
switch v1qos.GetPodQOS(pod) { case v1.PodQOSGuaranteed: // Guaranteed containers should be the last to get killed. return guaranteedOOMScoreAdj case v1.PodQOSBestEffort: return besteffortOOMScoreAdj }
2.2.4 Burstable
其中关键的一行就是:oomScoreAdjust := 1000 - (1000memoryRequest)/memoryCapacity,从这个计算里面可以看出,如果我们申请的资源越多,那么 (1000memoryRequest)/memoryCapacity这个里面计算出来的时机值就会越小,即最终结果就越大,其实也就表明如果我们占用的内存越少,则打分就越高,这类容器就相对比较容易被kill
memoryRequest := container.Resources.Requests.Memory().Value() oomScoreAdjust := 1000 - (1000*memoryRequest)/memoryCapacity // A guaranteed pod using 100% of memory can have an OOM score of 10. Ensure that burstable pods have a higher OOM score adjustment. if int(oomScoreAdjust) < (1000 + guaranteedOOMScoreAdj) { return (1000 + guaranteedOOMScoreAdj) } // Give burstable pods a higher chance of survival over besteffort pods. if int(oomScoreAdjust) == besteffortOOMScoreAdj { return int(oomScoreAdjust - 1) } return int(oomScoreAdjust)
好了今天就到这里,看之前还很懵逼,看完有种豁然开朗的感觉,还是那句话说的对,源码面前了无秘密,加油
k8s源码阅读电子书地址: https://www.yuque.com/baxiaoshi/tyado3
> 微信号:baxiaoshi2020 > 关注公告号阅读更多源码分析文章 > 更多文章关注 www.sreguide.com > 本文由博客一文多发平台 OpenWrite 发布
低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
图解kubernetes资源扩展机制实现(下)
昨天我们介绍了k8s中资源插件机制的核心关键组件,今天我们继续来看下各个组件是如何进行通信的,以及k8s中针对事件处理背后的关键设计 1.PluginManager PluginManager是一个上层组件,其内部包含了上篇文章中的关键组件,并且协调其内部数据流,而且还提供针对不同插件的具体的控制器 1.1 核心数据结构 核心结构里面其实就是按照数据流来进行设计的,首先需要一个感知插件desiredStateOfWorldPopulator用于感知后端服务的创建或者删除,然后将感知到的事件加入到desiredStateOfWorld期望状态缓存,由reconciler负责期进行底层的注册和下线,并且将结果存储到actualStateOfWorld实际状态缓存 type pluginManager struct { // 插件感知 desiredStateOfWorldPopulator *pluginwatcher.Watcher // 协调器插件 reconciler reconciler.Reconciler // 实际状态缓存 actualStateOfWorld cache.A...
- 下一篇
【小程序_02】布局方式
一、流式布局 1. 移动端基础 1.1 浏览器现状 国内的UC和QQ,百度等手机浏览器都是根据Webkit修改过来的内核,国内尚无自主研发的内核,就像国内的手机操作系统都是基于Android修改开发的一样。 移动端主流浏览器,处理Webkit内核浏览器即可 (H5C3 支持得相当好) 1.2 常见移动端屏幕尺寸 2. 视口 视口(viewport)就是浏览器显示页面内容的屏幕区域。 视口可以分为布局视口、视觉视口和理想视口 2.1 布局视口 (layout viewport) 一般移动设备的浏览器都默认设置了一个布局视口,用于解决早期的PC端页面在手机上显示的问题。iOS, Android基本都将这个视口分辨率设置为 980px,所以PC上的网页大多都能在手机上呈现,只不过元素看上去很小,一般默认可以通过手动缩放网页。 将其缩放 2.2 视觉视口 (visual viewport) 它是用户正在看到的网站的区域。注意:是网站的区域。我们可以通过缩放去操作视觉视口,但不会影响布局视口,布局视口仍保持原来的宽度。 2.3 理想视口 (ideal viewport) 为了使网站在移动端有最...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- MySQL8.0.19开启GTID主从同步CentOS8
- Mario游戏-低调大师作品
- CentOS关闭SELinux安全模块
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- Docker安装Oracle12C,快速搭建Oracle学习环境
- Red5直播服务器,属于Java语言的直播服务器
- CentOS8编译安装MySQL8.0.19
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- Springboot2将连接池hikari替换为druid,体验最强大的数据库连接池