Quantcast
Channel: CodeSection,代码区,Linux操作系统:Ubuntu_Centos_Debian - CodeSec
Viewing all articles
Browse latest Browse all 11063

Linux中的DTrace:BPF进入4.9内核

$
0
0

Linux中的DTrace:BPF进入4.9内核

随着 BPF 追踪系统(基于时间采样)最后一个主要功能被合并至 linux 4.9-rc1 版本的内核中,现在 Linux 内核拥有类似 DTrace 的原生追踪功能。DTrace 是 Solaris 系统中的高级追踪器。对于长期使用 DTrace 的用户和专家,这将是一个振奋人心的里程碑!现在在 Linux 系统上,你可以在生产环境中使用安全的、低负载的定制追踪系统,通过执行时间的柱状图和频率统计等信息,分析应用的性能以及内核。

用于 Linux 的追踪项目有很多,但是这个最终被合并进 Linux 内核的技术从一开始就根本不是一个追踪项目:它是最开始是用于伯克利包过滤器Berkeley Packet Filter(BPF)的增强功能。这些补丁允许 BPF 重定向数据包,从而创建软件定义网络(SDN)。久而久之,对事件追踪的支持就被添加进来了,使得程序追踪可用于 Linux 系统。

尽管目前 BPF 没有像 DTrace 一样的高级语言,但它所提供的前端已经足够让我创建很多 BPF 工具了,其中有些是基于我以前的 DTraceToolkit。这个帖子将告诉你怎么去用这些 BPF 提供的前端工具,以及畅谈这项技术将会何去何从。


Linux中的DTrace:BPF进入4.9内核
示例

我已经将基于 BPF 的追踪工具添加到了开源的 bcc 项目里(感谢 PLUMgrid 公司的 Brenden Blanco 带领 bcc 项目的发展)。详见 bcc 安装 手册。它会在 /usr/share/bcc/tools 目录下添加一系列工具,包括接下来的那些工具。

捕获新进程: #execsnoop PCOMMPIDRETARGS bash158870/usr/bin/manls preconv158940/usr/bin/preconv-eUTF-8 man158960/usr/bin/tbl man158970/usr/bin/nroff-mandoc-rLL=169n-rLT=169n-Tutf8 man158980/usr/bin/pager-s nroff159000/usr/bin/localecharmap nroff159010/usr/bin/groff-mtty-char-Tutf8-mandoc-rLL=169n-rLT=169n groff159020/usr/bin/troff-mtty-char-mandoc-rLL=169n-rLT=169n-Tutf8 groff159030/usr/bin/grotty

硬盘 I/O 延迟的柱状图:

#biolatency-m TracingblockdeviceI/O...HitCtrl-Ctoend. ^C msecs:countdistribution 0->1:96|************************************| 2->3:25|*********| 4->7:29|***********| 8->15:62|***********************| 16->31:100|**************************************| 32->63:62|***********************| 64->127:18|******|

追踪慢于 5 毫秒的 ext4 常见操作:

#ext4slower5 Tracingext4operationsslowerthan5ms TIMECOMMPIDTBYTESOFF_KBLAT(ms)FILENAME 21:49:45supervise3570W1805.48status.new 21:49:48supervise12770R12807.55run 21:49:48run12770R497016.46nsswitch.conf 21:49:48run12770R1680017.42netflix_environment.sh 21:49:48run12770R107909.53service_functions.sh 21:49:48run12772R128017.74svstat 21:49:48svstat12772R1808.67status 21:49:48run12774R128015.76stat 21:49:48run12777R12807.89grep 21:49:48run12776R12808.25ps 21:49:48run12780R128011.07xargs 21:49:48ps12776R832012.02libprocps.so.4.0.0 21:49:48run12779R128013.21cut [...]

追踪新建的 TCP 活跃连接(connect()):

#tcpconnect PIDCOMMIPSADDRDADDRDPORT 1479telnet4127.0.0.1127.0.0.123 1469curl410.201.219.23654.245.105.2580 1469curl410.201.219.23654.67.101.14580 1991telnet6::1::123 2015ssh6fe80::2000:bff:fe82:3acfe80::2000:bff:fe82:3ac22

通过跟踪 getaddrinfo()/gethostbyname() 库的调用来追踪 DNS 延迟:

#gethostlatency TIMEPIDCOMMLATmsHOST 06:10:2428011wget90.00www.iovisor.org 06:10:2828127wget0.00www.iovisor.org 06:10:4128404wget9.00www.netflix.com 06:10:4828544curl35.00www.netflix.com.au 06:11:1029054curl31.00www.plumgrid.com 06:11:1629195curl3.00www.facebook.com 06:11:2529404curl72.00foo 06:11:2829475curl1.00foo

按类别划分 VFS 操作的时间间隔统计:

#vfsstat TIMEREAD/sWRITE/sCREATE/sOPEN/sFSYNC/s 18:35:32:231124980 18:35:33:2741341060 18:35:34:5868642510 18:35:35:241154990

对一个给定的 PID,通过内核和用户堆栈轨迹来追踪 CPU 处理之外的时间(由内核进行统计):

#offcputime-d-p24347 Tracingoff-CPUtime(us)ofPID24347byuser+kernelstack...HitCtrl-Ctoend. ^C [...] ffffffff810a9581finish_task_switch ffffffff8185d385schedule ffffffff81085672do_wait ffffffff8108687bsys_wait4 ffffffff81861bf6entry_SYSCALL_64_fastpath -- 00007f6733a6b64awaitpid -bash(24347) 4952 ffffffff810a9581finish_task_switch ffffffff8185d385schedule ffffffff81860c48schedule_timeout ffffffff810c5672wait_woken ffffffff8150715an_tty_read ffffffff815010f2tty_read ffffffff8122cd67__vfs_read ffffffff8122df65vfs_read ffffffff8122f465sys_read ffffffff81861bf6entry_SYSCALL_64_fastpath -- 00007f6733a969b0read -bash(24347) 1450908

追踪 mysql 查询延迟(通过 USDT 探针):

#mysqld_qslower`pgrep-nmysqld` TracingMySQLserverqueriesforPID14371slowerthan1ms... TIME(s)PIDMSQUERY 0.00000018608130.751SELECT*FROMwordsWHEREwordREGEXP'^bre.*n$' 2.92153518608130.590SELECT*FROMwordsWHEREwordREGEXP'^alex.*$' 4.6035491860824.164SELECTCOUNT(*)FROMwords 9.73384718608130.936SELECTcount(*)AScountFROMwordsWHEREwordREGEXP'^bre.*n$' 17.86477618608130.298SELECT*FROMwordsWHEREwordREGEXP'^bre.*n$'ORDERBYword

监测 pam 库并使用多种追踪工具观察登录请求:

#trace'pam:pam_start"%s:%s",arg1,arg2' TIMEPIDCOMMFUNC- 17:49:455558sshdpam_startsshd:root 17:49:475662sudopam_startsudo:root 17:49:495727loginpam_startlogin:bgregg

bcc 项目里的很多工具都有帮助信息(-h 选项),并且都应该包含有示例的 man 页面和文本文件。

必要性

2014 年,Linux 追踪程序就有一些内核相关的特性(来自 ftrace 和 pref_events),但是我们仍然要转储并报告进程数据,这种几十年前的老技术有很多的限制。你不能频繁地访问进程名、函数名、堆栈轨迹或内核中的任意的其它数据。你不能在将变量保存到一个监测事件里,又在另一个事件里访问它们,这意味着你不能在你需要的地方计算延迟(或者说时间增量)。你也不能创建一个内核内部的延迟柱状图,也不能追踪 USDT 探针,甚至不能写个自定义的程序。DTrace 可以做到所有这些,但仅限于 Solaris 或 BSD 系统。在 Linux 系统中,有些不在主线内核的追踪器,比如 SystemTap 就可以满足你的这些需求,但它也有自身的不足。(理论上说,你可以写一个基于探针的内核模块来满足需求-但实际上没人这么做。)

2014 年我加入了 Netflix cloud performance 团队。做了这么久的 DTrace 方面的专家,转到 Linux 对我来说简直不可思议。但我确实这么做了,而且遇到了巨大的挑战:在应用快速变化、采用微服务架构和分布式系统的情况下,调优 Netflix cloud。有时要用到系统追踪,而我之前是用的 DTrace。在 Linux 系统上可没有 DTrace,我就开始用 Linux 内核内建的 ftrace 和 perf_events 工具,构建了一个追踪工具(perf-tools)。这些工具很有用,但有些工作还是没法完成,尤其是延迟柱状图以及堆栈踪迹计数。我们需要的是内核追踪的可程序化。

发生了什么?

BPF 将程序化的功能添加到现有的内核追踪工具中(tracepoints、kprobes、uprobes)。在 Linux 4.x 系列的内核里,这些功能大大加强了。

时间采样是最主要的部分,它被 Linux 4.9-rc1 所采用(patchset)。十分感谢 Alexei Starovoitov(在 Facebook 致力于 BPF 的开发),他是这些 BPF 增强功能的主要开发者。

Linux 内核现在内建有以下这些特性(自 2.6 版本到 4.9 版本之间增加):

内核级的动态追踪(BPF 对 kprobes 的支持) 用户级的动态追踪(BPF 对 uprobes 的支持) 内核级的静态追踪(BPF 对 tracepoints 的支持) 时间采样事件(BPF 的 pref_event_open) PMC 事件(BPF 的 pref_event_open) 过滤器(通过 BPF 程序) 调试输出(bpf_trace_printk()) 按事件输出(bpf_perf_event_output()) 基础变量(全局的和每个线程的变量,基于 BPF 映射) 关联数组(通过 BPF 映射) 频率计数(基于 BPF 映射) 柱状图(2 的冥次方、线性及自定义,基于 BPF 映射) 时间戳和时间增量(bpf_ktime_get_ns(),和

Viewing all articles
Browse latest Browse all 11063

Trending Articles