当前位置: 首页 > Linux

SysAKApplicationJitterDiagnosis-eBPF又立功了!-龙立科技

时间:2023-04-06 02:33:20 Linux

篇/系统运维SIG编者按:还记得曾经风靡一时的狄仁杰神探系列《他抖任他抖,IO诊断在我手》、《netinfo:揭开网络抖动面纱的神器》、《coredump 瘦身风云》等,带大家领略了角色青桑在网络、IO、内存等领域的无所不能的魅力。今天,系统运维SIG集团重磅回归。我已经引入了内核模块来处理IOramming。今天继续分享eBPF对系统中断的硬处理。跟我一起来看看SysAK是如何打造一款低性能、安全可靠、灵活的关机检测工具吧。1.背景日常业务运营经常受到各种干扰,造成抖动,影响客户体验。干扰源之一是禁用中断。禁用中断时间过长,可能会导致业务流程调度不及时,数据收发延迟。这种干扰在Linux内核中长期存在。相关停机检测手段较少。以下是几个典型的解决方案:1.内核最大off/off中断检查内核本身在系统中所有的off/on中断路径上增加了一个跟踪点TRACE_IRQ_OFF,用于监控系统中所有的on/off中断。优点:中断检测准确全面,同时可以观察到中断的时间甚至堆栈。缺点:取决于CONFIG_IRQSOFF_TRACER内核配置,许多发行版不支持该配置。插入点太多,而且是hotpath,对性能影响很大。2.watchdog/hardlockdetector内核注册一个PMU硬件事件,定时检查自己注册的watchdoghrtimer中断是否有及时更新的时间戳。优点:周期性检测对性能影响不大,适用于系统禁止中断或中断处理存在bug的情况。缺点:监控粒度过大,无法提供更细粒度的系统观察指标。此解决方案不适用于某些没有PMU硬件事件的虚拟化环境。3.trace_irq_handler_exit/trace_irq_handler_exit&&irq_enter/irq_exit在所有中断处理函数的入口/出口处插入跟踪和时间记录。优点:提供有关所有中断处理持续时间的原始数据。缺点:只能观察中断处理的时间,无法监测其他关闭路径,没有阈值触发机制,需要人工后期分析。4.其他开源检查工具Github上也有很多相关的关机检查工具。它们作为.ko模块提供,并使用hrtimer计时器检查过期时间是否超过预期时间。优点:周期采样系统开销小,提供毫秒级的监控粒度。缺点:作为第三方模块提供,稳定性无法保证。hrtimer作为普通中断,只有在中断关闭后才能检测到,不能保证准确性。同时,延迟中断函数时,之前中断的信息会丢失。以上各种检测机制各有千秋,也各有缺陷和不尽如人意的场景。让我们看看SysAK是如何构建一个低性能、安全可靠、灵活的关机检测工具。2.技术选择上述工具采用了不同的技术、实现方式和检测逻辑,导致在不同的场景下有不同的优缺点。对于生产环境来说,监控工具的稳定性和工具的成本是比较重要的考虑因素。因此,在内核热路径中使用存根和使用内核模块都不是理想的选择:前者在某些场景下可能对性能影响较大,后者对内核模块的编码安全性要求非常高,略逊一筹注意容易造成系统宕机,对于批量部署的生产环境来说风险太大。有没有解决以上两个问题的方案或技术手段?当然有。对于内核模块的安全问题,eBPF绝对是目前Linux业界最好的解决方案。它不仅安全而且提供了大量易于使用的库来提高编程体验。对于热路径插桩的性能问题,在关机时间过长的场景下,可以通过定期采样检查来解决,perf事件采样是采样的首选。3、方案设计根据前期背景及应用场景分析,初步完成了技术选型。这时,关机检测工具的大致原理基本有了一个原型:如果系统支持perf硬件采样(HW)事件,首先使用eBPF启动一个内核Timer,定时器周期性产生中断并定期更新一个flagin中断处理函数,然后perfHW事件周期性的检查标志位是否被及时更新,从而判断时钟中断是按时产生还是延迟产生。对于不支持perfHW的系统,我们无法再利用perfHW事件。下一个最好的事情是我们还需要通过eBPF启动内核定时器。定时器中断函数会检查这个定时器中断的超时时间是否和期望的时间不一样,从而判断中断是否有延时。4.技术实现为了实现上述功能,需要解决以下问题:1)如何在eBPF中安装定时器?2)如何在perf事件触发后将我们的检测逻辑hook到perf事件回调处理中?3)如何让eBPF根据系统是否支持perf硬件采样事件来选择不同的检查机制?1.eBPF安装定时器在前面的设计分析中,我们了解到需要使用eBPF来启动内核定时器来做一个中断样例。不幸的是,低于Linux-5.15的eBPF内核版本不支持定时器创建。幸运的是,条条大路通罗马。perfSW事件中的PERF_COUNT_SW_CPU_CLOCK事件是通过Linux内核底层的高精度时钟实现的。因此,只要巧妙地利用这个原理,再结合eBPF,就可以实现我们需要的eBPF定时器。2.eBPFprog处理函数关联perfHW/SW事件溢出回调函数。虽然perf在用户态提供了perf_event_open系统调用和ioctl方法来创建perfHW和perfSW事件样本(比如之前的PERF_COUNT_SW_CPU_CLOCK事件,以及perf硬件事件PERF_COUNT_HW_CPU_CYCLES,通过manperf_event_open查看更详细的信息),但是传统的用户态perf无法在这些事件触发后在内核中实现我们想要的hack动作,比如执行我们需要关闭中断检测的回调函数。在内核代码或内核模块中调用perf_event_create_kernel_counter函数,将我们需要的回调函数注册到perf事件的overflow_handler中,从而达到我们的目的。然而,这种困境随着eBPF的出现而改变了。perfevent为ebpf提供了专用的ioctl通道,让ebpf在内核中发挥其超强的威力(别忘了eBPF代码本质上还是在内核中执行的)。而eBPF与用户态有着天然的“亲和力”,使得用户态可以很方便的通过ioctl将自己的回调处理逻辑hook到perf事件上。在代码层面,使用:ioctl(PERF_EVENT_IOC_SET_BPF)`将eBPFprog处理函数注册到perf事件的overflow_handler回调处理中。3.系统是否支持perfHW事件选择不同的检查策略。通过perf_event_open系统调用的返回值判断系统是否支持perfHW事件。同时在eBPF中定义两组prog,如果支持perfHW,则附加HW事件检测的prog,否则附加SW事件检测的prog。五、操作过程本章主要对工具的实现进行了详细的分解。下图是一个简单的工具运行示意图:整个过程如下:1.首先分析参数,包括阈值、运行时间、日志记录文件规格等参数对的分析。2、进行eBPF初始化,这一步主要是加载eBPF程序。3.安装eBPF事件。首先创建一个perf事件,然后将ebpfprogattach关联到perf事件上,最后创建一个poll事件并监听。同时perf事件开始工作,触发perf事件后会调用eBPFprog程序运行。在eBPFprog程序检测到阈值事件后,它会唤醒用户模式以进行轮询任务。4.用户态轮询被唤醒后,将结果写入日志文件。6.工具使用安装SysAK后,使用如下命令:sysakirqoff[--help][-tTHRESH(ms)][-fLOGFILE][duration(s)]-t:关闭中断的阈值,单位是毫秒-f:指定irqoff结果记录的文件。duration:工具的运行时间,如果不指定,默认一直运行。通过内核模块创建一个worker,构造一个长期不中断的场景。下面是irqoff捕获的结果。TIME(irqoff)CPUCOMMTIDLAT(us)2022-05-05_11:45:193kworker/3:03795311000539<0xffffffffc04e2072>owner_func<0xffffffff890b1c5b>process_one_work<0xffffffff890b1eb9>worker_thread<0xffffffff890b7818>kthread<0xffffffff89a001ff>ret_from_fork结果中有几个部分:第一行是日志头。一共5列,从左到右分别是时间戳(模块信息)、最长关机时长的CPU、最长关机时长的当前线程ID、总关机时延。第二行对应日志头的实际信息。第三行及以下是捕获中断的现场堆栈信息,方便下一步分析源码。相关链接地址:Gitee代码仓库:https://gitee.com/anolis/sysak系统运维SIG:https://openanolis.cn/sig/sysom——完——