使用Sysdig进行系统性能分析
Sysdig是一个开源的系统性能分析工具,可以实现strace、tcpdump、lsof、top、iftop等工具所具有的功能。
如果需要源代码级别的、通用剖析工具,可以参考:利用perf剖析Linux应用程序。
1 2 3 4 5 6 7 8 9 10 |
# CentOS 7 rpm --import https://s3.amazonaws.com/download.draios.com/DRAIOS-GPG-KEY.public curl -s -o /etc/yum.repos.d/draios.repo http://download.draios.com/stable/rpm/draios.repo # yum update yum -y install epel-release yum install kernel-devel-$(uname -r) yum install sysdig /usr/lib/dkms/dkms_autoinstaller start sysdig-probe-loader |
-c 运行指定的chisel,如果chisel需要参数,则必须用--chisel=chiselname chiselargs形式
-cl 列出可用的chisel,从./chisels, ~/.chisels,/usr/share/sysdig/chisels搜索
-M 在指定秒数之后停止收集
-n 在获取指定数量的事件之后停止收集
-S 在捕获结束,例如列出top事件之后,打印汇总摘要
-s 捕获IO缓冲的前N字节,默认80
不加任何参数调用,每行显示一个捕获的事件,不断刷新。输出格式:
1 2 3 4 5 6 |
# 事件号 发生事件 CPU号 进程名(PID) 事件方向 # 事件类型 事件参数 1462218 16:40:38.068514659 3 <NA> (2941270) > switch next=2941697(sysdig) pgft_maj=0 pgft_min=0 vm_size=0 vm_rss=0 vm_swap=0 1462220 16:40:38.068515560 6 java (2556857) > futex addr=7F3B3888C598 op=129(FUTEX_PRIVATE_FLAG|FUTEX_WAKE) val=1 1462222 16:40:38.068515997 5 java (2557004) > futex addr=7F3AEC01C894 op=137(FUTEX_PRIVATE_FLAG|FUTEX_WAIT_BITSET) val=1 1462224 16:40:38.068516460 6 java (2556857) < futex res=0 |
可以将结果输出到文件而非控制台: sysdig -w result.dump,随后你可以读取先前保存的文件: sysdig -r result.dump
可以使用过滤器对sysdig输出进行过滤,过滤器支持 =、!=、contains等操作符
下面的命令列出可用的过滤器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
sysdig -l ---------------------- Field Class: fd fd.num # 文件描述符号 fd.type # 文件描述符类型,支持的值:'file', 'directory', 'ipv4', 'ipv6', 'unix', # 'pipe', 'event', 'signalfd', 'eventpoll', 'inotify', 'signal fd' fd.typechar # 文件描述符类型简写,支持的值:f 4 6 u # p e s l i # o表示未知 fd.name # 文件描述符全名,对于文件,即完整路径;对于套接字,即连接元组 fd.directory # 文件描述符是文件,且它必须位于此目录下 fd.filename # 文件描述符是文件,且它的basename是此值 fd.ip # 匹配客户端或服务器IP地址 fd.cip # 匹配客户端IP地址 fd.sip # 匹配服务器IP地址 fd.lip # 匹配本地地址 fd.rip # 匹配远程地址 fd.port # 匹配客户端或服务器端口 fd.cport # 对于TCP/UDP,客户端端口 fd.sport # 对于TCP/UDP,客户端端口 fd.lport # 对于TCP/UDP,本地端口 fd.rport # 对于TCP/UDP,远程端口 fd.l4proto # 套接字协议,可选 'tcp', 'udp', 'icmp' or 'raw' fd.sockfamily # 套接字家族,可选 'ip' or 'unix' fd.is_server # 指定为true则用于套接字的进程必须是服务器端 fd.uid # FD的唯一标识 fd.containername # container ID + FD name fd.containerdirectory # container ID + directory name fd.proto # FD的协议 fd.cproto # 对于TCP/UDP,客户端协议 fd.sproto # 对于TCP/UDP,服务器协议 fd.lproto # 对于TCP/UDP,本地协议 fd.rproto # 对于TCP/UDP,远程协议 fd.net # IP网络 fd.cnet fd.snet fd.lnet fd.rnet fd.connected # 对于TCP/UDP,设置为true则仅仅匹配已连接的套接字 ---------------------- Field Class: process proc.pid # 生成事件的进程的ID proc.exe # 第一个命令行参数,通常是可执行文件名 proc.name # 生成事件的可执行文件的名称 proc.args # 生成事件的进程的命令行参数 proc.env # 环境变量 proc.cmdline # 完整命令行,也就是 proc.name + proc.args proc.exeline # 完整命令行,也就是 proc.exe + proc.args proc.cwd # 当前工作目录 proc.nthreads # 进程包括的线程数量 proc.nchilds # 进程包括的子线程数量(除去主线程) proc.ppid # 父进程ID proc.pname # 父进程名称 proc.pcmdline # 父进程的cmdline proc.apid # 某个祖先进程的ID proc.aname # 某个祖先进程的名称 proc.loginshellid # 登陆Shell ID proc.duration # 进程已经启动的纳秒 proc.fdopencount # 进程打开的文件描述符数量 proc.fdlimit # 进程能够打开的文件描述符数量 proc.fdusage # 打开/最大文件描述符比率 proc.vmsize # 进程虚拟内存大小,单位KB proc.vmrss # 驻留内存大小 proc.vmswap # 交换到磁盘的内存大小 thread.pfmajor # 进程启动以来主页面错误次数 thread.pfminor # 进程启动以来次页面错误次数 thread.tid # 线程ID thread.ismain # 如果指定为true,生成事件的线程必须是主线程 thread.exectime # 最后被调度的线程消耗的CPU纳秒数 thread.totexectime # 从捕获开始,当前线程使用的CPU纳秒总数 thread.cgroups # 线程所属的Cgroup,聚合为单个字符串 thread.cgroup # 线程所属的某个Cgroup子系统 thread.vtid # 从产生事件的线程自己的PID命名空间看到的,自己的PID proc.vpid # 从产生事件的进程自己的PID命名空间看到的,自己的PID thread.cpu # 最近一秒消耗的CPU时间 thread.cpu.user # 最近一秒消耗的CPU时间(用户态) thread.cpu.system # 最近一秒消耗的CPU时间(内核态) thread.vmsize # 对于主线程,即虚拟内存大小,对于非主线程,为0 proc.sid # 会话ID proc.sname # 会话名称 proc.tty # 进程的控制终端,0为无控制终端的进程 proc.exepath # 可执行文件的完整路径 proc.vpgid # 从产生事件的进程自己的PID命名空间看到的,自己的进程组ID ---------------------- Field Class: evt evt.num # 事件编号 evt.time # 事件时间戳,包含纳秒部分 evt.time.s # 事件时间戳,不包含纳秒 evt.datetime # 事件时间戳,包含日期部分 evt.rawtime # 原始时间戳,19700101到现在的纳秒数 evt.rawtime.s # 原始时间戳,19700101到现在的秒数 evt.rawtime.ns # 原始时间戳,小数部分(纳秒部分) evt.reltime # 从捕获到发生事件时流逝的时间 evt.reltime.s evt.reltime.ns evt.latency # 配对的enter/exit事件的延迟,纳秒 evt.latency.s evt.latency.ns evt.latency.human # 可读格式,例如10.3ms evt.deltatime # 当前事件和上一个事件之间的延迟 evt.deltatime.s evt.deltatime.ns evt.dir # 事件方向,>为enter事件,<为exit事件 evt.type # 事件(类型的)名称,例如open evt.type.is # evt.type.is.open匹配所有open事件 syscall.type # 对于系统调用事件,指定系统调用名称,例如open evt.category # 事件分类,例如file表示文件操作包括open/close,net表示网络操作 # memory表示mmap/brk等操作 evt.cpu # 事件所在的CPU序号 evt.args # 聚合为字符串的事件参数 evt.arg # 单个事件参数,使用参数名或序号,例如evt.arg.fd或'evt.arg[0] evt.res # 事件结果字符串,如果成功SUCCESS,否则是错误码字符串,例如ENOENT evt.failed # 如果true匹配失败事件 evt.is_io # 匹配读写FD的事件,例如 read(), send, recvfrom() evt.is_io_read evt.is_io_write evt.io_dir # IO方向,r或w evt.is_wait # 如果true则匹配那些导致线程等待的事件,例如sleep(), select(), poll() evt.wait_latency # 等待事件返回(exit)消耗的时间阈值 evt.is_syslog # 事件是否是写入syslog evt.is_open_read # 如果为true,匹配打开以进行读的open/openat事件 evt.is_open_write # 如果为true,匹配打开以进行写的open/openat事件 ---------------------- Field Class: user user.uid # 用户ID user.name # 用户名称 user.homedir # 家目录 user.shell # 用户的Shell user.loginuid # 审计用户ID user.loginname # 审计用户名 ---------------------- Field Class: group group.gid # 组ID group.name # 组名称 ---------------------- Field Class: container container.id # 容器ID container.name # 容器名称 container.image # 容器镜像名称 container.image.id # 容器镜像ID container.type # 容器类型,例如docker, rkt container.privileged # true则匹配运行在特权模式的容器 container.image.repository container.image.tag container.image.digest ---------------------- Field Class: k8s k8s.pod.name # Pod名称 k8s.pod.id # Pod标识符 k8s.pod.label # Pod的标签,例如k8s.pod.label.foo k8s.pod.labels # 逗号分隔的多个Pod标签 k8s.rc.name # 复制控制器 k8s.rc.id k8s.rc.label k8s.rc.labels k8s.svc.name # 服务 k8s.svc.id k8s.svc.label k8s.svc.labels k8s.ns.name # 命名空间 k8s.ns.id k8s.ns.label k8s.ns.labels k8s.rs.name # 复制集 k8s.rs.id k8s.rs.label k8s.rs.labels k8s.deployment.name # Deployment k8s.deployment.id k8s.deployment.label k8s.deployment.labels |
过滤特定进程产生的事件:
1 2 3 4 5 |
# 仅仅捕获sshd产生的事件 sysdig proc.name=sshd # 读取Dump,仅仅显示mysqld产生的事件 sysdig -r result.dump proc.name=mysqld |
Sysdig中的chisels是一小段Lua脚本,用于分析sysdig事件流。Chisels支持:
- 实时分析:每秒刷新一次
- 离线分析:会打印总体的汇总信息
执行下面的命令列出可用的Chisels:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
sysdig -cl Category: Application --------------------- httplog # HTTP请求日志 httptop # HTTP请求TOP memcachelog # memcache请求日志 Category: CPU Usage ------------------- spectrogram # OS延迟的可视化直方图 subsecoffset # topcontainers_cpu # CPU占用最高的容器 topprocs_cpu # CPU占用最高的进程 Category: Errors ---------------- topcontainers_error # 错误最多的容器 topfiles_errors # 错误最多的文件 topprocs_errors # 错误最多的进程 Category: I/O ------------- echo_fds # 打印进程读写的文件 fdbytes_by # IO字节数,根据一个任意的过滤器字段进行聚合 fdcount_by # FD计数,根据一个任意的过滤器字段进行聚合 fdtime_by # FD时间 iobytes # 任何类型的FD的IO字节数总和 iobytes_file # 文件IO字节数总和 spy_file # 回响任何进程对所有文件进行的任何读写,可选的,你可以提供一个文件名,这样只会拦截 # 单个文件上发生的读写 stderr # 打印进程的标准错误 stdin # 打印进程的标准输入 stdout # 打印进程的标准输出 topcontainers_file # 读写磁盘字节数最多的容器 topfiles_bytes # 被读写字节数最多的文件 topfiles_time # 被访问时间最长的文件 topprocs_file # 读写磁盘字节数最多的进程 Category: Logs -------------- spy_logs # 回响任何进程对任何日志文件执行的写入 spy_syslog # 打印任何写入到syslog的消息 Category: Misc -------------- around # 在指定过滤器匹配时,输出指定事件范围附近的事件 Category: Net ------------- iobytes_net # 显示总和网络IO字节数 spy_ip # 显示和指定IP地址的数据交换情况 spy_port # 显示和指定端口的数据交换情况 topconns # IO字节数最多的网络链接 topcontainers_net # 导致网络IO最多的容器 topports_server # 读写字节数最多的TCP/UDP端口 topprocs_net # 导致网络IO最多的进程 Category: Performance --------------------- bottlenecks # 最缓慢的系统调用 fileslower # 跟踪缓慢的文件IO netlower # 跟踪缓慢的网络IO proc_exec_time # 显示进程执行时间 scallslower # 跟踪缓慢的系统调用 topscalls # 调用次数最多的系统调用 topscalls_time # 消耗时间最多的系统调用 Category: Security ------------------ list_login_shells # 列出登陆Shell的ID shellshock_detect # 打印 shellshock攻击 spy_users # 显示交互式的用户活动 Category: System State ---------------------- lscontainers # 列出运行中的荣iq lsof # 列出(可过滤)打开的文件描述符 netstat # 列出(可过滤)打开的网络链接 ps # 列出(可过滤)运行中的进程 |
显示使用网络带宽最多的进程:
1 |
sysdig -c topprocs_net |
查看网络IO最高的进程:
1 2 3 4 5 6 7 8 9 |
sysdig -c topprocs_net # Bytes Process PID # -------------------------------------------------------------------------------- # 38.48KB msgr-worker-1 198488 # 24.36KB msgr-worker-0 198488 # 8.12KB msgr-worker-2 198488 # 76B bird 3951084 # 52B zabbix_agentd 5930 #31B zabbix_agentd 5931 |
打印和目标主机之间的数据交换:
1 2 3 4 |
# 以二进制形式打印 sysdig -s2000 -X -c echo_fds fd.cip=10.5.39.41 # 以ASCII形式打印 sysdig -s2000 -A -c echo_fds fd.cip=192.168.0.1 |
最繁忙服务器端口,按当前已建立连接数:
1 2 |
# 按服务器端口分组 sysdig -c fdcount_by fd.sport "evt.type=accept" |
最繁忙客户端地址,按收发字节数:
1 |
sysdig -c fdbytes_by fd.cip |
列出不是发往Apache的入站请求:
1 |
sysdig -p "%proc.name %fd.name" "evt.type=accept and proc.name!=httpd" |
捕获打开特定文件的进程:
1 2 3 4 5 6 |
# 针对/var/log文件的事件 sysdig fd.name=/var/log # 事件参数fd中包含/var/log的事件 sysdig fd.name contains /var/log # 7227884 16:52:37.116806685 4 svlogd (5880) > write fd=6(<f>/var/log/calico/libnetwork/current) size=50 # 7227885 16:52:37.116816800 4 svlogd (5880) < write res=50 data=./run: exec: line 3: libnetwork-plugin: not found. |
下面的例子,显示被读写字节数最多的文件(瞬时):
1 2 3 4 5 6 7 8 |
sysdig -c topfiles_bytes # Bytes Filename # -------------------------------------------------------------------------------- # 2.53KB /etc/hosts # 585B /sys/fs/cgroup/memory/kubepods/besteffort/pod56e20dda-38bf-11e9-99bd-44a8421fdcc8/memory.stat # 563B /sys/fs/cgroup/memory/kubepods/besteffort/memory.stat # 116B /sys/fs/cgroup/cpu,cpuacct/kubepods/besteffort/cpuacct.usage_percpu |
联用过滤器,仅仅显示/root下读写字节数最多的文件(瞬时):
1 |
sysdig -c topfiles_bytes "fd.name contains /root" |
联用过滤器,仅仅显示admin用户读写字节数最多的文件(瞬时):
1 |
sysdig -c topfiles_bytes "user.name=admin" |
显示延迟超过1ms的IO调用:
1 2 3 4 |
sysdig -c fileslower 1 # evt.datetime proc.name evt.type LATENCY(ms) fd.name # ----------------------- ------------ -------- ------------ ----------------------------------------- # 2019-03-25 11:15:54.119 node_exporte read 75 /host/sys/fs/xfs/sda2/stats/stats |
根据FD类型汇总IO数据量:
1 2 3 4 5 6 7 8 9 10 |
sysdig -r t.scap -c fdbytes_by fd.type # Bytes fd.type # ------------------------------ # 485.00M file # 4.63M unix # 509.92KB pipe # 99.83KB ipv4 # 53.79KB event # 3.08KB inotify |
根据目录汇总IO数据量,仅仅考虑文件IO:
1 2 3 4 5 6 7 8 |
sysdig -r t.scap -c fdbytes_by fd.directory "fd.type=file" # Bytes fd.directory # ------------------------------ # 101.89M /tmp/ # 90.26M /root/.ccache/tmp/ # 85.75M /usr/include/c++/4.7.2/bits/ # 24.74M /usr/include/c++/4.7.2/ |
在特定目录下,汇总每个文件的IO数据量:
1 2 3 4 5 6 7 |
sysdig -r t.scap -c fdbytes_by fd.filename "fd.directory=/tmp/" # Bytes fd.filename # ------------------------------ # 13.64M ccJvb4Mi.s # 9.33M cc4pbJkV.s # 6.72M ccx9zir6.s |
发现导致特定目录下文件IO的进程:
1 2 3 4 5 6 7 8 9 10 |
# 根据进程名聚合 # 逻辑与:IO的目标是/tmp/*.s文件 sysdig -r t.scap -c fdbytes_by proc.name "fd.directory=/tmp/ and fd.filename contains .s" # Bytes proc.name # ------------------------------ # 50.57M as # 49.03M cc1plus # 1.54M cc1 # 1B httpd |
发现针对特定文件IO的调用栈:
1 2 3 4 5 6 7 |
sysdig -A -r t.scap -c echo_fds "fd.filename=ccJvb4Mi.s" # ------ Write 4.00KB to /tmp/ccJvb4Mi.s # .file"chisel.cpp" # .text # .Ltext0: # .section.text._ZNSt9exceptionC2Ev,"axG",@p |
1 2 3 4 5 6 7 8 |
# CPU用量最大的进程 sysdig -pc -c topprocs_cpu # 网络带宽用量最大的进程 sysdig -pc -c topprocs_net # 文件IO字节数最大 sysdig -pc -c topfiles_bytes # 网络连接数最高 sysdig -pc -c topconns |
sysdig的图形化用户接口,类似于top或htop,但是功能要强大的多:
- 支持实时分析,也支持分析sysdig跟踪文件。跟踪文件可以来自其它机器
- 支持CPU、内存、磁盘IO、网络IO等多方面指标的详细分析
- 支持跟踪进程、文件、网络连接的IO活动
- 可以钻取到进程、文件、网络连接
- 支持sysdig的过滤语法
- 支持容器和K8S
csysdig基于view,每个view是一小段Lua脚本,负责收集指标并展示在屏幕上
1 |
apt-get install sysdig |
-d 刷新间隔,默认2000
-pc 容器支持,显示额外的容器相关的字段
-k 启用K8S支持,指定API Server的URL,可用环境变量SYSDIG_K8S_API代替
-K 使用指定的凭证来访问K8S,可用环境变量SYSDIG_K8S_API_CERT代替
-N 不把端口号转换为名称
-r 读取跟踪文件
- 不使用参数调用该命令,执行实时分析;使用-r来分析跟踪文件
- 按F2切换view
- Enter可以钻取,Backspace可以退回
- 按F5可以显示选中条目的IO活动
- 按F6可以看到选中条目的sysdig事件
你可以钻取、上卷,快捷键分别为Enter、Backspace。例如你可以从进程钻取到线程,在不同的钻取级别,你都可以切换、查看其它view,非常强大
- 进程视图:k杀死进程
- 容器视图:b打开Shell
以系统调用为例,颜色越靠近红色,说明那个耗时区间的系统调用越多:
F2选择视图时,右侧会给出每个字段的含义
Leave a Reply