第43集:进程监控工具

章节标题

进程监控工具

核心知识点讲解

进程监控工具概述

进程监控工具是用于实时观察和分析系统中进程行为、资源使用情况的软件工具。它们可以帮助系统管理员和开发人员了解系统状态,识别性能瓶颈,以及排查系统问题。

top 命令

top 命令是最基本的进程监控工具,几乎在所有Linux系统中都默认安装。

基本用法

# 启动top命令
top

# 以批处理模式运行,显示指定次数后退出
top -b -n 1

# 只显示指定PID的进程
top -p PID1,PID2

# 设置更新间隔(秒)
top -d 2

交互式命令

在top运行时,可以使用以下快捷键:

快捷键 功能
q 退出top
k 终止指定进程
r 调整进程优先级
f 自定义显示字段
M 按内存使用率排序
P 按CPU使用率排序
T 按CPU时间排序
1 显示所有CPU核心的使用率
z 启用彩色显示
h 显示帮助信息

输出解释

top命令的输出分为两部分:

  1. 顶部系统摘要信息:包括系统时间、运行时间、用户数、负载平均值、CPU使用率、内存使用率等
  2. 进程列表:按默认或用户指定的排序方式显示进程信息

htop 命令

htoptop 命令的增强版本,提供了更友好的界面和更多的功能。

安装

# 在Debian/Ubuntu系统上安装
sudo apt install htop

# 在CentOS/RHEL系统上安装
sudo yum install htop

# 在Fedora系统上安装
sudo dnf install htop

基本用法

# 启动htop命令
htop

# 只显示指定用户的进程
htop -u username

# 只显示指定PID的进程
htop -p PID1,PID2

# 以树状结构显示进程
htop -t

交互式命令

在htop运行时,可以使用以下快捷键:

快捷键 功能
F1 显示帮助信息
F2 配置htop
F3 搜索进程
F4 过滤进程
F5 切换树状结构视图
F6 选择排序字段
F7 降低进程优先级
F8 提高进程优先级
F9 终止进程
F10 退出htop
空格 标记/取消标记进程
U 取消所有标记
K 终止所有标记的进程
/ 搜索
过滤
H 显示/隐藏用户线程
I 显示/隐藏空闲进程
P 按CPU使用率排序
M 按内存使用率排序
T 按CPU时间排序
1 显示所有CPU核心

atop 命令

atop 是一个高级的性能监控工具,不仅可以实时监控系统状态,还可以记录历史数据以便后续分析。

安装

# 在Debian/Ubuntu系统上安装
sudo apt install atop

# 在CentOS/RHEL系统上安装
sudo yum install atop

# 在Fedora系统上安装
sudo dnf install atop

基本用法

# 启动atop命令
atop

# 以批处理模式运行,显示指定次数后退出
atop -b -n 1

# 查看历史数据
atop -r /var/log/atop/atop_20240101

# 设置更新间隔(秒)
atop -i 2

交互式命令

在atop运行时,可以使用以下快捷键:

快捷键 功能
h 显示帮助信息
q 退出atop
a 按CPU使用率排序
m 按内存使用率排序
d 按磁盘I/O排序
n 按网络I/O排序
c 显示/隐藏命令行
u 显示/隐藏用户信息
t 向前/向后查看历史数据(在查看历史文件时)
b 显示/隐藏平均负载和CPU使用率
w 显示/隐藏交换空间使用情况
l 显示/隐藏磁盘统计信息
e 显示/隐藏进程环境变量

glances 命令

glances 是一个跨平台的系统监控工具,提供了更丰富的信息和更现代化的界面。

安装

# 使用pip安装
sudo pip install glances

# 在Debian/Ubuntu系统上安装
sudo apt install glances

# 在CentOS/RHEL系统上安装
sudo yum install glances

# 在Fedora系统上安装
sudo dnf install glances

基本用法

# 启动glances命令
glances

# 以Web服务器模式运行
glances -w

# 以客户端/服务器模式运行
# 服务器端
glances -s
# 客户端
glances -c server_ip

# 以批处理模式运行,显示指定次数后退出
glances -b -n 1

交互式命令

在glances运行时,可以使用以下快捷键:

快捷键 功能
h 显示帮助信息
q 退出glances
c 按CPU使用率排序
m 按内存使用率排序
i 按I/O使用率排序
p 按进程名称排序
d 显示/隐藏磁盘I/O统计信息
n 显示/隐藏网络统计信息
s 显示/隐藏传感器信息
t 显示/隐藏顶部进程
w 切换到Web界面
z 切换彩色/单色模式
1 切换全局/每个CPU的统计信息

其他进程监控工具

pidstat 命令

pidstatsysstat 包的一部分,用于监控进程的详细统计信息。

# 安装sysstat
sudo apt install sysstat  # Debian/Ubuntu
sudo yum install sysstat  # CentOS/RHEL

# 监控所有进程的CPU使用率
pidstat

# 监控指定PID的进程
pidstat -p PID

# 监控进程的内存使用情况
pidstat -r

# 监控进程的I/O情况
pidstat -d

# 定期输出统计信息
pidstat 1 5  # 每1秒输出一次,共输出5次

psacct 工具集

psacct 工具集用于监控进程的活动和资源使用情况。

# 安装psacct
sudo apt install acct  # Debian/Ubuntu
sudo yum install psacct  # CentOS/RHEL

# 查看进程的CPU使用情况
lastcomm

# 查看用户的CPU使用情况
ac

# 查看命令的使用情况
sa

systemtap 工具

systemtap 是一个高级的系统监控和故障诊断工具。

# 安装systemtap
sudo apt install systemtap  # Debian/Ubuntu
sudo yum install systemtap  # CentOS/RHEL

# 示例:监控进程创建和终止
stap -e 'probe syscall.fork, syscall.vfork, syscall.clone { printf("Process created by %d\n", pid()); } probe syscall.exit { printf("Process %d exited\n", pid()); }'

实用案例分析

案例1:实时监控系统资源

# 使用top实时监控
top

# 使用htop实时监控(更友好的界面)
htop

# 使用glances实时监控(更丰富的信息)
glances

# 使用atop实时监控(更详细的统计)
atop

案例2:监控特定进程

# 使用top监控特定进程
top -p $(pgrep nginx | head -1)

# 使用htop监控特定进程
htop -p $(pgrep nginx | head -1)

# 使用pidstat监控特定进程的详细信息
pidstat -p $(pgrep nginx | head -1) 1 10

# 使用glances监控特定进程
glances --process-filter nginx

案例3:历史数据分析

# 使用atop查看历史数据
atop -r /var/log/atop/atop_$(date +%Y%m%d)

# 在atop中查看特定时间点的数据
# 启动atop后,使用t键向前/向后移动

# 使用sar查看历史数据(sysstat的一部分)
sar -u  # CPU使用情况
sar -r  # 内存使用情况
sar -d  # 磁盘I/O情况

案例4:远程监控

# 使用glances的客户端/服务器模式
# 服务器端
glances -s

# 客户端
glances -c server_ip

# 使用SSH远程运行监控命令
ssh user@server "top -b -n 1"

# 使用netstat监控网络连接
netstat -tuln

# 使用ss监控网络连接(更现代的工具)
ss -tuln

案例5:系统瓶颈分析

# 分析CPU瓶颈
# 使用top查看CPU使用率高的进程
top

# 分析内存瓶颈
# 使用top或htop查看内存使用率高的进程
top -o %MEM

# 分析磁盘I/O瓶颈
# 使用iostat查看磁盘I/O情况
iostat -x

# 使用atop查看磁盘I/O情况
atop -d

# 分析网络瓶颈
# 使用netstat或ss查看网络连接
netstat -tuln

# 使用iftop查看网络流量
iftop

代码示例

示例1:系统监控脚本

#!/bin/bash

# 系统监控脚本

# 显示帮助信息
show_help() {
    echo "系统监控脚本"
    echo "用法: $0 [选项]"
    echo "选项:"
    echo "  -c, --cpu                监控CPU使用情况"
    echo "  -m, --mem                监控内存使用情况"
    echo "  -d, --disk               监控磁盘使用情况"
    echo "  -n, --net                监控网络使用情况"
    echo "  -p, --process <name>     监控指定进程"
    echo "  -a, --all                监控所有资源"
    echo "  -i, --interval <sec>     监控间隔(秒),默认1秒"
    echo "  -t, --time <sec>         监控时长(秒),默认无限"
    echo "  -h, --help               显示帮助信息"
}

# 解析命令行参数
CPU=false
MEM=false
DISK=false
NET=false
PROCESS=""
ALL=false
INTERVAL=1
TIME=0

while [[ $# -gt 0 ]]; do
    case $1 in
        -c|--cpu)
            CPU=true
            shift
            ;;
        -m|--mem)
            MEM=true
            shift
            ;;
        -d|--disk)
            DISK=true
            shift
            ;;
        -n|--net)
            NET=true
            shift
            ;;
        -p|--process)
            PROCESS="$2"
            shift 2
            ;;
        -a|--all)
            ALL=true
            CPU=true
            MEM=true
            DISK=true
            NET=true
            shift
            ;;
        -i|--interval)
            INTERVAL="$2"
            shift 2
            ;;
        -t|--time)
            TIME="$2"
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            echo "未知选项: $1"
            show_help
            exit 1
            ;;
    esac
done

# 检查参数
if [[ $CPU == false && $MEM == false && $DISK == false && $NET == false && -z "$PROCESS" ]]; then
    echo "错误: 必须指定至少一个监控选项"
    show_help
    exit 1
fi

# 开始监控
echo "=== 系统监控开始 ==="
echo "监控时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "监控间隔: $INTERVAL 秒"
if [[ $TIME -gt 0 ]]; then
    echo "监控时长: $TIME 秒"
fi
echo ""

# 计算结束时间
if [[ $TIME -gt 0 ]]; then
    end_time=$(( $(date +%s) + $TIME ))
fi

# 监控循环
while true; do
    # 检查是否达到结束时间
    if [[ $TIME -gt 0 && $(date +%s) -ge $end_time ]]; then
        break
    fi
    
    # 显示当前时间
    echo "[$(date '+%Y-%m-%d %H:%M:%S')]"
    echo ""
    
    # 监控CPU
    if $CPU; then
        echo "=== CPU使用情况 ==="
        mpstat
        echo ""
    fi
    
    # 监控内存
    if $MEM; then
        echo "=== 内存使用情况 ==="
        free -h
        echo ""
    fi
    
    # 监控磁盘
    if $DISK; then
        echo "=== 磁盘使用情况 ==="
        df -h
        echo ""
        
        echo "=== 磁盘I/O情况 ==="
        iostat -x
        echo ""
    fi
    
    # 监控网络
    if $NET; then
        echo "=== 网络使用情况 ==="
        netstat -tuln
        echo ""
        
        echo "=== 网络连接情况 ==="
        ss -s
        echo ""
    fi
    
    # 监控特定进程
    if [[ -n "$PROCESS" ]]; then
        echo "=== 进程 '$PROCESS' 状态 ==="
        pgrep -a "$PROCESS"
        if [[ $? -eq 0 ]]; then
            pid=$(pgrep -f "$PROCESS" | head -1)
            if [[ -n "$pid" ]]; then
                ps -p $pid -o pid,ppid,user,%cpu,%mem,state,command
                echo ""
                
                echo "=== 进程 '$pid' 详细统计 ==="
                pidstat -p $pid
            fi
        else
            echo "进程 '$PROCESS' 不存在"
        fi
        echo ""
    fi
    
    # 等待指定的间隔
    sleep $INTERVAL
done

echo "=== 系统监控结束 ==="
echo "结束时间: $(date '+%Y-%m-%d %H:%M:%S')"

示例2:进程资源使用监控脚本

#!/bin/bash

# 进程资源使用监控脚本

# 显示帮助信息
show_help() {
    echo "进程资源使用监控脚本"
    echo "用法: $0 [选项]"
    echo "选项:"
    echo "  -p, --pid <pid>         监控指定PID的进程"
    echo "  -n, --name <name>       监控指定名称的进程"
    echo "  -i, --interval <sec>    监控间隔(秒),默认1秒"
    echo "  -c, --count <num>       监控次数,默认无限"
    echo "  -o, --output <file>     将监控结果输出到文件"
    echo "  -h, --help              显示帮助信息"
}

# 解析命令行参数
PID=""
NAME=""
INTERVAL=1
COUNT=-1
OUTPUT=""

while [[ $# -gt 0 ]]; do
    case $1 in
        -p|--pid)
            PID="$2"
            shift 2
            ;;
        -n|--name)
            NAME="$2"
            shift 2
            ;;
        -i|--interval)
            INTERVAL="$2"
            shift 2
            ;;
        -c|--count)
            COUNT="$2"
            shift 2
            ;;
        -o|--output)
            OUTPUT="$2"
            shift 2
            ;;
        -h|--help)
            show_help
            exit 0
            ;;
        *)
            echo "未知选项: $1"
            show_help
            exit 1
            ;;
    esac
done

# 检查参数
if [[ -z "$PID" && -z "$NAME" ]]; then
    echo "错误: 必须指定PID或进程名称"
    show_help
    exit 1
fi

# 如果指定了进程名称,获取其PID
if [[ -n "$NAME" ]]; then
    PID=$(pgrep -f "$NAME" | head -1)
    if [[ -z "$PID" ]]; then
        echo "错误: 找不到名称为 '$NAME' 的进程"
        exit 1
    fi
    echo "找到进程 '$NAME',PID: $PID"
fi

# 准备输出文件
if [[ -n "$OUTPUT" ]]; then
    echo "=== 进程资源使用监控 ===" > "$OUTPUT"
    echo "监控进程: $PID" >> "$OUTPUT"
    echo "监控时间: $(date '+%Y-%m-%d %H:%M:%S')" >> "$OUTPUT"
    echo "监控间隔: $INTERVAL 秒" >> "$OUTPUT"
    if [[ $COUNT -gt 0 ]]; then
        echo "监控次数: $COUNT" >> "$OUTPUT"
    fi
    echo "" >> "$OUTPUT"
    echo "时间,PID,CPU使用率,内存使用率,虚拟内存(KB),物理内存(KB),状态,命令" >> "$OUTPUT"
fi

# 监控循环
iteration=0
while true; do
    # 检查进程是否存在
    if ! ps -p $PID > /dev/null 2>&1; then
        echo "进程 $PID 不存在或已结束"
        if [[ -n "$OUTPUT" ]]; then
            echo "进程 $PID 不存在或已结束" >> "$OUTPUT"
        fi
        break
    fi
    
    # 获取当前时间
    current_time=$(date '+%Y-%m-%d %H:%M:%S')
    
    # 获取进程状态
    process_info=$(ps -p $PID -o pid,%cpu,%mem,vsz,rss,state,command --no-headers)
    
    # 提取信息
    read -r pid cpu mem vsz rss state command <<< "$process_info"
    
    # 显示信息
    echo "[$current_time] 进程 $PID 状态:"
    echo "CPU使用率: $cpu%"
    echo "内存使用率: $mem%"
    echo "虚拟内存: $vsz KB"
    echo "物理内存: $rss KB"
    echo "状态: $state"
    echo "命令: $command"
    echo ""
    
    # 输出到文件
    if [[ -n "$OUTPUT" ]]; then
        echo "$current_time,$pid,$cpu,$mem,$vsz,$rss,$state,\"$command\"" >> "$OUTPUT"
    fi
    
    # 增加迭代计数
    iteration=$((iteration + 1))
    
    # 检查是否达到指定的监控次数
    if [[ $COUNT -gt 0 && $iteration -ge $COUNT ]]; then
        break
    fi
    
    # 等待指定的间隔
    sleep $INTERVAL
done

echo "监控结束"
if [[ -n "$OUTPUT" ]]; then
    echo "监控结束时间: $(date '+%Y-%m-%d %H:%M:%S')" >> "$OUTPUT"
    echo "监控结果已保存到: $OUTPUT"
fi

示例3:系统负载监控与告警脚本

#!/bin/bash

# 系统负载监控与告警脚本

# 配置告警阈值
CPU_THRESHOLD=80  # CPU使用率阈值(%)
MEM_THRESHOLD=80  # 内存使用率阈值(%)
DISK_THRESHOLD=90  # 磁盘使用率阈值(%)
LOAD_THRESHOLD=1.0  # 系统负载阈值(每个CPU核心)

# 监控间隔
INTERVAL=60  # 秒

# 告警日志文件
ALERT_LOG="/var/log/system_alert.log"

# 创建告警日志文件
if [[ ! -f "$ALERT_LOG" ]]; then
    touch "$ALERT_LOG"
    chmod 644 "$ALERT_LOG"
fi

# 发送告警
send_alert() {
    local message="$1"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    
    echo "[$timestamp] ALERT: $message" >> "$ALERT_LOG"
    echo "[$timestamp] ALERT: $message"
    
    # 这里可以添加发送邮件或其他通知的代码
    # 例如:echo "$message" | mail -s "System Alert" admin@example.com
}

# 监控CPU使用情况
monitor_cpu() {
    local cpu_usage=$(mpstat | awk '/all/{print 100 - $NF}')
    local cpu_usage_int=$(printf "%.0f" "$cpu_usage")
    
    if [[ $cpu_usage_int -ge $CPU_THRESHOLD ]]; then
        send_alert "CPU使用率过高: ${cpu_usage_int}%"
    fi
}

# 监控内存使用情况
monitor_memory() {
    local mem_total=$(free | awk '/Mem/{print $2}')
    local mem_used=$(free | awk '/Mem/{print $3}')
    local mem_usage=$((mem_used * 100 / mem_total))
    
    if [[ $mem_usage -ge $MEM_THRESHOLD ]]; then
        send_alert "内存使用率过高: ${mem_usage}%"
    fi
}

# 监控磁盘使用情况
monitor_disk() {
    local disk_usage=$(df -h | grep -v tmpfs | grep -v devtmpfs | awk '{print $5}' | sed 's/%//g')
    
    for usage in $disk_usage; do
        if [[ $usage -ge $DISK_THRESHOLD ]]; then
            local mount_point=$(df -h | grep -v tmpfs | grep -v devtmpfs | grep " ${usage}%" | awk '{print $6}')
            send_alert "磁盘使用率过高: ${usage}% (挂载点: $mount_point)"
        fi
    done
}

# 监控系统负载
monitor_load() {
    local load_avg=$(uptime | awk -F'load average:' '{print $2}' | awk '{print $1}')
    local cpu_count=$(nproc)
    local load_per_cpu=$(echo "$load_avg / $cpu_count" | bc -l)
    local load_per_cpu_int=$(printf "%.1f" "$load_per_cpu")
    
    if (( $(echo "$load_per_cpu_int >= $LOAD_THRESHOLD" | bc -l) )); then
        send_alert "系统负载过高: ${load_avg} (每CPU核心: ${load_per_cpu_int})"
    fi
}

# 主监控函数
main_monitor() {
    echo "=== 系统负载监控开始 ==="
    echo "监控时间: $(date '+%Y-%m-%d %H:%M:%S')"
    echo "监控间隔: $INTERVAL 秒"
    echo "告警日志: $ALERT_LOG"
    echo ""
    
    while true; do
        # 监控各项指标
        monitor_cpu
        monitor_memory
        monitor_disk
        monitor_load
        
        # 等待指定的间隔
        sleep $INTERVAL
    done
}

# 运行监控
main_monitor

总结

本集介绍了 Linux 中常用的进程监控工具,包括:

  1. top 命令:最基本的进程监控工具,默认安装在所有Linux系统中
  2. htop 命令:top 的增强版本,提供更友好的界面和更多功能
  3. atop 命令:高级性能监控工具,支持历史数据记录和分析
  4. glances 命令:跨平台系统监控工具,提供丰富的信息和现代化界面
  5. 其他进程监控工具:如 pidstatpsacctsystemtap

同时,本集还介绍了这些工具的安装方法、基本用法、交互式命令和输出解释,以及多个实用案例和代码示例,包括:

  • 实时监控系统资源
  • 监控特定进程
  • 历史数据分析
  • 远程监控
  • 系统瓶颈分析
  • 系统监控脚本
  • 进程资源使用监控脚本
  • 系统负载监控与告警脚本

通过掌握这些进程监控工具,用户可以更好地了解系统的运行状态,及时发现和解决性能问题,从而提高系统的稳定性和可靠性。在实际工作中,应根据具体需求选择合适的监控工具,并结合自动化脚本实现持续监控和告警。

« 上一篇 进程查看命令 下一篇 » 进程控制命令