容器中的诊断与分析4——live diagnosis——LTTng LTTng 简介&使用实战

官网地址html

LTTng 简介&使用实战python

使用LTTng连接内核和用户空间应用程序追踪linux

 

简介:算法

LTTng: (Linux Trace Toolkit Next Generation),它是用于跟踪 Linux 内核、应用程序以及库的系统软件包shell

LTTng 主要由内核模块和动态连接库(用于应用程序和动态连接库的跟踪)组成缓存

由一个会话守护进程控制,该守护进程接受来自命令行接口的命令安全

 babeltrace 项目容许将追踪信息翻译成用户可读的日志,并提供一个读追踪库,即 libbabletrace。babel

 

  •  LTTng 不只使用了 Linux 内核中的追踪点(tracepoint)手段,并且可使用其余各类信息来源,
    • 好比kprobes 和 Perf(Linux 中的性能监检测工具)。
  • 这对于调试大范围内的bug 是很是有用的,不然这种调试工做将极具挑战性。
    • 好比,包括并行系统和实时系统中的性能问题。
  • 另外,用户本身定制的工具也能够加入到其中。
    • LTTng 的设计目标是将性能影响最小化,并且在没有跟踪的状况下,对系统的影响应该几乎为零。

 

LTTng现在已支持多个发行版(Ubuntu/Dibian、Fedora、OpenSUSE、Arch etc.)和多种架构(x86 and x86-64 、ARM 、PowerPC, Sparc, Mips etc.),此外官方还说支持Android和FreeBSD系统。网络

 

 

实战:session

  • 首先咱们得确认你是否已经安装了lttng-modules 和lttng-tools。
  • 列出全部的可追踪内核事件: 
# lttng list -k
Kernel events:
-------------
     timer_init (loglevel: TRACE_EMERG (0)) (type: tracepoint)
     timer_start (loglevel: TRACE_EMERG (0)) (type: tracepoint)
     timer_expire_entry (loglevel: TRACE_EMERG (0)) (type: tracepoint)
 ……
  • 建立一个追踪会话(session),这个命令会建立一个目录用以存放追踪结果:

    # lttng create mysession
    Session mysession created.
    Traces will be written in /home/dslab/lttng-traces/mysession-20131010-145153

    • 假如你当前已经有了不少的会话,咱们能够设置当前追踪会话:
# lttng set-session myothersession
Session set to myothersession
  • 建立追踪规则(探测点/系统调用 etc.)

    • 追踪内核全部的探测点和全部的系统调用事件(-k/--kernel):
      • # lttng enable-event -a -k  
    • 追踪探测点事件,这里咱们追踪 sched_switch和sched_wakeup为例 (-k/--kernel) ;或者追踪全部的探测点事件:
      • # lttng enable-event sched_switch,sched_wakeup -k
      • # lttng enable-event -a -k --tracepoint
    • 追踪全部的系统调用:
      • # lttng enable-event -a -k --syscall
    • 使用 kprobes 以及 (或) 其余追踪器做为lttng的源:
      • 这是一个LTTng2.0内核追踪器的一个新特性,你可使用一个动态probe做为源,probe的追踪结果会显示在lttng的追踪结果中。
      • 能够为probe制定一个准确的地址0xffff7260695或者 symbol+offset。
        • lttng enable-event aname -k --probe 0xffff7260695
        • lttng enable-event aname -k --probe symbol+0x0
      • 也可使用功能追踪(使用的Ftrace API),追踪结果也会显示在lttng的追踪结果中
        • lttng enable-event aname -k --function <symbol_name>
    • 打开一个事件的上下文信息:
      • 这也是一个新特性,可让你添加一个事件的上下文信息。
        • 好比说你能够添加PID:# lttng add-context -k -e sched_switch -t pid
      • 也可使用多个上下文信息:
        • # lttng add-context -k -e sched_switch -t pid -t nice -t tid
      • 可使用' lttng add-context --help ' 学习全部的上下文格式的用法。
    • 打开事件的Perf计数器: 
      • 这也是一个新的很强大的特性,为每一个追踪的事件添加Perf计数器数据(使用Perf的API)。
        • 下面实例为为每一个事件添加CPU周期:# lttng add-context -k -e sched_switch -t perf:cpu-cycles
      • 注: 你须要使用 add-context 的help学习全部的perf计数器值的含义
  • 开始追踪
    • # lttng start
    • 追踪结果会写到上面建立会话时建立的文件夹中。
      • 好比上面的 :/home/dslab/lttng-traces/mysession-20131010-145153
    • 注意:这个命令会打开全部的追踪,若是你想同时追踪用户空间和内核空间,你在使用这个以前须要设置好全部的追踪规则。

 

  • 中止追踪
    • # lttng stop
    • 注:在这时候,你可一使用 lttng start 从新追踪,也能够打开/关闭某个事件或者隔段时间再来追踪。固然你也能够查看追踪信息。

 

  • 关闭追踪(你的追踪工做已经结束)
    • # lttng destroy 

 

用户空间追踪:

追踪数据分析:

 

  • 分析工具 -- babeltrace
    • babeltrace是lttng tools中自带的分析工具,很强大。
    • 能够直接使用babeltrace打开追踪数据
      • 好比上面提到的 /home/dslab/lttng-traces/mysession-20131010-145153。
    • 先查看下这个追踪结果下的结构:
      • # tree /home/dslab/lttng-traces/mysession-20131010-145153
         
        
        /home/dslab/lttng-traces/mysession-20131010-145153
        └── kernel
            ├── channel0_0 
            ├── channel0_1 
            ├── channel0_2 
            ├── channel0_3 
            └── metadata
      • 能够看出来追踪目录下只有一个目录,叫作kernel;若是追踪前也打开了用户追踪,那么这里面还会多个追踪目录(用户空间的)
      • kernel目录下分几个文件保存追踪数据。可是咱们使用babeltrace查看追踪结果时不能指定到具体的文件,须要指定到kernel。
    • 若是咱们将babeltrace的输出信息输出到一个文件中,咱们就可使用shell脚本获取/tmp/trace中的追踪数据并进一步分析。
      • 好比# babeltrace /home/dslab/lttng-traces/mysession-20131010-145153 > /tmp/trace 。

 

原文连接

LTT:(Linux Trace Toolkit)是linux下一种用于跟踪系统详细运行状态和流程的重要工具,它能够跟踪记录系统中的特定事件。

这些事件包括:
* 系统调用的进入和退出
* 陷阱/中断(Trap / Irq)的进入和退出
* 进程调度事件
* 内核定时器
* 进程管理相关事件:建立 ,唤醒,信号处理等等
* 文件系统相关事件:Open / Read / Write / Seek / Ioctl 等等
* 内存管理相关事件:内存分配/释放等
* 其余事件:IPC / Socket/ 网络 等等
此外 Ltt还提供了自定义和记录须要跟踪的事件类型的函数接口。

 

LTTng: (Linux Trace Toolkit Next Generation),它是用于跟踪 Linux 内核、应用程序以及库的系统软件包。

LTTng 主要由内核模块和动态连接库(用于应用程序和动态连接库的跟踪)组成。

它由一个会话守护进程控制,该守护进程接受来自命令行接口的命令。

babeltrace 项目容许将追踪信息翻译成用户可读的日志,并提供一个读追踪库,即 libbabletrace。
LTTng 不只使用了 Linux 内核中的追踪点(tracepoint)手段,并且使用了其余各类信息来源,好比kprobes 和 Perf(Linux 中的性能监检测工具)。

这对于调试大范围内的bug 是很是有用的,不然这种调试工做将极具挑战性。好比,包括并行系统和实时系统中的性能问题。

另外,用户本身定制的工具也能够加入到其中。LTTng 的设计目标是将性能影响最小化,并且在没有跟踪的状况下,对系统的影响应该几乎为零。

 

LTTng2.0:使用简单的用户接口--lttng命令来整合用户空间和内核空间追踪。

还有其余一些特性:

  • 从支持多个发行版 & 多个架构
  • 有通用的追踪格式
  • 支持探测点、详细的系统调用追踪、函数追踪器、CPU性能监控以及kprobe
  • 提供对用户空间和内核的追踪接口
  • 能够在追踪中的事件附加上下文信息(好比PMU 性能监控单元counter, pid, ppid, tid, comm name等)。全部的额外信息都被收集起来放在一个追踪session的部件里。

 

研究背景

     现现在,多核、集群以及嵌入式系统等让Linux系统变得愈来愈复杂,而开发者就面临着愈来愈复杂的bug,这些bug可能只在产品中出现而在调试时就不见了或者不多发生并且只让系统变得有点慢,这些特性都让传统的调试内核工具变得无效。因此须要有调试工具来应对这些问题。这些工具对系统的性能影响必要要很小,从而能够把他们用在产品上。
     内核追踪就是一款这样的工具,它提供了一种颇有效的理解内核行为以及调试用户空间程序和内核故障的方法。可是在一些状况下,内核追踪也是不足以应对的。好比,有个程序会发出大量的请求或者它有不少不少个线程从而致使只从内核空间的角度来追踪是很是难的。因此在这种状况下,应用空间的程序也须要追踪。并且要求追踪的用户空间事件与内核事件是相关的。
     本文提到的是LTTng的一个用户空间追踪器,能够实现上述功能 --  同时追踪用户空间应用程序事件和内核事件。

 

What is tracing?

     追踪是一门技术用来理解或者监控系统里面是如何运行的。追踪器(tracer)是用来追踪的软件。追踪能够用来调试不少的bug,这些可能包括复杂的并行系统或者实时系统中的性能问题。
     追踪其实和记录日志很像:它主要就是记录系统中的事件。可是,与日志相比,它记录的是系统中更为底层以及更频繁的事件。因此追踪其必须被优化从而能够处理大量的数据而不对系统产生很大的影响。追踪其一般一秒钟产生数以千计的事件。它们常常处理数以百万计的事件以及数M到数十G的数据。
     追踪可能包括操做系统内核的各类事件(好比中断请求处理函数的进入/退出,系统调用的进入/退出,调度状况以及网络状况等),他们还可能包括应用程序的事件。
     事件追踪的列表可能被手动的像读取日志文件那样读取,可是由于工做量太大,因此追踪分析器或者阅读器能够根据这些庞大的数据生成图型或者统计数据。这些分析软件须要特殊设计以便快读处理这些庞大的数据。

 

相关研究

* strace :是一种提供原始的用户空间追踪的工具,它能够追踪系统调用和信号的状况。可是它会引起较大的性能损失。可是它限制到追踪一些系统调用和信号,能够以较小的损失来得到追踪信息。

* DTrace :具备静态定义的跟踪(Statically Defined Tracing,SDT)能够用在用户空间应用中。它用一种在运行时连接中的特殊支持实现的。【6】

* SystemTap :如同DTrace实现了SDT。【2】

* LTTng : 这些年提供了几种不一样的用户空间追踪技术:

1)systemcall assisted -- 这个技术声明了两个新的系统调用,第一个用来注册一个事件类型并返回事件ID,第二种用来记录事件,他须要事件ID和负荷
2) userspace tracing -- 它不须要内核的支持。程序在他们本身的地址空间缓存上写事件,追踪器为每一个线程穿件一个共享缓存的同伴进程,同伴进程使用一个无锁算法来使用这个缓存。

---- 这两个方法都被遗弃了,如今有个新的替代方案被提出,它是一个简单的使用字符串作参数的系统调用。调用它会产生一个参数就是这个字符串的事件,…… 。这个特性是来自于DebugFS(/debug/ltt/write_event),向这个文件写入一个字符就会建立一个叫作user-space_event的事件,事件的参数是这个字符串。

* Ftrace :有相似的特性,叫作trace_marker.

 

实现 

主要介绍UST(LTTng Userspace Tracer,LTTng用户空间追踪器)的结构,首先咱们看看UST的重要设计目标:
   * 须要与内核空间的追踪器彻底独立,用户空间追踪和内核空间追踪的结果应该在分析的时候再关联
   * 须要是可重入的,并支持多线程&追踪信号处理的事件
   * 在快速路径中不能有系统调用
   * 追踪结果不能被拷贝
   * 须要能追踪共享库中的代码
   * 探测点须要支持无穷多的参数
   * 对于链接器和编译器不须要特殊的支持
   * 追踪格式须要是紧凑的

 

追踪库 

* libust - 追踪库
* liburcu - 用户空间读/拷贝/更新库,用来在数据结构之间无锁操控【4】
* libkcompat - Linux内核提供用户空间API的库(如院子看哦乃至,链接表机制,kref类型机制等)【5】

 

时间

     LTTng的用户空间追踪器和内核没有依赖关系,可是为了把内核追踪和用户空间追踪合并分析,全部的追踪器的时间戳必须是一致的(必须来自同样的时钟源)。
     一个合适的时钟源必须是高精度的这样才能保证在核之间都是一致的;还要保证用户空间和内核空间访问时的开销要小(由于系统调用的代价以及很高了)。
UST中使用的是内核提供的时钟源,并且直接使用rdtsc指令读取。这个时钟源也是内核追踪器使用的,读取和多核之间同步都很快。

 

探测点

     探测点是由内核LTTng使用的两个端口组成:marker和tracepoint,它们的使用也与内核中同样。
     插入marker就像在事件须要记录的地方插入一行代码同样简单,下面的代码中咱们能够看到,mark的使用与printf很相似:
                       trace_mark(main,myevent,"firstarg %d secondarg %s",v,st);
     tracepoint的设计更佳,从下面代码中能够看到,它基本不包括一个格式字符串,但须要一些声明,通常分开放在C文件和头文件中。因此,它更合适放在永久的代码中(须要时,只须要修改头文件中声明便可)。而marker更合适用在调试时添加。(用来调试中打印信息)
                       trace_main_myevent(v,st);
     marker和tracepoint在可执行或者动态对象中的一个特殊字段列举他们自身信息,全部包含探测点的库和可执行文件所以须要经过调用追踪库来注册他们的marker/tracepoint。这是经过唤醒一个添加构造函数的宏来实现的。

 

 

缓存机制 

     缓存机制是无锁LTTng算法的一个端口,它的设计不少源自于K42操做系统以及Linux内核中的Relay系统【8】事件在一个圆形的、每一个进程一个的缓冲区中被写入,这个缓冲区被划分红多个sub-buffer。默认状况下,当一个sub-buffer写满,就会有一个清空守护进程清空它。在另一种操做模式下(flight recorder),圆形的缓冲区被不断的重写直到这个缓冲区被清除,这对于等待一些罕见的bug出现是颇有帮助的。
     每一个事件都与一个channel(通道?)相关联,对于每一个channel每一个进程都有个明显的缓冲区。有几个channel容许选择每一个channel的sub-buffer大小。在flight recorder模式下,它经过将一些时间放在低速率的缓冲区中实现容许保持这些事件的缓冲区很长的时间。
     缓冲区被分配在System V的共享内存字段中,因此清空守护进程能够将它们映射到它本身的地址空间。
     写缓冲区时使用了一种已形式化验证过其安全性的无锁算法,因此能够保证可重入、多线程、安全性。

 

追踪控制

      用户空间追踪器确定须要一个控制方法,好比咱们须要开始/中止追踪、使能/关闭/列出探测点以及控制追踪参数(好比sub-buffer的大小以及数量)
      一个叫作ust的辅助应用被设计用来作这项工做,它与被追踪的程序经过UNIX socket通讯,被追踪哦进程中一个特殊的线程来处理这个通讯。这个线程并非当这个应用程序开始时就启动,这使得UST看起来不是那么有攻击性。而是,当追踪库构造函数为一个特别的信号注册一个信号控制器,当那个信号被接收到,这个监听的线程才会启动。这个线程会在一个预先定义好的目录下建立一个socket,socket的名为进程ID。

 

数据收集 

      有一个进程收集系统中全部被追踪的进程的追踪数据,这个进程叫作ustd。收集数据使用一个命名socket,socket会调用ustd 并定位到与被追踪的程序的socket一样的目录下。经过这个socket,ustd才能接受指令并收集给定PID对应的缓存的追踪数据。
      收到指令后,ustd会建立一个线程用来连接socket和被追踪的进程。首先,假如socket还没准备好它会发送一个SIGIO信号,而后,它会请求共享内存以求映射缓存。
      直到可以使用被追踪应用的socket后,这个线程会发一个请求来获取下一个sub-buffer的许可。当下一个sub-buffer满了后,会发送一个回复。收到回复后,这个线程会将他的数据写到追踪文件中(从共享内存段中读取的)。

 

过早和过晚地追踪

       UST使用一种特殊的机制用来保证在程序执行时开始追踪:用两个环境变量运行这个程序,这些环境变量被追踪库构造函数解析,设定这些环境变量是为了保证在程序进入他的main()函数时追踪已然开始。       但对于程序结束时如何结束跟踪难度比较大:可能程序崩溃了而后就没办法通知ustd来获取最后一个sub-buffer的信息,更坏的多是在追踪还没映射它的缓存程序就结束了。对于前面的状况,追踪的最后一部分就丢失了;对于后面的状况,整个追踪就丢失了,由于内核会在使用者与共享内存段断开链接时解除分配这段共享内存。      当程序崩溃时,内核会关闭socket链接,可是ustd可以检测到socket的断开,并在缓存上运行一个崩溃恢复程序,这个程序会辨别哪一个sub-buffer有还没记录的数据以及有多少数据能够被恢复,这些数据会被恢复程序追加到追踪文件后。对于如何辨别sub-buffer中的数据是否是有效的,使用的是一些在映射缓存与共享内存段的原子算法中用到的计数器。      当程序的生命周期对于ustd来讲过短了,来不及映射内存,新的难题出现了。(目前UST还没支持这种状况下的追踪)可是计划是使用析构函数来处理这个问题,假如追踪库的析构函数检测到一个追踪被记录可是他的缓冲区还未被映射,它会扩展程序的生命周期来给ustd足够的时间映射。

相关文章
相关标签/搜索