shell脚本中系统健康评分需采用非线性、条件加权的联合逻辑:以swap使用率动态调节i/o延迟权重,设置15%触发阈值进入敏感模式,并引入归一化乘积的协同恶化惩罚项,全程用整数运算保障兼容性。

在 Shell 脚本中对系统健康打分时,不能简单把 swap 使用率和 I/O 延迟各自独立评分再求平均——它们存在隐含的因果与放大关系:swap 使用率高往往意味着内存压力大,触发频繁 page-in/page-out,进而拉高 I/O 延迟;而 I/O 延迟本身又会拖慢 swap 操作,形成负向循环。因此需设计**非线性、条件加权的联合评分逻辑**,而非线性叠加。
用 swap 使用率作为 I/O 延迟权重的调节因子
核心思路是:I/O 延迟的“危害程度”取决于它是否发生在 swap 高负载背景下。当 swap 使用率为 0% 时,I/O 延迟即使略高(如 avgqu-sz > 2),实际影响也有限;但若 swap 已用 80%,同样的延迟可能预示 imminent OOM 或进程卡死。
- 先采集基础指标:
swap_used_pct = $(free | awk '/Swap:/ {printf "%.0f", $3*100/$2}')
io_delay_ms = $(iostat -x 1 1 | awk '/vda|sda/ {if($10>0) print $10}' | head -n1 | awk '{printf "%.1f"}' 2>/dev/null || echo "0.5") - 定义基础分(满分 10 分):
swap_score = max(0, 10 - swap_used_pct / 10) # 0%→10分,100%→0分
io_score = max(0, 10 - io_delay_ms * 1.5) # 0ms→10分,6.7ms→0分 - 引入耦合权重:
weight_factor = 1 + (swap_used_pct / 100) * 0.8 # swap 0%→权重 1.0,100%→权重 1.8
final_io_score = io_score / weight_factor
设置 swap 触发阈值,激活 I/O 敏感模式
当 swap 使用率低于某个临界点(如 15%),I/O 延迟可视为常规磁盘负载,按基础公式评分;一旦超过该阈值,说明内存已实质性透支,此时应大幅降低 I/O 容忍度,并让 swap 分数“拖累”整体健康分。
- 设定阈值:swap_critical=15
- 动态调整逻辑:
if [ $swap_used_pct -gt $swap_critical ]; then
# 进入敏感模式:I/O 延迟每增加 0.5ms 扣 1.2 分(原为 0.75 分)
io_penalty=$(echo "$io_delay_ms * 2.4" | bc -l | xargs printf "%.0f")
io_score=$((10 - io_penalty > 0 ? 10 - io_penalty : 0))
# 同时对 swap 分施加二次衰减:
swap_score=$((swap_score * 85 / 100))
fi
用归一化乘积项体现协同恶化效应
swap 和 I/O 是“雪崩式”组合:单独一项异常尚可容忍,两者同时升高时风险呈指数级上升。可用归一化乘积构造惩罚项:
- 将两项原始得分映射到 [0,1] 区间:
norm_swap = $swap_used_pct / 100.0 # 越高越差
norm_io = $io_delay_ms / 20.0 # 设定 I/O 恶化上限为 20ms - 计算协同恶化系数:
synergy_penalty = $(echo "$norm_swap * $norm_io * 100" | bc -l | xargs printf "%.0f")
# 例如:swap 60% + io 10ms → 0.6 × 0.5 × 100 = 30 分惩罚(从总分中扣除) - 最终健康分 = max(0, 100 - swap_penalty - io_penalty - synergy_penalty)
避免浮点陷阱,用整数运算保障 Shell 兼容性
多数嵌入式或旧版系统 shell 不支持浮点,所有计算应转为整数缩放(如 ×100)后处理:
- swap_used_pct_int=$((swap_used_pct * 100))
io_delay_us_int=$(( $(echo "$io_delay_ms * 1000" | bc -l | xargs printf "%.0f") )) - 用 awk 替代纯 bash 浮点:
score=$(awk -v s=$swap_used_pct -v i=$io_delay_ms 'BEGIN{print int(100 - s*0.8 - i*1.2 - (s/100)*(i/10)*30)}') - 始终做边界截断:
score=$((score 100 ? 100 : score))











