Memcached监控脚本控制台运行正常,crontab执行失败求助
问题描述
Memcached监控脚本以root身份在控制台运行正常,但通过crontab执行时失败,报错信息如下:
Traceback (most recent call last): File "<stdin>", line 6, in <module> ValueError: could not convert string to float: /root/bin/memcached_guard: line 33: [: ==: unary operator expected
该脚本用于检测Memcached的CPU使用率,超过阈值则重启服务,此前在另一服务器的crontab中运行正常。已尝试修改if语句的判断值为"1"、使用env命令运行脚本、对比两台服务器的cron环境(二者一致)、验证Python模块路径无问题,但均未解决。
脚本内容:
#!/bin/sh # Max usage for memcached in percents MEMCACHED_MAX_USAGE=70.0 # Where to send e-mail if there is a problem MONITORING_EMAIL="xyz@xyz.com" CURRENT_USAGE=$(top -bn 1 | grep -w memcached | awk '{print $9}') #echo 'Currently using' $CURRENT_USAGE # BASH does not support floating point numbers, so use Python # Have to pass arguments as environment variables on same line so # they are executed in same context as Python script # Wrap into function for easier use function check_usage { MAX="$1" CUR="$2" python2 - <<END import os #import sys #print "MAX Usage is " + os.environ['MAX'] #print "CUR Usage is " + os.environ['CUR'] if float(os.environ['MAX']) < float(os.environ['CUR']): print 1 else: print 0 END } if [ $(check_usage $MEMCACHED_MAX_USAGE $CURRENT_USAGE) == 1 ] then echo "Memcached takes $CURRENT_USAGE% of CPU. Restarting" | mail -s "memcached problem detected" $MONITORING_EMAIL /sbin/service memcached restart fi
故障原因
- CURRENT_USAGE为空值:cron环境中
top命令的输出格式可能与交互式终端不同,或者memcached进程短暂未被top捕获,导致grep -w memcached无匹配结果,最终CURRENT_USAGE为空字符串。 - bash条件判断语法错误:当
check_usage函数因CURRENT_USAGE为空触发Python错误后,函数返回空值,此时if [ == 1 ]会触发语法错误——因为条件左侧无有效值,bash将==识别为一元操作符,不符合语法规则。
解决办法
方案1:给CURRENT_USAGE设置默认值,避免空值
修改获取CURRENT_USAGE的代码,为空时默认赋值0:
CURRENT_USAGE=$(top -bn 1 | grep -w memcached | awk '{print $9}') # 为空时默认设为0 CURRENT_USAGE=${CURRENT_USAGE:-0}
方案2:替换top为更可靠的pidstat命令(推荐)
top的输出列在不同环境可能有差异,改用pidstat获取CPU使用率更稳定:
# 先获取memcached的PID,再用pidstat获取CPU使用率 MEM_PID=$(pidof memcached) if [ -n "$MEM_PID" ]; then # 采样1次,间隔1秒,取最后一行的CPU使用率 CURRENT_USAGE=$(pidstat -p $MEM_PID 1 1 | tail -1 | awk '{print $8}') else CURRENT_USAGE=0 fi
方案3:修复bash的if判断语法,添加引号防止空值
修改if语句,给命令替换的结果加引号,避免空值导致语法错误:
if [ "$(check_usage $MEMCACHED_MAX_USAGE $CURRENT_USAGE)" == "1" ] then echo "Memcached takes $CURRENT_USAGE% of CPU. Restarting" | mail -s "memcached problem detected" $MONITORING_EMAIL /sbin/service memcached restart fi
方案4:在Python脚本中处理空值情况
修改check_usage函数里的Python代码,主动处理CUR为空的场景:
import os max_usage = float(os.environ['MAX']) # 为空时默认设为0.0 cur_usage = float(os.environ['CUR'].strip()) if os.environ['CUR'].strip() else 0.0 if max_usage < cur_usage: print(1) else: print(0)
验证方法
- 手动模拟CURRENT_USAGE为空的情况,执行脚本测试是否还报错:
CURRENT_USAGE='' ./memcached_guard
- 将脚本加入crontab后,查看cron日志(通常在
/var/log/cron或/var/log/syslog)确认执行情况。
内容的提问来源于stack exchange,提问作者Rudolf
相关产品推荐
相关产品推荐

