加入收藏 | 设为首页 | 会员中心 | 我要投稿 温州站长网 (https://www.0577zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 编程要点 > 资讯 > 正文

Part1 探针的原理及应用

发布时间:2021-06-02 06:25:48 所属栏目:资讯 来源:互联网
导读:这篇文章介绍的探针像调试程序时候打断点一样,只不过打断点是有交互的,同时是以字节码形式运行在内核虚拟机(BPF)中的。 一、异常 异常(exception)就是控制流中的突变,用来响应处理器状态中的某些变化。理解异常有助于理解探针技术。下图 所示处理器在

这篇文章介绍的探针像调试程序时候打断点一样,只不过打断点是有交互的,同时是以字节码形式运行在内核虚拟机(BPF)中的。

一、异常

异常(exception) 就是控制流中的突变,用来响应处理器状态中的某些变化。理解异常有助于理解探针技术。下图 所示处理器在执行时执行时,发生了一个重要的变化,我们把它称为事件(event)。事件可能与当前指令直接相关,如缺页异常,算术溢出,尝试除以 0 。也有可能无关如定时器产生信号,I/O 完成。在任何情况下处理器通过异常表进行一个间接过程调用到专门的异常处理程序来处理。

异常可以分成四类: 中断(interrupt), 陷阱(trap),故障(fault)和终止(abort)。

中断是异步发生的,是来自处理器外部 I/O (鼠标,键盘,网卡等)设备信号的结果。 硬件中断不是由任何一条专门的指令造成,从这个意义讲它是异步的。剩下的异常类型(陷阱,故障,终止)是同步发生的,是执行当前指令的结果。我们把这种指令称为故障指令。

陷阱是有意的异常,是程序员“主动”触发的,就像是自己在代码埋下一个陷阱一样。 陷阱最常见的用户是进程发起系统调用,通过 INT 从用户态 trap 进内核态。

故障由错误情况引起,能够被故障处理程序修正。 当故障发生时,处理器讲控制转移给故障处理程序。例如当缺页异常发生时,故障处理程序可以从磁盘中间对应的页 swap 进物理内存。

终止,是不可恢复的致命错误造成的结果,通常是一些硬件错误。 程序员平常调试代码时,给程序添加断点,让程序在我们想要的地方停住。调试器能够随心所欲控制程序运行,主要靠软件中断。软件断点在 X86 系统中就是指令 INT 3。当程序执行到 INT 3 指令时,会引发软件中断。这就是上文提到的陷阱。不同于我们在 Visual Studio 和 GDB 中交互式的断点,如果程序在 trap 发生时,自动执行预定义和 handle 记录和统计运行情况,不影响程序的正常运行,达到观察 MySQL 的目的。

二、探针

为了捕捉程序运行情况,我们在程序中设置一些 “ 陷阱 ”,并设置处理程序,我们称之为探针。有的探针是在代码中预定义的,有的是在运行时动态添加的。

1. 静态探针

静态探针是事先在程序中定义好,并编译到程序或者内核的探针。

静态探针只有被开启时才会运行,不开启就不会运行,常见的静态探针包括内核中的跟踪点(tracepoints)和 USDT(Userland Statically Defined Tracing)探针。tracepoints 在代码中埋下钩子,在运行时调用相连接的探针。

它有“打开”(已连接探针)和“关闭”(未连接探针)两种状态。

当跟踪点处于“关闭”状态时,它没有任何作用,只增加微小的时间损失(检查分支的条件)和空间损失。当跟踪点为“ 打开”时,每次在调用者的执行上下文中执行跟踪点时,都会调用相连接的探针。探针函数执行完后,将返回到调用方。USDT和tracepoint类似,只不过是用户态的,在代码中插入DTRACE_PROBE()即可。

2. 动态探针

动态探针是应用程序没有定义,在程序运行时动态添加的探针。

动态探针类似于异常处理机制,当系统产生一个异常,就会跳转去执行对应的 handle。动态探针会在函数入口和出口插入一些断点,程序执行到断点时候会去执行对应的 handle,从而达到观测应用程序的目的。这里的中断是指 trap(陷阱),在X86体系是int3指令。

KProbes 是 Linux 内核探针,可以用于监视生产系统中的事件。您可以使用它来解决性能瓶颈,记录特定事件,跟踪问题等。

KProbes 能实时在内核代码中插入中断指令,虽然这听上去有点不可思议,实际上 KProbes 做了很多安全性保证,例如 stop_machine 用于确保其他CPU在被修改时停止执行。

实际上 kprobes 最大风险是给一些调用十分频繁的函数加上探针,如在网络模块中,频繁中断可能造成一定的性能风险。KProbe需要定义 pre-handler 和 post-handler,当被探测的指令要被执行时,先执行pre-handler程序。同样,当被探测指令执行之后立即执行post-handler。

uprobes 是Linux提供用户态的动态探针,合并于2012年7月发布的 Linux 3.5 内核中。uprobes 和 kprobes 十分相似,用于用户态。

三、BPF

BPF(Berkeley Packet Filter) 最早开发在 BSD 操作系统中,是 TCP/IP 包过滤的工业标注,被 tcpdump 使用。

它的工作方法有点特别: 用户自定义包过滤表达式,然后注入内核中的 BPF 中运行 ,这样的好处就是在内核进行过滤而不是将包拷贝到用户态,避免大量数据从内核态拷贝到用户态,因此具有较好的性能。

后来出现了eBPF(extend BPF), eBPF 有自己的语言,用户自己编写程序编译后通过 BPF 调用注入到内核的 BPF 虚拟机中运行,可以安全访问内核内存,它使得内核变成可编程。运行在内核中因为不需要把数据拷贝到用户空间往往具有比较高的性能,因此 BPF 被很多性能追踪工具使用。

(编辑:温州站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读