camunda 流程执行追踪_动态追踪技术原理

动态追踪技术是软件调试的高级手段,能帮助快速定位生产系统问题。本文介绍了动态追踪技术的原理,包括异常、静态探针、tracepoints、USDT、动态探针(kprobes、uprobes)以及硬件追踪。通过在程序中设置探针,可以在不影响系统运行的情况下,实现对软件系统的无损观测,类似于医生给患者拍片子。
摘要由CSDN通过智能技术生成

什么是动态追踪

动态追踪技术是一种高级的软件调试技术。它可以帮助你快速定位和解决生产系统中问题。互联网快速发展,软件系统规模越来越大,系统的业务逻辑越来越复杂。慢慢的,我们的程序员丧失了对软件系统的洞察力和掌控力。很多人处理问题的方法是错误的,一旦软件系统出现问题,立马去搜索对应的 case,一般情况下你踩过的坑应该有人已经踩过了,如果你运气比较好的话,能够很快 fix 掉问题。但是这些热心网友的解决方案不一定适合你,我们的系统产生问题的原因不尽相同。更糟糕的是由于你不断试错,可能已经破坏现场,离正确答案越来越远。我们应该像医生一样,了解患者的病历,给病人拍片子,去观察病人,找到问题再对症下药。

日志是一种很好的追踪工具。我们可以用 log.error 记录一些系统出现的错误事件,包含错误的产生时间,函数调用栈等详细信息,这个方便我们对问题的处理,也可以使用 log.info 记录一些我们感兴趣的运行信息,便于我们对应用系统的观察。日志往往掺杂大量无效数据,同时如果自己感兴趣的内容日志没有记录下来就比较麻烦。而且日志是一种侵入性的,混合在我们应用程序的代码里面,修改代码需要重新打包,发布,重启服务。更重要的是重启服务很有可能破坏现场。

有没有什么观测系统的方法可以按照自己需要捕获自己感兴趣的事件嗯,不需要修改代码,不需要重启服务,对服务性能损失很小。就像医生给病人拍片子一样,基本对患者健康没有损失,但可以很好观察病人体内情况。我们也可以给软件系统"拍片子",在给系统性能带来极少损失的前提下实现对系统的观察, 这就是今天要介绍的动态追踪技术。

异常

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

21d5f2b48cb1ac2cb8df8af3180fdb8d.png

图1 异常刨析

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

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

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

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

终止 是不可恢复的致命错误造成的结果,通常是一些硬件错误。

程序员平常调试代码时,给程序添加断点,让程序在我们想要的地方停住。调试器能够随心所欲控制程序运行,主要靠软件中断。软件断点在 X86 系统中就是指令 INT 3,它的二进制代码opcode 是 0xCC。当程序执行到 INT 3 指令时,会引发软件中断。这就是上文提到的陷阱。不同于我们在 Visual Studio 和 GDB 中交互式的断点,如果程序在 trap 发生时,自动执行预定义和 handle 记录和统计运行情况,不影响程序的正常运行,从而达到医生拍片子的效果。

常见的动态追踪技术原理

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

静态探针

静态探针是事先在程序中定义好,并编译到程序或者内核的探针。静态探针只有被开启时才会运行,不开启就不会运行,常见的静态探针包括内核中的跟踪点(tracepoints)和 USDT(Userland Statically Defined Tracing)探针。

tracepoints

tracepoints 在代码中埋下钩子,在运行时调用相连接的探针。它有"打开"(已连接探针)和"关闭"(未连接探针)两种状态。当跟踪点处于"关闭"状态时,它没有任何作用,只增加微小的时间损失(检查分支的条件)和空间损失。当跟踪点为" 打开"时,每次在调用者的执行上下文中执行跟踪点时,都会调用相连接的探针。探针函数执行完后,将返回到调用方。 可以将 tracepoints 放置在代码中的重要位置, 用于应用观察和性能统计。如果用户准备为 kernel 加入新的 tracepoint,每个 tracepoint 必须以下列格式声明:

c366839cd4dd238152bb5434753320cc.png

上面的宏定义了一个新的 tracepoint 叫 tracepoint_name。与这个 tracepoint 关联的 probe 函数必须与 TPPROTO 宏定义的函数 prototype 一致,probe 函数的参数列表必须与TPARGS 宏定义的一致。

使用 perf list 查看内核中预定义的 tracepoints, 例如查看磁盘 I/O 相关的 tracepoints

8b73d0c123b2bc679fe39dda659cb114.png

USDT

USDT和tracepoint类似,只不过是用户态的,在代码中插入DTRACE_PROBE()即可。

动态探针

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

kprobes

KProbes 是 Linux 内核的调试机制,也可以用于监视生产系统中的事件。您可以使用它来解决性能瓶颈,记录特定事件,跟踪问题等。KProbes 由 IBM 开发,是另一个名为 DProbes 的跟踪工具的基础开发而来。 KProbes 的实现取决于处理器体系结构,它根据执行它的体系结构使用略有不同的机制。我们仅讨论X86体系结构。

KProbe需要定义 pre-handler post-handler,当被探测的指令要被执行时,先执行pre-handler程序。同样,当被探测指令执行之后立即执行post-handler。

740f35871717a3bcedb27634b901bc25.png

kprobes 工作流程如下所示:

1、 当用户注册一个探测点后,kprobe 首先备份被探测点的对应指令,然后将原始指令的入口点替换为断点指令,该指令是 CPU 架构相关的,如 i386 和 x86_64 是 int3

2、 当CPU流程执行到探测点的断点指令时,就触发了一个 trap,在 trap 处理流程中会保存当前CPU的寄存器信息并调用对应的 trap 处理函数,该处理函数会设置 kprobe 的调用状态并调用用户注册的 pre_handler 回调函数,kprobe 会向该函数传递注册的 struct kprobe结构地址以及保存的 CPU 寄存器信息;

3、 随后 kprobe 单步执行前面所拷贝的被探测指令,具体执行方式各个架构不尽相同,arm 会在异常处理流程中使用模拟函数执行,而 x86_64 架构则会设置单步调试 flag 并回到异常触发前的流程中执行;

4、 在单步执行完成后,kprobe 执行用户注册的 post_handler 回调函数;

5、 最后,执行流程回到被探测指令之后的正常流程继续执行。

实时修改内核 code text 听起来会带来极大的风险。但是 kprobes 有很多安全上的考虑,例如为了避免递归陷阱,kprobes不能给一些在黑名单上的函数加探针,kprobes相关的函数就在黑名单中。kprobes还利用安全的技术来插入断点:x86 体系下使用 int3 或者 jmp 时,使用stop_machine 用于确保其他CPU在被修改时停止执行。实际上 kprobes 最大风险是给一些调用十分频繁的函数加上探针,如在网络模块中,频繁中断可能造成一定的性能风险。

uprobes

uprobes 是Linux提供用户态的动态探针,合并于2012年7月发布的 Linux 3.5 内核中。uprobes 和 kprobes 十分相似,只不过用在用户态而已。 uprobes 可以检测到用户态函数入口和出口的位置。uprobes 工作原理和 kprobes 差不多,它会在目标位置插入一个断点,这样当程序执行流执行到这个地方会去执行我们设置的 uprobe handle。当我们不再不需探测和收集信息时候,可以移除断点恢复原状。

硬件追踪

我们看到动态追踪技术在软件系统的分析当中可以扮演非常关键的角色,那么很自然地会想到,是否也可以用类似的方法和思想去追踪硬件。

我们知道其实操作系统是直接和硬件打交道的,那么通过追踪操作系统的某些驱动程序或者其他方面,我们也可以间接地去分析与之相接的硬件设备的一些行为和问题。同时,现代硬件,比如说像 Intel 的 CPU,一般会内置一些性能统计方面的寄存器(Hardware Performance Counter),通过软件读取这些特殊寄存器里的信息,我们也可以得到很多有趣的直接关于硬件的信息。比如说 Linux 世界里的 perf 工具最初就是为了这个目的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值