https://www.bilibili.com/vide...

背景

零碎调用是内核提供给用户的性能接口,在咱们的零碎中,通常会运行许多零碎调用,其中有很多零碎调用是由咱们的用户程序来触发的(比方C语言中的printf()函数,理论会触发底层的write()零碎调用)。在绝大多数状况下,零碎调用能够在很短的工夫内执行实现并且返回,然而在某些状况下, 零碎调用可能会执行的比较慢,从而成为咱们过程运行时的瓶颈。
对于这些执行较慢的零碎调用咱们能够分为两类,一类是在肯定工夫内执行实现,然而执行工夫过长的零碎调用,咱们能够称之为慢零碎调用;另一类是在肯定工夫内始终未返回的零碎调用,咱们称之为超时零碎调用。在Kindling中,咱们实现了对于这两类零碎调用的捕捉和剖析,并将其报告给下层用户,以便用户洞察零碎调用的状况。

实现原理

内核空间eBPF捕捉零碎调用

首先,咱们能够应用eBPF技术通过内核提供的rawsyscalls目录下的tracepoint来捕捉所有零碎调用的入口和进口(sysenter对应零碎调用的入口,sysexit对应零碎调用的进口),可在/sys/kernel/debug/tracing/events/rawsyscalls/中看到该tracepoint的具体信息。

图1 sys_enter tracepoint的format信息
咱们通过该tracepoint捕捉所有零碎调用,并将每一个零碎调用关联到具体的线程上,发送至用户空间进行进一步解决。

用户空间关联系统调用工夫信息

慢零碎调用

对于一个零碎调用而言,它有一个enter和一个exit(所有零碎调用都只有一个trap,不会呈现堆栈序列的enter和exit),咱们能够在零碎调用enter时获取以后工夫戳,而后在exit时再获取以后工夫戳,此时两个工夫戳的差值就是该零碎调用的理论执行时长,在Kindling中,咱们将该值称为一个慢零碎调用的latency。

图2 慢零碎调用实现示意

超时零碎调用

对于超时的零碎调用,它们在一段时间范畴内并未返回,因而咱们无奈获取到零碎调用的exit信息,目前kindling采取的策略是保护一个以tid为key,syscall信息为value的map,当有零碎调用进入时,在map做一次标记,而后咱们会定时去扫描这个map,如果发现map中有超时的零碎调用则立刻将该零碎调用标记为超时零碎调用。

图3 超时零碎调用实现示意

demo测试

这里咱们写一个简略的demo来测试一下咱们所捕捉到的慢零碎调用 ,咱们写一个最简略的调用nanosleep()零碎调用的例子,让过程睡眠3秒钟,咱们能够在运行的Kindling输入日志中看到捕捉到的信息:


咱们能够看到,Kindling捕捉到了该零碎调用,并给出了其类型,执行时长以及TID、PID等具体信息。

总结

首先,咱们通过eBPF技术和内核提供的零碎调用tracepoint捕捉了所有的零碎调用数据,而后把零碎调用与线程信息做了关联,而后咱们在用户空间对系统调用的enter和exit进行了latency的计算以判断是否为慢零碎调用,特地的是,对于那些超时的零碎调用,咱们无奈间接计算latency,采取了应用map标记零碎调用入口并定时扫描map的策略,从而实现对于超时零碎调用的捕捉。Kindling是一款基于eBPF的云原生可观测性开源工具,旨在帮忙用户更好更快的定界云原生零碎问题,并致力于打造云原生全故障域的定界能力。

Kindling是一款基于eBPF的云原生可观测性开源工具,旨在帮忙用户更好更快的定界云原生零碎问题,并致力于打造云原生全故障域的定界能力。
关注咱们

退出咱们