涉及到 iotop, iostat, netstat, sar 命令的使用。
本文全面介绍 Linux 系统下四种强大的网络与 IO 监控工具及其实际应用。详细讲解了 iotop 进程级 IO 监控、iostat 设备 IO 统计、netstat 网络连接分析和 sar 系统活动报告工具的安装配置、命令选项和常见使用场景。文章最后提供了一个实用脚本,用于自动收集系统网络数据并实现日志轮转,帮助系统管理员高效监测和排查网络性能问题。
1. iotop#
类似于 top 命令,用于监控和显示进程级别的磁盘 I/O 使用情况,可以像 top 一样实时刷新显示。
如果系统默认没有安装,需要先安装:
sudo yum install iotop使用格式:iotop [options]
常用的选项 options 有:
-o 仅显示当前正在进行 I/O 操作的进程-b 批处理模式,不刷新屏幕,直接输出结果,适用于脚本-n NUM 指定输出的刷新次数(默认无限刷新)-d SEC 指定刷新间隔,单位为秒(默认 1 秒)-p PID 只显示特定进程的 I/O 活动-P 只显示进程,不显示线程-u USER 只显示属于特定用户的进程的 I/O 使用情况-q 使 iotop 运行时安静,只输出一次统计信息而不刷新-k 输出的单位,kbytes/s-t 显示时间戳使用场景:
- 每两秒刷新一次数据,
iotop -d 2 - 查看指定的 PID 的 IO 活动,
iotop -p <PID> - 批处理,
iotop -b -oPt -n 10 > io_stats.log, 每隔 1 秒输出活动进程的 IO 统计信息到指定文件,输出 10 次。
2. iostat#
系统的 I/O 数据统计,可以动态的监视磁盘设备的 IO 负载情况
如果系统默认没有安装,需要先安装:
sudo yum install sysstat使用格式:iostat [ options ] [ interval [ count ] ]
常用的选项 options 有:
-d 输出设备 (磁盘) 的 IO 统计信息-c 输出 CPU 的统计信息,与 -d 选项相互排斥-h 输出 human readable 格式信息-k/-m 输出的单位,kbytes/s, mbytes/s,默认是块(每块 512 字节)-x 输出拓展信息,包含更详细的 I/O 指标-t 显示采集数据时的时间-p [device] 显示所有设备或指定设备的**分区**统计-y 忽略自机器启动以来的累计统计数据,而从命名执行开始统计使用场景:
- 显示系统每个设备的 IO 统计数据,执行
iostat -d - 显示每个设备以及其分区的 IO 统计数据,执行
iostat -p - 每隔 1 秒,持续地采集系统设备 IO 的详细指标,执行
iostat -xyt 1
3. netstat#
netstat 查看系统中网络相关活动的重要工具,常用于查看 TCP/UDP 连接,socket 活动等等。
如果系统默认没有安装,则需要进行安装:
sudo yum install net-tools常用的选项有:
-r, --route 显示路由表-i, --interfaces 显示所有网卡表,如 `netstat -i`-I, --interfaces=<Iface> 显示指定的网卡表,如 `netstat -I=eth0`
-s, --statistics 输出网络的统计信息 (like SNMP)-v, --verbose verbose 输出-c, --continuous 连续输出模式
-n,--numeric 不解析主机名,直接显示对应的 ip-e, --extend 显示更多拓展 or 隐藏的信息,如 `netstat -i -e` 的输出相当于 `ifconfig`-p, --programs 显示 PID/Program 占用的 socket
-l, --listening 显示正在监听的 socket 活动-a, --all 显示所有的 socket 活动 (默认:connected)
-t, --tcp 显示 TCP 连接活动-u, --udp 显示 UDP 连接活动实际场景:
- 查找哪些服务正在监听哪些 TCP 端口,使用
-t选项:netstat -t -ln - 查看某个端口或者 socket 正在被哪个进程/服务占用,使用
-p选项:netstat -p -tln | grep :80 - 查看网卡的网络数据统计信息,使用
-s选项:netstat -s 3, 后面接一个数字 3 表示每 3 秒刷新一次,也意味着进入--continue模式。
4. sar#
sar 表示 system activity reporter, 也是 Linux 上有用的性能分析工具。
使用格式是:sar [ options ] [ t
常用的选项 options 有:
-b I/O 和传送速率的统计 [A_IO]-B 内存分页统计 [A_PAGE]-d 块设备统计 [A_DISK]-n { <关键词> [,...] | ALL } 网络统计 [A_NET_...] 关键词有: DEV Network interfaces EDEV Network interfaces (errors) IP IP traffic (v4) EIP IP traffic (v4) (errors) TCP TCP traffic (v4) ETCP TCP traffic (v4) (errors) UDP UDP traffic (v4) UDP6 UDP traffic (v6) SOCK Sockets (v4) SOCK6 Sockets (v6) IP6 IP traffic (v6) EIP6 IP traffic (v6) (errors)-q [ <关键词> [,...] | PSI | ALL ] System load and pressure-stall statistics 关键词有: LOAD Queue length and load average statistics [A_QUEUE] CPU Pressure-stall CPU statistics [A_PSI_CPU] IO Pressure-stall I/O statistics [A_PSI_IO] MEM Pressure-stall memory statistics [A_PSI_MEM]-r [ ALL ] 内存使用统计 [A_MEMORY]-S 交换内存使用统计 [A_MEMORY]-u [ ALL ] CPU 利用率 [A_CPU]-v Kernel tables statistics [A_KTABLES]-W Swapping statistics [A_SWAP]-w Task creation and system switching statistics [A_PCSW]-y TTY devices statistics [A_SERIAL]t 表示采样间隔,n 表示采样次数
-o 表示输出到指定文件,之后还可以通过 -f 指定读取该文件,查看之前记录的统计数据。
实际场景:
- 排查 CPU 相关的问题,执行
sar -u 1 10和sar -q 1 10每间隔 1 秒采集一次,共采集 10 次。 - 排查内存相关的问题,执行
sar -r,sar -B,sar -W,也可以加上采集间隔和采集次数。 - 排查 IO 相关问题,执行
sar -b,sar -u,sar -d,也可以加上采集间隔和采集次数。
注意到这个命令在不同的操作系统或发行版本中可能在选项上有些差异,需要在具体系统中使用 sar --help 来确认。
参考:https://linuxtools-rst.readthedocs.io/zh-cn/latest/tool/sar.html
一个小脚本#
之前项目中需要对系统网络情况进行监控,所以写了这个脚本。 它实现了将网络统计数据写入日志文件,然后定期对日志文件进行 rotate,丢掉过期的文件 (logroate 服务有系统的 crontab job 定期执行)。
#! /bin/bashset -e
LOGROTATE_IOSTAT=/etc/logrotate.d/iostatLOGROTATE_IOTOP=/etc/logrotate.d/iotopLOGROTATE_SAR=/etc/logrotate.d/sarLOGROTATE_NETSTAT=/etc/logrotate.d/netstat
# todo# SYSTEMD_PATH=/usr/lib/systemd/system/watcher.service
new_date() { date '+%Y-%m-%d-%H-%M-%S'}
function run_iotop() { # time-stamp, batch, only process ret=`iotop -tboP -d $interval | tee -a $logger` if [[ $? -eq 0 ]]; then echo "done ..." | tee -a $logger exit fi}
run_iostat() { while true; do ret=`iostat -t -y -d $interval | tee -a $logger` if [[ $? -eq 0 ]]; then echo "done ..." | tee -a $logger exit fi done}
run_netstat() { ret=`netstat -s $interval | tee -a $logger` if [[ $? -eq 0 ]]; then echo "done ..." | tee -a $logger echo >&3 exit fi}
run_sar() { while true; do ret=`sar -n ETCP $interval | tee -a $logger` if [[ $? -eq 0 ]]; then echo "done ..." | tee -a $logger exit fi done}
setup_logroate() { LOG=$(readlink -f ${1}) LOG_CONF=$2 if [[ ! -f $LOG_CONF ]]; then cat <<-EOF > $LOG_CONF$LOG {dailycreaterotate 31missingokcopytruncatedateextcompressminsize 1Mcreate 666 root root}EOF fi}
stop_iostat() { ps -ef | grep iostat | grep -v grep | grep -v $1 | grep -v tee | awk '{print $2}' | xargs -I{} kill -9 {}}
stop_iotop() { ps -ef | grep iotop | grep -v grep | grep -v $1 | grep -v tee | awk '{print $2}' | xargs -I{} kill -9 {}}
stop_netstat() { ps -ef | grep netstat | grep -v grep | grep -v $1 | grep -v tee | awk '{print $2}' | xargs -I{} kill -9 {}}
stop_sar() { ps -ef | grep sar | grep -v grep | grep -v $1 | grep -v tee | awk '{print $2}' | xargs -I{} kill -9 {}}
show_usage() { echo "Usage: $0 [-c | --cmd] [-o | --operate] [-i | --interval] [-f | --log-file] [-h | --help]" echo "Example: $0 -c iostat -o start -i 3 -f /home/logs/iostat.log " echo "Example: $0 -c iostat -o stop" echo "COMMONDS: iotop, iostat, netstat, sar"}
main() { if [[ $# -lt 1 ]]; then show_usage exit 1 fi
script_name=$0 ARGS=$(getopt -o i:,f:,o:,c:,h --long cmd:,operate:,interval:,log-file:,help, -- "$@") if [[ $? -ne 0 ]]; then echo "parse params error." show_usage exit 1 fi eval set -- "${ARGS}" while true; do case $1 in -c | --cmd) cmd=$2 shift 2 ;; -o | --operate) operate=$2 shift 2 ;; -i | --interval) interval=$2 shift 2 ;; -f | --log-file) logger=$2 shift 2 ;; -h | --help) show_usage exit ;; --) shift break ;; *) show_usage exit 2 ;; esac done
if [[ -z $logger ]]; then logger=$(new_date)-${cmd}.log fi if [[ -z $interval ]]; then interval=1 fi
# iostat if [[ $cmd == "iostat" && $operate == "start" ]]; then setup_logroate $logger $LOGROTATE_IOSTAT run_iostat & fi if [[ $cmd == "iostat" && $operate == "stop" ]]; then stop_iostat $script_name fi
# iotop if [[ $cmd == "iotop" && $operate == "start" ]]; then setup_logroate $logger $LOGROTATE_IOTOP run_iotop & fi if [[ $cmd == "iotop" && $operate == "stop" ]]; then stop_iotop $script_name fi
# netstat if [[ $cmd == "netstat" && $operate == "start" ]]; then setup_logroate $logger $LOGROTATE_NETSTAT run_netstat & fi if [[ $cmd == "netstat" && $operate == "stop" ]]; then stop_netstat $script_name fi
# sar if [[ $cmd == "sar" && $operate == "start" ]]; then setup_logroate $logger $LOGROTATE_SAR run_sar & fi if [[ $cmd == "sar" && $operate == "stop" ]]; then stop_sar $script_name fi
}
main "$@"