对于一个拥有成千上万台服务器的公司,Linux内核缺陷导致的死机屡见不鲜。每次内核升级意味者服务器重启、业务中断以及繁重的运维工作。在云平台里一台宿主机往往运行多个云主机,每一次重启都意味着中断其上运行的所有云主机。
UCloud云平台运行着大量的宿主机,如何应对呢?在UCloud,所有内核缺陷都是借助热补丁免重启修复的。热补丁是指动态修改运行中内核相应的指令区域以修复缺陷,即给运行中内核打上二进制补丁。UCloud的热补丁技术基于多年前的开源ksplice加以定制优化而来,现已累计进行过5万台次免重启修复。
热补丁技术基本流程如下图:
二进制形式的热补丁模块由ksplice程序从源码补丁编译生成,其结果包括带缺陷的二进制指令和正确的二进制指令(这些二进制按函数级别组织);模块加载后,自动定位到内核的缺陷处并以正确的二进制指令替换缺陷指令,从而完成免重启修复。
上面是简要描述,实际整个过程相当复杂,有两点比较重要:
热补丁生成:要结合运行中内核对应的源码树和源码补丁编译出二进制形式的缺陷指令和修复指令,这里要按函数级别组织。我们修改了GCC编译器以达到目的;
热补丁打入前检查:热补丁中带有的缺陷指令用于和运行中内核的缺陷处进行二进制比较,根据差异确定能否热修复;不仅如此,整个内核被stop_machine并检测各个线程栈不含待修复的函数,之后才能安全地进行二进制替换。
这里,频繁调用的内核函数(如hrtimer, schedule)就几乎每次出现在某个线程栈。而整个内核stop_machine期间也是业务中断期间。为了能对频繁函数热补丁和为了避免中断,我们对热补丁工具做了相当多的优化。实际上为了支持回滚、支持模块、支持二次热补丁、支持数据结构改动,背后需要解决的问题多得多。
除了对Linux内核进行热补丁,还扩展这项技术,对用户态进程也进行过热补丁修复。基本原理类似,也是对二进制指令动态替换达到免重启修复,并支持对进程运行中内存的数据结构进行修改。 |