零代价修复海量服务器的内核缺陷——UCloud内核热补丁技术揭秘

下述为UCloud资深工程师邱模炯在InfoQ架构师峰会上的演讲——《UCloud云平台的内核实践》中很是受关注的内核热补丁技术的一部分。给你们揭开了UCloud云平台内核技术的神秘面纱。服务器

 

如何零代价修复海量服务器的Linux内核缺陷?数据结构

 

对于一个拥有成千上万台服务器的公司,Linux内核缺陷致使的死机家常便饭。让工程师们纠结的是,到底要不要经过给服务器升级内核来修复缺陷?升级意味者服务器重启、业务中断以及繁重的准备工做;不升级则担忧服务器死机,一样形成业务中断和繁重的善后工做。架构

 

而在今天的云计算时代,一台宿主机每每运行多个云主机,每一次重启不论是主动升级仍是被动死机,都意味着中断其上运行的全部云主机。所以,宿主机内核缺陷的修复更加棘手。运维

 

而做为一个支撑着上万家企业用户IT基础架构的云服务商,UCloud云平台上的海量宿主机又是如何修复内核缺陷的呢?函数

 

邱模炯透露,若是按照传统的重启方式来修复,那么不管是对于UCloud或是用户,都意味着繁重的运维和业务中断。可是,UCloud经过“内核热补丁技术”——即给运行中的内核打上二进制补丁,UCloud已经作到了零代价免重启修复海量服务器的内核缺陷!目前为止,UCloud对所发现的上游内核10+个缺陷全以热补丁方式修复,累计数万台次,无一例失败且无任何反作用;理论上避免了相应次数的宿主机重启及所隐含的云主机业务中断。这项技术在UCloud已经成熟。工具

 

UCloud内核热补丁技术揭秘post

 

UCloud的热补丁技术基于多年前的开源ksplice加以定制优化而来,经过加载一个特殊准备的热补丁模块来修复内核。其过程以下图所示:性能

 

 

 

热补丁模块由ksplice程序编译生成,包含有缺陷的二进制指令和修复后的二进制指令(这些二进制按函数级别组织);模块加载后,自动定位到内核的缺陷处并以修复指令动态替换缺陷指令。优化

 

ksplice热补丁模块的建立原理见下图:网站

 

首先获取一份运行中内核对应的源码并编译出二进制,称为pre对象;打上源码补丁再次编译,称为post对象。而运行中的内核二进制称为run对象。post和pre逐条指令比较并找出存在差别的函数,以后把这些差别合并为内核模块形式的热补丁。

 

建立好的热补丁模块在加载到内核时还会作些检验工做:对比pre和run对象。只有经过检验才能成功加载进内核。pre-run比较的目的是为了辨别编译过程差别是否过大以至于不能打入post对象的热补丁;更重要的是,从pre-run差别中提取的关键信息才能把post对象的热补丁顺利打入运行中内核。

 

热补丁模块加载到内核后,便自动进行内核修复。也就是使用热补丁中的二进制指令替换有缺陷的二进制指令。这里ksplice利用了Linux内核的stop_machine机制:中止全部CPU的执行,只留下主CPU进行二进制指令替换。值得注意的是,stop_machine后若是发现任何一个线程栈的内容与热补丁存在冲突,就须要退出指令替换以免系统崩溃。因此并不是全部热补丁都能打入内核,有些频繁使用的内核函数(如schedule, hrtimer相关)就没法热补丁,重试次数再多也无济于事。

 

ksplice同时支持对内核和模块进行热补丁,也支持热补丁后叠加热补丁,灵活方便。不过也存在一些缺陷:stop_machine期间整个系统处于中断状态,虽然单次中断小于1ms,但有些时候屡次重试的累计中断也不小;另外,有些频繁使用的函数没法打入热补丁。

 

kpatch和kgraft

kpatch和kgraft均是近期新出现的内核热补丁技术,前者属于Redhat公司,后者SuSE。二者原理和ksplice大体相同,都想合并进Linux内核,内核社区正在争议对比。

 

kpatch原理和前面讲的ksplice很接近。最大的区别在于二进制指令替换,stop_machine中止全部CPU执行后ksplice直接修改,而kpatch则借助ftrace机制来触发替换。目前的实现上,kpatch有较大局限性,不支持对模块打热补丁,不支持函数静态变量等。

 

kgraft原理也基本同样。主要的差别有两点:

 

1)热补丁生成方法不一样;

2)热补丁打入内核过程里kgraft用到了RCU渐进方法。得益于RCU方法,kgraft无需像ksplice和kpatch同样调用stop_machine并检查线程栈的冲突。不过它的缺点也缘于RCU,涉及到数据结构改变时,kgraft更难经过编写辅助代码打入热补丁,这限制了kgraft的应用范围。

 

有关kpatch和kgraft的详细状况请分别参考Redhat和SuSE网站的技术资料。

 

除了免重启修复,热补丁还用于内核开发过程的性能分析和故障定位。好比,加上性能统计代码生成热补丁,就能够在线分析感兴趣的性能问题;加入额外调试代码捕捉运行中内核的异常。这些很是有用,更是海量服务器里捕捉不可重现内核异常的不二法宝。因为热补丁不须要重启服务器,既可打入也可撤销,因此不会有反作用。

 

UCloud对开源Ksplice的优化主要在如下三个方面:

 

支持高版本内核

热补丁技术与内核紧密耦合。不一样版本的内核在指令结构体,符合表结构体和一些特性上(好比早期内核没有ftrace)有所不一样,直接影响热补丁成败。UCloud研究了各版本内核的区别,使得同一份ksplice支持各个版本的Linux内核。值得一提的是,解决了ftrace与ksplice不兼容的问题。

 

容许热修复频繁调用的函数

无论什么样的热补丁技术,两种类型的内核函数难以热补丁:频繁使用的内核函数如schedule, hrtimer;常常处于线程栈内核部分顶部的函数,如sys_poll, sys_read。UCloud更改了ksplice相关内核代码和用户态工具,成功解除了这些限制,好比UCloud现网服务器已打入了三个hrtimer热补丁。

 

减小业务中断时间

ksplice是在stop_machine后替换二进制指令的。虽然单次stop_machine对业务形成的中断在一毫秒左右,但有些频繁使用的内核函数须要大量重试才能碰到合适的热补丁时机,因而会形成最长达上百毫秒的中断。UCloud在此作过一点优化,使得业务中断时间控制在十毫秒级别。

 

海量服务器环境下热补丁技术可用来零代价且无反作用地修复内核缺陷,并且内核开发也因热补丁能走得更远更好。之前由于缺少辅助分析手段和害怕内核BUG,即便适合在内核实现的特性也被告诫移到用户态实现,然而有了热补丁,相关观念也能够适当调整,内核开发也能够更加大胆和跳脱。

相关文章
相关标签/搜索