开发者学堂课程【内核调度器开发入门:内核调度器开发入门】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/1034/detail/15144
内核调度器开发入门
内容介绍
一、Plugsched 简介与背景
二、Plugsched 优势及价值
三、Plugsched 应用场景
四、Plugsched 原理简介
五、Plugsched 操作演示
一、Plugsched 简介与背景
Plugsched Linux 内核调度器热升级,从以下几个方面给大家进行介绍,包括那个Plugsched 的背景价值应用场景以及原理,那么最后进行实际的操作演示。
那么首先给大家简单的介绍一下 Plugsched 以及它的背景,那么什么是 Plugsched ,它是 Linux 的内核调度器子系统热升级的sdk,它可以实现在不重启系统应用的情况下,能够动态的替换内核调度器子系统,而且它具有毫秒级的 downtime ,而且它可以对生产环境中的调度特性动态的进行增删改,然后还可以满足不同的场景或者应用的需求,而且它还支持回滚。
那接下来简单介绍一下 Plugsched 的背景,或者说它想解决什么样的问题,Linux的内核已经发展了有很多年了,它的代码变得是越来越繁重,越来越复杂了,而调度器是内核中最核心的子系统之一,它的结构复杂,而且与其他的子系统紧密耦合,这样就就使得开发和调试调度器变得相对复杂了,另外 Linux 的内核很少增加新的调度类,尤其是不太可能接受非通用或者是场景针对性的调度器,所以上游社区在调度领域发展的其实相对是比较缓慢的。
第二点,内核升级困难,Linux 的内核调度器是内嵌在内核当中的,那么如果有新的调度优化或者是新的调度特性,就需要升级内核才能应用上去,但是内核的发布周期是通常是长达数月之久的,那么这就导致新的调速器没有办法及时的应用到生产环境当中,如果在集群范围内升级新的内核,那么它就会势必牵扯到业务的升级和停机升级,这样一来对于业务方来说,它的代价是比较昂贵的。
第三点 Linux 的内核是没有办法升级子系统的。kpatch 和 livepatch 是函数粒度的热升级方案,它们的可修改能力较弱,它们不能实现复杂的改动,对于 eBPF 当中在内核网络当中广泛应用,但是就目前来说内核调度器还没有支持 eBPF 的 hook,即使是将来支持了,那也只是支持可以实现一些局部策略的改动,它的可修改能力仍然较弱。那么最后一点就是应用场景不同,附加登录策略也不一样,虽然 Linux 社区对内核的调度器的研发理念是能够让它应用在各种场景,不论是云端、移动端还是桌面端,但是应用的种类是非常之多的,而且特征也都不一样,尤其是在云场景下,调度策略的优化是比较复杂的,不存在一劳永逸的调度策略,因此在不同的场景去定制调度器是很有必要的,那么就是对于刚刚讲到的那些困难和限制, Plugsched 应该去做些什么工作,它能够将调度器子系统从内核当中提取出来,以模块的形式对内核调度器进行热升级,那么通过对调度器模块的修改就能够针对不同的应用场景来定制化调度器。
二、Plugsched 优势及价值
接下来说一下 Plugsched 的优势和价值,那么前面提到 Plugsched 能够将调度器子系统从内核代码中提取出来,实际上就是调度器与内核版本的一个解耦,不同的应用场景可以使用不同的调度器,而且 Plugsched 还可以帮助开发人员加速调度问题的修复和策略的优化落地,同时还可以加快调度技术的演进和迭代。
Plugsched 可以将调度器子系统从内核中提取出来,所以它可以支持整个子系统范围的修改,因此它的修改能力是很强的,它能够实现复杂特性和策略的修改,再有非通用或者是场景针对性的调度器可以利用 Plugsched 通过 Rpm 包的形式发布和上线,那么内核中就只需要保留通用调度器就可以了,然后可以让内核代码就是变得比较简洁起来,这样对内核的初学者也有一定的帮助,不需要被其他的各种场景的优化混淆起来,然后代码的维护也变得相对简单一些。再有一点就是 Plugsched 使用起来是很简单的,它提供了容器化的开发环境,可以一键生成调度器 rpm 包,测试和验证的效率也很高,因为它不需要编译内核,生成的调度器包可以安装到系统中就可以进行测试和验证了,还有 Plugsched 可以支持老内核版本,这样线上的存量业务也可以安装新的调度,可以及时享受到新的技术。最后 Plugsched 的性能是比较高效的,它具有毫秒级的 downtime ,然后还有可以忽略的 overhead ,所以 Plugsched 的价值就在于能够让调度器与内核解耦,以模块的形式对内核调度器进行热升级,可针对不同的应用场景定制化调度器,而且最主要的是可以在不中断业务的情况下上线。
三、Plugsched 应用场景
通过前面就已经知道了 Plugsched 的一些优势,那么接下来来介绍一下它的应用场景,Plugsched 相比 kpatch 和 livepatch 可修改能力更强,热升级范围更广,plugsched 是子系统范围的热升级,而后者是函数级别的热升级。
对于 plugsched 而言,无论是 bugfix,还是性能优化,甚至是特性的增、删、改,都可胜任。鉴于 plugsched 较强的可修改能力,它可应用到以下场景。
第一点,Plugsched 可以快速的验证,它可以将调度器从内核中提取出来,可以让开发测试和验证变得敏捷起来,因为它不需要编译整个内核,经过验证的优化或者是特性稳定以后,可以将它们合入到内核主线;
第二点,它可以定制调度器,通过对调度器模块的修改,可以对不同的场景进行定制,然后以 rpm 包的形式发布和维护非通用的调度器;
第三点,它可以统一管理调度器的热补丁,能避免就是多个热补丁之间可能会出现一些冲突而引发的一些故障。
这里讲一个实际的案例是阿里云的,它还遇到了一些问题,那么它们使用的内核是旧的内核版本,这个版本的调度器对 load 的统计算法不合理,导致 CPU 利用率过高,虽然修复补丁已经合入内核主线,但是新内核版本还未发布,而且业务方也不打算更换内核,因为集群中部署了大量的业务,升级内核成本较高。再有一点客户的内核开发人员对其混部业务场景进行了针对性的优化,想将优化内容合入内核主线。但是阿里云内核开发人员经过计算后发现,该优化内容在其它场景中有性能回退,属于非通用优化,因此不允许将优化内容合入主线当中。
那么最终就是客户选择了选择使用了 Plugsched ,它们将优化内容和修复的那些内容全部通过 Plugsched 移植到调度器模块里面,然后最后通过 rpm 包的形式进行规模的部署。那么这个实际案例就可以体现出 Plugsched 与内核发布解耦以及它可以定制化调度器的优势和价值。
四、Plugsched 原理简介
那么现在已经介绍过了 Plugsched 的背景价值和应用场景,那么接下来简单的介绍一下它的实现原理, Plugsched 采用的是模块化的思想,它把调度器子系统从内核中提取出来,因此需要确定调度器子系统的边界,而 Plugsched 提供了边界划分程序,它能够确定调度器模块的边际,然后将调度器模块代码从内核中提取到一个独立的目录当中,那么这样开发人员就可以对提取出来的调度器模块进行代码的修改,然后编译成内存模块,安装该模块就可以动态的替换内核中内嵌的调度器。
那么就对于子系统进行边界划分和代码提取,它是需要处理函数和数据的,那么对于函数而言,Plugsched 将函数分为三个种类,第一类是接口函数,接口函数指的是什么,它是指调度器模块对外呈现了一个接口,那么以这些函数为入口就可以进入到模块当中;第二类是内部函数,内部函数是只能够被接口函数和内部函数调用,那么除了接口函数和内部函数,剩下的就是外部函数,那么就是经过边界划分以后,调度器模块就形成了一个封闭的包,通过替换那个接口函数就可以绕过内核原有的执行逻辑,然后进入到模块里面去执行,这样就可以完成函数的升级。那么对于数据来说,调度器模块默认使用,而且继承了内核中原有的数据,但是对于调度器重要的一些数据,比如说运行队列的状态,这些是可以通过调度器状态重建技术进行处理的,那么这类数据就属于私有数据,当然为了灵活性,那么 Plugsched 也允许手动去定义私有的数据,那么这些定义的私有数据会在模块中保留它的副本,但是需要显示的对这些数据进行初始化,然后就是对于结构体,Plugsched 将调度器相关的结构体中的成员分为内部成员和外部成员,那么内部成员就是指被调度器模块方面的成员,外部成员是指外部方面的成员,对于那个结构体的修改建议只修改结构体中的预留字段。
右边就是整个的一个设计架构,它主要包含了两大部分,第一大部分就是边界划分和代码提取,因为 Linux 调速器是内嵌在内核当中的,由于调度器本身并不是模块,因此需要明确调度器的边界才能将它模块化。边界划分程序会根据边界配置信息(主要包含代码文件、接口函数等信息)从内核源代码中将调度器模块的代码提取到指定目录作为 code base,然后开发人员可在此基础上进行调度器模块的开发。这个配置信息主要包含代码文件,以及接口函数的信息。那么第二部分就是模块的升级过程,调度器模块开发结束以后,它可以生成调度器的 IPM 包,然后可以将它安装到系统当中,安装后会热替换内核中原有的调度器,那么整个升级过程会经历以下几个关键的过程,首先是符号的重定位,它主要用于解析模块对部分内核符号的访问,那么接下来就是栈安全检查啊,就像那个 KPI 一样,函数替换前必须进行栈安全检查,否则会出现一定的当机风险,那么 Plugsched 对栈安全检查进行了并行和二分搜索的优化,提高了检查的效率,从而降低 downtime,然后就是函数替换,用模块中的接口函数动态的替换内核中的函数就可以完成函数替换,最后就是调度器的状态状态重建过程,状态重建技术采用的是一种相对通用的方案,能够自动同步新的和旧的调度器的状态,它可以极大的简化数据状态的一致性维护,然后它可以节约开发人员的时间,还可以减少风险。