云边日落 当局者迷,旁观者清。 (新唐书·元行冲传)
博主 云边日落
渝ICP备2021002886号-1渝公网安备50022502000591号博主 11月5日 在线自豪地使用 Typecho 建站搭配使用 🌻Sunny 主题当前在线 1 人
歌曲封面 未知作品
  • 歌曲封面“魔女の宅急便”~ルージュの伝言松任谷由実

渝ICP备2021002886号-1

渝公网安备50022502000591号

网站已运行 4 年 152 天 15 小时 8 分

Powered by Typecho & Sunny

2 online · 44 ms

Title

针对绿云服务器带宽和CPU监控自动化: Bash脚本实现

酒笙

·

·

237次阅读
笔记留存
Article

使用 Bash 脚本实现服务器资源监控与限制

首先声明,绿云是垃圾。
这个脚本主要是针对绿云的限制写的,没办法,他真的很垃圾。
本文将介绍如何编写一个 Bash 脚本,通过配置文件设定参数,实现对服务器带宽和 CPU 使用率的监控与限制,同时支持通过飞书 Webhook 发送通知。

一、配置文件 config.cfg

首先,我们需要定义一个配置文件,用于存储各种参数,便于后续脚本的读取和使用。以下是配置文件的内容:

♾️ bash 代码:
# 配置参数

# 网络接口
INTERFACE="ens3"  # 请替换为您的实际网络接口名称

# 带宽限制配置(单位:Mbps)
MAX_BANDWIDTH=10000          # 最大带宽限制(10Gbps)
LIMITED_BANDWIDTH=100        # 限制后的带宽(100Mbps)

# 带宽阈值
BANDWIDTH_THRESHOLD=100      # 带宽阈值(100Mbps)

# 爆发事件判定带宽
BURST_THRESHOLD=9500         # 爆发事件判断阈值(9.5Gbps)

# 爆发次数限制
BURST_TIME_WINDOW=10800      # 爆发次数统计的时间窗口(秒),3小时 = 10800秒
BURST_LIMIT_DURATION=3600    # 带宽限制持续时间(秒),1小时 = 3600秒

# 6小时持续高带宽使用限制
HIGH_USAGE_DURATION_LIMIT=21600  # 持续高带宽使用的时间限制(秒),6小时 = 21600秒
HIGH_USAGE_LIMIT_DURATION=3600   # 高带宽使用限制持续时间(秒),1小时 = 3600秒

# 带宽下降宽限期(秒)
BANDWIDTH_DROP_GRACE_PERIOD=300  # 5分钟

# CPU 使用率限制(百分比)
CPU_AVG_LIMIT=30               # 平均 CPU 使用率限制
CPU_BURST_LIMIT=100            # CPU 突发使用率限制
BURST_DURATION=600             # 突发允许持续时间(秒),例如 600 秒为 10 分钟

# 监控间隔(秒)
MONITOR_INTERVAL=60            # 监控资源使用的时间间隔

# 日志文件
LOG_FILE="/var/log/resource_monitor.log"

# 飞书 Webhook 地址
FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/你的-webhook-url"

配置参数解释

  • INTERFACE:需要监控的网络接口名称,需替换为实际的接口名称。
  • MAX_BANDWIDTH:最大允许的带宽限制,默认是 10Gbps。
  • LIMITED_BANDWIDTH:当触发限制时,将带宽限制到该值,默认是 100Mbps。
  • BANDWIDTH_THRESHOLD:带宽使用达到该值时,开始计时监控高带宽使用情况。
  • BURST_THRESHOLD:带宽使用超过该值时,判定为一次带宽爆发事件。
  • BURST_TIME_WINDOW:统计带宽爆发事件的时间窗口,默认是 3 小时。
  • BURST_LIMIT_DURATION:当带宽爆发次数过多时,限制带宽的持续时间,默认是 1 小时。
  • HIGH_USAGE_DURATION_LIMIT:持续高带宽使用的时间限制,默认是 6 小时。
  • HIGH_USAGE_LIMIT_DURATION:当持续高带宽使用达到限制时,限制带宽的持续时间,默认是 1 小时。
  • BANDWIDTH_DROP_GRACE_PERIOD:带宽使用下降时的宽限期,默认是 5 分钟。
  • CPU_AVG_LIMIT:CPU 平均使用率的限制,超过该值开始监控突发使用。
  • CPU_BURST_LIMIT:CPU 突发使用率的限制,超过且持续一定时间将触发限制措施。
  • BURST_DURATION:CPU 突发使用率的持续时间阈值,超过该时间将触发限制措施。
  • MONITOR_INTERVAL:资源监控的时间间隔,默认是 60 秒。
  • LOG_FILE:日志文件的路径。
  • FEISHU_WEBHOOK_URL:飞书机器人 Webhook 地址,用于发送通知。

二、将脚本设置为系统服务

为了使脚本能够持续运行并在系统启动时自动启动,我们需要将其设置为一个系统服务。以下是查看服务状态的命令输出:

♾️ bash 代码:
root@server:~# systemctl status resource_monitor.service
● resource_monitor.service - Resource Monitor Service
     Loaded: loaded (/etc/systemd/system/resource_monitor.service; enabled; vendor preset: enabled)
     Active: active (running) since Fri 2023-10-20 11:34:14 BST; 36min ago
   Main PID: 38113 (bash)
      Tasks: 3
     Memory: 5.2M
     CGroup: /system.slice/resource_monitor.service
             ├─38113 /usr/bin/bash /usr/local/bin/resource_monitor.sh
             ├─39463 /usr/bin/bash /usr/local/bin/resource_monitor.sh
             └─39466 sleep 60

Oct 20 11:58:14 server bash[38715]: 2023-10-20 11:58:14 - CPU 限制已移除
Oct 20 11:59:14 server bash[38736]: 2023-10-20 11:59:14 - 当前带宽使用:0 Mbps
Oct 20 12:00:14 server bash[38760]: 2023-10-20 12:00:14 - 当前 CPU 使用率:0%
Oct 20 12:00:14 server bash[38763]: 2023-10-20 12:00:14 - CPU 限制已移除
Oct 20 12:01:14 server bash[39077]: 2023-10-20 12:01:14 - 当前带宽使用:0 Mbps
Oct 20 12:02:14 server bash[39209]: 2023-10-20 12:02:14 - 当前 CPU 使用率:67%
Oct 20 12:02:14 server bash[39212]: 2023-10-20 12:02:14 - CPU 使用率超过 30%,开始监控突发使用
Oct 20 12:09:15 server bash[39433]: 2023-10-20 12:09:15 - 当前带宽使用:0 Mbps
Oct 20 12:10:15 server bash[39457]: 2023-10-20 12:10:15 - 当前 CPU 使用率:0%
Oct 20 12:10:15 server bash[39460]: 2023-10-20 12:10:15 - CPU 限制已移除

三、核心脚本 resource_monitor.sh

以下是资源监控脚本的完整代码,我们将对其进行详细解释。

♾️ bash 代码:
#!/bin/bash

# 加载配置参数
CONFIG_FILE="/usr/local/bin/config.cfg"
if [ ! -f "$CONFIG_FILE" ]; then
  echo "配置文件 $CONFIG_FILE 未找到!"
  exit 1
fi
source "$CONFIG_FILE"

# 确保脚本以 root 用户运行
if [ "$EUID" -ne 0 ]; then
  echo "请以 root 用户运行此脚本。"
  exit 1
fi

# 检查必要的工具是否已安装
REQUIRED_TOOLS=("tc" "cgcreate" "cgdelete" "mpstat" "awk" "curl")
for tool in "${REQUIRED_TOOLS[@]}"; do
  if ! command -v "$tool" &>/dev/null; then
    echo "错误:$tool 未安装,请安装后再运行此脚本。"
    exit 1
  fi
done

# 初始化日志
echo "脚本在 $(date '+%Y-%m-%d %H:%M:%S') 启动" >> "$LOG_FILE"

log() {
  echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_FILE"
}

# 发送飞书通知
send_feishu_notification() {
  local message="$1"
  curl -X POST -H "Content-Type: application/json" \
    -d "{\"msg_type\": \"text\", \"content\": {\"text\": \"$message\"}}" \
    "$FEISHU_WEBHOOK_URL"
}

# 初始化带宽限制
initialize_bandwidth_limit() {
  tc qdisc del dev $INTERFACE root 2>/dev/null
  tc qdisc add dev $INTERFACE root handle 1: htb default 10
  tc class add dev $INTERFACE parent 1: classid 1:10 htb rate ${MAX_BANDWIDTH}mbit ceil ${MAX_BANDWIDTH}mbit
  log "带宽限制已初始化为 ${MAX_BANDWIDTH}Mbps 在接口 $INTERFACE 上"
}

# 设置带宽限制为限制后的带宽
set_limited_bandwidth() {
  tc class change dev $INTERFACE parent 1: classid 1:10 htb rate ${LIMITED_BANDWIDTH}mbit ceil ${LIMITED_BANDWIDTH}mbit
  bandwidth_limited=true
  bandwidth_limit_end_time=$(($(date +%s) + $1))
  log "带宽限制已降低到 ${LIMITED_BANDWIDTH}Mbps,限制持续 $(( $1 / 60 )) 分钟"
  send_feishu_notification "带宽已限制到 ${LIMITED_BANDWIDTH}Mbps,限制持续 $(( $1 / 60 )) 分钟。原因:$2"
}

# 恢复最大带宽限制
restore_max_bandwidth() {
  tc class change dev $INTERFACE parent 1: classid 1:10 htb rate ${MAX_BANDWIDTH}mbit ceil ${MAX_BANDWIDTH}mbit
  bandwidth_limited=false
  log "带宽限制已恢复到 ${MAX_BANDWIDTH}Mbps"
  send_feishu_notification "带宽限制已解除,恢复到 ${MAX_BANDWIDTH}Mbps。"
}

# 初始化 CPU 限制
initialize_cpu_limit() {
  cgcreate -g cpu:/cpulimited 2>/dev/null
  echo "$((CPU_AVG_LIMIT * 1000))" > /sys/fs/cgroup/cpu/cpulimited/cpu.cfs_quota_us
  echo "100000" > /sys/fs/cgroup/cpu/cpulimited/cpu.cfs_period_us
  # 将所有进程加入到限制组中
  for pid in $(ps -e -o pid=); do
    echo $pid > /sys/fs/cgroup/cpu/cpulimited/tasks 2>/dev/null
  done
  log "CPU 监控阈值已设置为 ${CPU_AVG_LIMIT}%,超过此值将触发限制机制"
}

# 移除 CPU 限制
remove_cpu_limit() {
  echo "-1" > /sys/fs/cgroup/cpu/cpulimited/cpu.cfs_quota_us
  log "CPU 限制已移除"
}

# 带宽使用监控函数
monitor_bandwidth_usage() {
  local rx_bytes_prev=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
  local tx_bytes_prev=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)
  sleep "$MONITOR_INTERVAL"
  local rx_bytes_curr=$(cat /sys/class/net/$INTERFACE/statistics/rx_bytes)
  local tx_bytes_curr=$(cat /sys/class/net/$INTERFACE/statistics/tx_bytes)

  local rx_rate=$(( (rx_bytes_curr - rx_bytes_prev) * 8 / MONITOR_INTERVAL ))  # bps
  local tx_rate=$(( (tx_bytes_curr - tx_bytes_prev) * 8 / MONITOR_INTERVAL ))  # bps

  local total_rate=$(( (rx_rate + tx_rate) / 1000000 ))  # Mbps

  echo "$total_rate"
}

# CPU 使用监控函数
monitor_cpu_usage() {
  local cpu_usage=$(mpstat "$MONITOR_INTERVAL" 1 | awk '/Average/ {print 100 - $NF}')
  echo "${cpu_usage%.*}"  # 转换为整数
}

# 清理函数
cleanup() {
  log "脚本退出,正在清理资源..."
  tc qdisc del dev $INTERFACE root 2>/dev/null
  cgdelete -g cpu:/cpulimited 2>/dev/null
  exit 0
}

trap cleanup SIGINT SIGTERM

# 初始化限制
initialize_bandwidth_limit
initialize_cpu_limit

# 初始化变量
burst_events=()
high_bandwidth_start_time=0
bandwidth_limited=false
bandwidth_limit_end_time=0
high_usage_limited=false
high_usage_limit_end_time=0
bandwidth_drop_start_time=0

# 主循环
while true; do
  # 获取当前时间
  current_time=$(date +%s)

  # 带宽监控
  bandwidth_usage=$(monitor_bandwidth_usage)
  log "当前带宽使用:${bandwidth_usage} Mbps"

  # 检查是否需要解除带宽限制
  if [ "$bandwidth_limited" = true ] && [ "$current_time" -ge "$bandwidth_limit_end_time" ]; then
    restore_max_bandwidth
  fi
  if [ "$high_usage_limited" = true ] && [ "$current_time" -ge "$high_usage_limit_end_time" ]; then
    restore_max_bandwidth
    high_usage_limited=false
    high_bandwidth_start_time=0
    bandwidth_drop_start_time=0
    log "6小时高带宽使用限制已结束,恢复带宽限制和计时器"
    send_feishu_notification "6小时高带宽使用限制已结束,带宽已恢复到 ${MAX_BANDWIDTH}Mbps。"
  fi

  # 检查爆发次数限制
  if [ "$bandwidth_usage" -ge "$BURST_THRESHOLD" ]; then
    # 记录爆发事件
    burst_events+=("$current_time")
    log "检测到爆发事件,带宽达到 ${BURST_THRESHOLD} Mbps"

    # 移除超过时间窗口的事件
    for i in "${!burst_events[@]}"; do
      if [ $(($current_time - ${burst_events[$i]})) -gt $BURST_TIME_WINDOW ]; then
        unset 'burst_events[i]'
      fi
    done

    # 限制带宽
    if [ "$bandwidth_limited" = false ]; then
      set_limited_bandwidth "$BURST_LIMIT_DURATION" "触发爆发次数限制"
    fi
  fi

  # 检查持续高带宽使用限制
  if [ "$bandwidth_usage" -ge "$BANDWIDTH_THRESHOLD" ]; then
    if [ "$high_bandwidth_start_time" -eq 0 ]; then
      high_bandwidth_start_time=$current_time
      log "带宽使用超过 ${BANDWIDTH_THRESHOLD} Mbps,开始计时"
    fi
    # 带宽使用高于阈值,重置带宽下降开始时间
    bandwidth_drop_start_time=0
  else
    if [ "$bandwidth_drop_start_time" -eq 0 ]; then
      bandwidth_drop_start_time=$current_time
      log "带宽使用低于 ${BANDWIDTH_THRESHOLD} Mbps,开始宽限期计时"
    else
      drop_elapsed_time=$((current_time - bandwidth_drop_start_time))
      if [ "$drop_elapsed_time" -ge "$BANDWIDTH_DROP_GRACE_PERIOD" ]; then
        if [ "$high_bandwidth_start_time" -ne 0 ]; then
          log "带宽使用低于阈值超过宽限期,重置高带宽计时器"
          high_bandwidth_start_time=0
          bandwidth_drop_start_time=0
        fi
      fi
    fi
  fi

  # 检查是否达到高带宽限制条件
  if [ "$high_bandwidth_start_time" -ne 0 ] && [ "$high_usage_limited" = false ]; then
    elapsed_time=$((current_time - high_bandwidth_start_time))
    if [ "$elapsed_time" -ge "$HIGH_USAGE_DURATION_LIMIT" ]; then
      set_limited_bandwidth "$HIGH_USAGE_LIMIT_DURATION" "触发6小时高带宽使用限制"
      high_usage_limited=true
      high_usage_limit_end_time=$(($current_time + $HIGH_USAGE_LIMIT_DURATION))
      log "带宽使用持续超过 ${BANDWIDTH_THRESHOLD} Mbps 达到 6 小时,已限制带宽 1 小时"
    fi
  fi

  # CPU 监控
  cpu_usage=$(monitor_cpu_usage)
  log "当前 CPU 使用率:${cpu_usage}%"

  if [ "$cpu_usage" -gt "$CPU_AVG_LIMIT" ]; then
    log "CPU 使用率超过 ${CPU_AVG_LIMIT}%,开始监控突发使用"
    cpu_burst_start=$(date +%s)
    while [ "$cpu_usage" -gt "$CPU_AVG_LIMIT" ]; do
      sleep "$MONITOR_INTERVAL"
      cpu_usage=$(monitor_cpu_usage)
      current_time=$(date +%s)
      burst_duration=$((current_time - cpu_burst_start))

      if [ "$burst_duration" -ge "$BURST_DURATION" ]; then
        log "CPU 使用率已超过 ${CPU_BURST_LIMIT}% 持续 ${BURST_DURATION} 秒,维持 CPU 限制"
        send_feishu_notification "CPU 使用率已超过 ${CPU_BURST_LIMIT}% 持续 ${BURST_DURATION} 秒,已维持 CPU 限制。"
        break
      fi
    done
  else
    remove_cpu_limit
  fi
done

脚本解析

  1. 加载配置文件和环境检查

    • 使用 source 加载配置文件中的参数。
    • 确保脚本以 root 用户运行,否则无法执行某些系统命令。
    • 检查必要的工具是否已安装,确保脚本运行所需的环境。
  2. 日志和通知功能

    • log 函数用于记录日志,同时将日志输出到屏幕和日志文件。
    • send_feishu_notification 函数用于通过飞书 Webhook 发送通知,便于及时获悉服务器状态。
  3. 带宽限制的初始化和管理

    • initialize_bandwidth_limit 函数使用 tc 命令设置带宽限制的初始状态。
    • set_limited_bandwidth 函数在需要时降低带宽限制,并记录限制的结束时间。
    • restore_max_bandwidth 函数在限制结束后,恢复到最大带宽。
  4. CPU 限制的初始化和管理

    • initialize_cpu_limit 函数使用 cgroups 创建一个 CPU 限制组,并设置 CPU 配额。
    • remove_cpu_limit 函数移除 CPU 限制,恢复正常状态。
  5. 资源监控函数

    • monitor_bandwidth_usage 函数监控指定网络接口的带宽使用情况。
    • monitor_cpu_usage 函数监控 CPU 的平均使用率。
  6. 清理函数

    • cleanup 函数在脚本退出时,清理设置的带宽和 CPU 限制,确保系统恢复正常。
  7. 主循环逻辑

    • 在无限循环中,不断监控带宽和 CPU 使用情况。
    • 根据定义的阈值和时间窗口,判断是否需要触发限制措施。
    • 在需要解除限制时,自动恢复带宽和 CPU 到正常状态。
    • 通过日志和飞书通知,实时反馈服务器资源使用和限制情况。

四、将脚本设置为系统服务

为了让脚本在后台持续运行并在系统启动时自动启动,我们需要将其设置为一个 Systemd 服务。

  1. 创建服务文件

    /etc/systemd/system/ 目录下创建 resource_monitor.service 文件:

    ♾️ ini 代码:
    [Unit]
    Description=Resource Monitor Service
    After=network.target
    
    [Service]
    Type=simple
    ExecStart=/usr/bin/bash /usr/local/bin/resource_monitor.sh
    Restart=always
    
    [Install]
    WantedBy=multi-user.target
  2. 重新加载 Systemd 配置并启动服务

    ♾️ bash 代码:
    sudo systemctl daemon-reload
    sudo systemctl enable resource_monitor.service
    sudo systemctl start resource_monitor.service
  3. 查看服务状态

    ♾️ bash 代码:
    sudo systemctl status resource_monitor.service

五、注意事项

  • 权限要求:脚本需要以 root 用户运行,因为涉及到系统级别的资源限制。
  • 工具依赖:确保系统已安装 tccgroup-toolssysstatcurl 等工具。
  • 飞书 Webhook:替换配置文件中的 FEISHU_WEBHOOK_URL 为实际的 Webhook 地址。
  • 日志查看:日志文件默认保存在 /var/log/resource_monitor.log,可根据需要修改路径。

六、结语

通过上述脚本,我们实现了对服务器带宽和 CPU 使用率的实时监控和限制。当资源使用超过设定的阈值时,脚本会自动采取限制措施,并通过飞书通知管理员。这个解决方案有助于保障服务器的稳定运行,防止资源滥用。

希望本文对您有所帮助,如果有任何问题或建议,欢迎交流。

现在已有 0 条评论,3 人点赞
酒笙
Author:酒笙
作者
针对绿云服务器带宽和CPU监控自动化: Bash脚本实现
当前文章累计共 12446 字,阅读大概需要 6 分钟。
shell脚本基础
2022年2月22日 · 2评论
python模块二
2022年2月22日 · 0评论
LobeChat服务端数据库版本部署指南
2024年9月10日 · 0评论
Comment:共0条
发表
搜 索 消 息 足 迹
你还不曾留言过..
你还不曾留下足迹..
博主 不再显示
博主