Linux系统CPU高负载排查

Linux系统CPU高负载排查

一、核心排查工具

1. PS命令

基础进程查询

# 按CPU使用率降序排序(显示前10)
ps aux --sort=-%cpu | head -n 11

# 按内存使用率排序
ps aux --sort=-%mem | head -n 5

# 按运行时间排序
ps aux --sort=-time | head -n 5

线程级分析

# 查看指定进程的所有线程
ps -eLf | grep [PID]

# 按CPU时间排序线程
ps -mp [PID] -o THREAD,tid,time | sort -rn

# 显示线程状态
ps -T -p [PID]

进程树分析

# 显示进程树关系
pstree -p [PID]

# 显示完整进程信息
ps -fp [PID]

2. TOP命令高级用法

# 实时监控(按CPU排序)
top -o %CPU

# 指定更新间隔
top -d 2 -n 5

# 线程级监控
top -H -p [PID]

二、组合排查策略

1. 组合使用

# 组合TOP和PS
top -b -n 1 | grep "Cpu(s)" && ps aux --sort=-%cpu | head -n 11

# 综合资源分析
ps aux --sort=-%cpu,-%mem | head -n 11

2. 历史记录关联分析

# 结合历史命令排查
history | grep [PID]

# 检查最近登录
last | grep "pts"

三、场景示例

场景1:Java应用高CPU排查

# 1. 定位Java进程
ps aux | grep java | sort -k3 -nr | head -n 5

# 2. 线程分析
ps -mp [PID] -o THREAD,tid,time | sort -rn

# 3. 线程转储
jstack [PID] | grep -A 20 [TID]

场景2:系统进程异常

# 1. 检查系统进程
ps aux | grep -E 'systemd|kernel' | sort -k3 -nr | head -n 5

# 2. 内核线程检查
cat /proc/[PID]/status | grep Threads

# 3. 进程权限检查
ls -l /proc/[PID]/exe

四、进阶分析技巧

1. 实时监控脚本

# 动态监控脚本
watch -n 1 "ps aux --sort=-%cpu | head -n 11"

# 资源趋势记录
while true; do 
    date +"%H:%M:%S"; 
    ps aux --sort=-%cpu | head -n 5; 
    sleep 5; 
done > cpu_monitor.log

2. 日志关联分析

# 结合系统日志
grep "CPU load" /var/log/messages | tail -n 20

# 应用日志分析
grep "ERROR" /var/log/app.log | awk '{print $2}'

3. 性能基线建立

# 建立性能基线
ps aux --sort=-%cpu > baseline_$(date +%Y%m%d).txt

# 对比分析
diff baseline_20250821.txt current_scan.txt

3. 完整脚本

# cpu_monitor.sh
#!/bin/sh
# 智能CPU监控脚本(带后台控制)

THRESHOLD=300
CHANGE_THRESHOLD=10
LOG_DIR="$(dirname "$0")/cpu_logs"
MAX_LOG_DAYS=7
CHECK_INTERVAL=60
PID_FILE="/tmp/cpu_monitor.pid"

case "$1" in
    start)
        if [ -f "$PID_FILE" ]; then
            if kill -0 $(cat "$PID_FILE") 2>/dev/null; then
                echo "监控已在运行 (PID: $(cat "$PID_FILE"))"
                exit 1
            else
                rm -f "$PID_FILE"
            fi
        fi

        nohup "$0" daemon >/dev/null 2>&1 &
        echo $! > "$PID_FILE"
        echo "CPU监控已启动 (PID: $!)"
        ;;
    stop)
        if [ -f "$PID_FILE" ]; then
            PID=$(cat "$PID_FILE")
            if kill -0 $PID 2>/dev/null; then
                kill $PID
                rm -f "$PID_FILE"
                echo "CPU监控已停止"
            else
                rm -f "$PID_FILE"
                echo "监控进程不存在,已清理PID文件"
            fi
        else
            echo "监控未运行"
        fi
        ;;
    status)
        if [ -f "$PID_FILE" ]; then
            PID=$(cat "$PID_FILE")
            if kill -0 $PID 2>/dev/null; then
                echo "CPU监控正在运行 (PID: $PID)"
            else
                rm -f "$PID_FILE"
                echo "监控进程已停止"
            fi
        else
            echo "监控未运行"
        fi
        ;;
    daemon)
        clean_old_logs() {
            mkdir -p "$LOG_DIR"
            find "$LOG_DIR" -name "cpu_alert_*.log" -mtime +$MAX_LOG_DAYS -exec rm {} \;
        }

        last_sum=0
        last_alert_time=0

        monitor() {
            clean_old_logs
            current_sum=$(ps -eo %cpu --sort=-%cpu | head -n 10 | awk '{s+=$1} END {print int(s)}')
            current_time=$(date +%s)
            sum_diff=$((current_sum - last_sum))

            if [ "$current_sum" -gt "$THRESHOLD" ]; then
                if [ "$last_sum" -le "$THRESHOLD" ] || \
                   [ $((current_time - last_alert_time)) -ge 3600 ] || \
                   [ ${sum_diff#-} -ge "$CHANGE_THRESHOLD" ]; then
                    log_alert "$current_sum" "$sum_diff"
                    last_alert_time=$current_time
                fi
            fi
            last_sum=$current_sum
        }

        log_alert() {
            log_file="$LOG_DIR/cpu_alert_$(date +%Y%m%d).log"
            echo "[$(date "+%Y-%m-%d %H:%M:%S")] CPU负载警报: $1% (变化: $2%)" >> "$log_file"
            ps -eo pid,user,ppid,%cpu,cmd --sort=-%cpu | head -n 11 >> "$log_file"
            echo "----------------------------------------" >> "$log_file"
        }

        trap "rm -f '$PID_FILE'; exit 0" INT TERM
        while :; do
            monitor
            sleep "$CHECK_INTERVAL"
        done
        ;;
    *)
        echo "用法: $0 {start|stop|status}"
        exit 1
        ;;
esac


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值