Shell脚本如何监控文件句柄数

wen 实用脚本 2

本文目录导读:

Shell脚本如何监控文件句柄数

  1. 监控当前进程的文件句柄数
  2. 监控系统全局的文件句柄数
  3. 完整的监控脚本(带告警和日志)
  4. 单次检查脚本(适合crontab定时执行)
  5. 使用注意事项

在Shell脚本中监控文件句柄数主要有以下几种方法,我会提供完整的脚本示例:

监控当前进程的文件句柄数

#!/bin/bash
# 监控指定进程的文件句柄数
PROCESS_NAME="nginx"  # 替换为你需要监控的进程名
PID=$(pgrep -f "$PROCESS_NAME" | head -1)
if [ -z "$PID" ]; then
    echo "进程 $PROCESS_NAME 不存在"
    exit 1
fi
# 方法1:通过 /proc 文件系统
FD_COUNT=$(ls -l /proc/$PID/fd/ 2>/dev/null | wc -l)
echo "进程 $PROCESS_NAME (PID: $PID) 当前文件句柄数: $FD_COUNT"
# 方法2:通过 lsof 命令
LSOF_COUNT=$(lsof -p $PID 2>/dev/null | wc -l)
echo "进程 $PROCESS_NAME (PID: $PID) 通过lsof统计的句柄数: $LSOF_COUNT"
# 方法3:读取 /proc/pid/fd 目录计数
FD_COUNT_V2=$(find /proc/$PID/fd -type l 2>/dev/null | wc -l)
echo "进程 $PROCESS_NAME (PID: $PID) 文件描述符数量: $FD_COUNT_V2"

监控系统全局的文件句柄数

#!/bin/bash
# 获取系统文件句柄信息
get_system_fd_info() {
    echo "=== 系统文件句柄信息 ==="
    # 已分配的句柄数
    ALLOCATED=$(cat /proc/sys/fs/file-nr | awk '{print $1}')
    echo "已分配的文件句柄数: $ALLOCATED"
    # 未使用的句柄数
    UNUSED=$(cat /proc/sys/fs/file-nr | awk '{print $2}')
    echo "未使用的文件句柄数: $UNUSED"
    # 最大文件句柄数
    MAX_FD=$(cat /proc/sys/fs/file-max)
    echo "系统最大文件句柄数: $MAX_FD"
    # 使用率计算
    if [ "$MAX_FD" -gt 0 ]; then
        USED_PERCENT=$(echo "scale=2; $ALLOCATED * 100 / $MAX_FD" | bc)
        echo "文件句柄使用率: ${USED_PERCENT}%"
    fi
}
# 执行监控
get_system_fd_info

完整的监控脚本(带告警和日志)

#!/bin/bash
# ========== 配置区域 ==========
PROCESS_NAME="java"  # 需要监控的进程名
ALERT_THRESHOLD=80   # 告警阈值(百分比)
CHECK_INTERVAL=60    # 检查间隔(秒)
LOG_FILE="/var/log/fd_monitor.log"
# ========== 日志函数 ==========
log_message() {
    local LEVEL=$1
    local MESSAGE=$2
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] [$LEVEL] $MESSAGE" | tee -a "$LOG_FILE"
}
# ========== 获取进程文件句柄数 ==========
get_process_fd_count() {
    local process_name=$1
    local pid=$(pgrep -f "$process_name" | head -1)
    if [ -z "$pid" ]; then
        log_message "WARN" "进程 $process_name 未运行"
        return 1
    fi
    local fd_count=$(ls -l /proc/$pid/fd/ 2>/dev/null | wc -l)
    if [ -z "$fd_count" ]; then
        log_message "ERROR" "无法获取进程 $process_name (PID: $pid) 的文件句柄数"
        return 1
    fi
    echo "$fd_count"
    return 0
}
# ========== 监控系统文件句柄 ==========
monitor_system_fd() {
    local allocated=$(cat /proc/sys/fs/file-nr 2>/dev/null | awk '{print $1}')
    local max_fd=$(cat /proc/sys/fs/file-max 2>/dev/null)
    if [ -n "$allocated" ] && [ -n "$max_fd" ] && [ "$max_fd" -gt 0 ]; then
        local usage_percent=$(echo "scale=2; $allocated * 100 / $max_fd" | bc)
        echo "系统状态 - 已分配: $allocated, 最大: $max_fd, 使用率: ${usage_percent}%"
        # 检查告警阈值
        if (( $(echo "$usage_percent > $ALERT_THRESHOLD" | bc -l) )); then
            log_message "ALERT" "警告: 系统文件句柄使用率 ${usage_percent}% 超过阈值 ${ALERT_THRESHOLD}%"
            return 2
        fi
    else
        log_message "ERROR" "无法获取系统文件句柄信息"
        return 1
    fi
    return 0
}
# ========== 主监控循环 ==========
monitor_loop() {
    log_message "INFO" "文件句柄监控启动 - 进程: $PROCESS_NAME, 告警阈值: ${ALERT_THRESHOLD}%, 检查间隔: ${CHECK_INTERVAL}s"
    while true; do
        # 获取进程文件句柄数
        local fd_count=$(get_process_fd_count "$PROCESS_NAME")
        local return_code=$?
        if [ $return_code -eq 0 ] && [ -n "$fd_count" ]; then
            log_message "INFO" "进程 $PROCESS_NAME 文件句柄数: $fd_count"
        fi
        # 监控系统文件句柄
        monitor_system_fd
        local sys_status=$?
        if [ $sys_status -eq 2 ]; then
            # 触发告警时,可以添加额外的操作
            log_message "INFO" "告警触发,准备执行恢复操作..."
            # 这里可以添加清理操作或通知管理员
        fi
        # 等待下一次检查
        sleep "$CHECK_INTERVAL"
    done
}
# ========== 主程序 ==========
main() {
    # 检查必要的命令
    for cmd in bc pgrep; do
        if ! command -v $cmd &> /dev/null; then
            echo "错误: 需要安装 $cmd 命令"
            exit 1
        fi
    done
    # 创建日志目录
    mkdir -p "$(dirname "$LOG_FILE")" 2>/dev/null
    # 启动监控循环
    monitor_loop
}
# 运行主程序
main

单次检查脚本(适合crontab定时执行)

#!/bin/bash
# 单次检查脚本 - 适合crontab定时执行
# 用法: */5 * * * * /path/to/check_fd.sh
ALERT_EMAIL="admin@example.com"
THRESHOLD=90
# 检查系统文件句柄
ALLOCATED=$(cat /proc/sys/fs/file-nr | awk '{print $1}')
MAX_FD=$(cat /proc/sys/fs/file-max)
USED_PERCENT=$(echo "scale=2; $ALLOCATED * 100 / $MAX_FD" | bc)
echo "文件句柄使用率: ${USED_PERCENT}%"
# 告警检查
if (( $(echo "$USED_PERCENT > $THRESHOLD" | bc -l) )); then
    echo "警告: 文件句柄使用率 ${USED_PERCENT}% 超出阈值 ${THRESHOLD}%" | \
        mail -s "文件句柄告警 - $(hostname)" "$ALERT_EMAIL"
    # 显示占用最多的进程
    echo "占用文件句柄最多的进程:"
    for pid in $(ls /proc/ | grep -E '^[0-9]+$' | head -20); do
        fd_count=$(ls -l /proc/$pid/fd 2>/dev/null | wc -l)
        if [ "$fd_count" -gt 0 ]; then
            process_name=$(cat /proc/$pid/comm 2>/dev/null)
            echo "PID: $pid, 名称: $process_name, 句柄数: $fd_count"
        fi
    done | sort -t: -k3 -n | tail -10
fi

使用注意事项

权限要求

# 普通用户只能查看自己的进程
# 查看所有进程需要root权限
sudo ./monitor_fd.sh

crontab定时任务配置

# 每5分钟检查一次
*/5 * * * * /path/to/check_fd.sh
# 每1小时记录一次
0 * * * * /path/to/record_fd.sh

这个监控脚本可以帮助你及时发现文件句柄泄漏问题,防止系统资源耗尽。

抱歉,评论功能暂时关闭!