半夜三点,物业老王盯着监控大屏,发现第三号机位的画面突然变成了一片惨白。不是黑屏,也不是花屏,就是那种死气沉沉、透着蓝光的白。他赶紧抓起电话叫运维,可值班人员都睡熟了,醒来再远程操作,黄花菜都凉了。第二天清晨,业主群里炸开了锅,说家里车位被刮了却没录像,投诉电话差点把前台打爆。
这种事儿,在监控行业里太常见了。我们总以为设备买回来就能一劳永逸,但实际上,网络录像机(NVR)或硬盘录像机长时间运行后,内存泄漏、进程僵死、硬盘缓存堆积,都会导致“白屏”、“卡死”或者录像丢失。如果完全依赖人工巡检,不仅成本高昂,还 inevitably 会出现监管盲区。
今天,咱们不整那些虚头巴脑的理论,就直接聊聊怎么利用Linux系统下的“定时任务”机制,给录像机请一个24小时在线的“隐形保安”。我会结合三个真实的典型场景,手把手教你怎么配置、怎么避开业务高峰、怎么确保数据不丢。这不仅仅是配置脚本,更是一套让监控系统长治久安的策略。
场景一:内存泄漏导致的进程僵死——最朴素的“心跳检测”
先说说第一种情况,这也是最常见的一种。很多老旧或者低端品牌的NVR,跑久了之后,负责视频解码或者网络服务的进程会慢慢占用越来越多的内存,直到系统内存耗尽,图形界面卡死,最终呈现给用户的就是“白屏”。这时候,录像服务可能还在后台微弱地转着,但已经无法存储新的画面了,或者存储速度极慢导致丢帧。
对付这种情况,我们不能指望它自己恢复,最稳妥的办法就是定期重启核心服务,或者在发现异常时强制重启。但注意,千万别随便写个“每5分钟重启一次”的脚本,那会让硬盘疯狂读写,加速老化,而且如果重启失败,可能导致整个系统瘫痪。
我们需要做的,是一个智能的“心跳检测”机制。
假设你的NVR运行的是嵌入式Linux系统(大部分网络录像机都是),你可以登录进去,创建一个简单的监控脚本。这个脚本的逻辑是:检查某个关键进程(比如nsd、recording或者nginx,具体看你设备的进程名)是否存活。如果不存活,或者CPU/内存占用超过阈值,就记录日志并尝试重启服务。
下面这段代码展示了一个基本的监控脚本逻辑,你可以把它保存为/usr/local/bin/monitor_rec.sh:
#!/bin/bash
# 监控录像进程健康状态的脚本
# 日志文件路径
LOG_FILE="/var/log/rec_monitor.log"
# 需要监控的关键进程名(请根据实际设备修改,例如nsd, vlc, gdm等)
PROCESS_NAME="nsd"
# 重启命令
RESTART_CMD="systemctl restart nsd"
# 获取当前时间
TIME=$(date '+%Y-%m-%d %H:%M:%S')
# 检查进程是否存在
if pgrep -x "$PROCESS_NAME" > /dev/null; then
echo "[$TIME] $PROCESS_NAME 运行正常,PID: $(pgrep -x $PROCESS_NAME)" >> $LOG_FILE
else
echo "[$TIME] 警告:$PROCESS_NAME 进程未找到,尝试重启..." >> $LOG_FILE
# 执行重启
eval $RESTART_CMD
if [ $? -eq 0 ]; then
echo "[$TIME] $PROCESS_NAME 重启成功" >> $LOG_FILE
else
echo "[$TIME] 错误:$PROCESS_NAME 重启失败,请人工介入!" >> $LOG_FILE
fi
fi
写好了脚本,别忘了给权限:chmod +x /usr/local/bin/monitor_rec.sh。
接下来,就要用到我们的主角——crontab(定时任务)。我们要让系统每隔5分钟执行一次这个检查。打开终端,输入crontab -e,添加以下行:
*/5 * * * * /usr/local/bin/monitor_rec.sh
这个配置的意思是,每5分钟执行一次。看起来很简单对吧?但这里有个坑。很多运维新手会忽略“重启后的冷却期”。如果进程刚启动就崩了,crontab会无限循环地重启,把日志写爆,甚至拖垮系统。所以,更高级的做法是在脚本里加一个冷却机制,或者只在日志里报警,而不是直接重启。
不过,对于大多数稳定的商业NVR,如果它真的崩了,重启通常是唯一办法。关键是,我们要把重启的时间控制在“业务低峰期”。
场景二:硬盘维护与碎片整理——如何在凌晨2点优雅地“大扫除”
除了进程僵死,硬盘问题也是导致白屏和录像丢失的元凶。机械硬盘长时间读写,会产生碎片,更重要的是,文件系统本身可能需要修复。如果你在某天下午业务高峰期去手动执行fsck(文件系统检查)或者重启NVR做硬盘清理,那简直就是灾难。此时,几十个摄像头都在高速写入数据,一旦磁盘被锁定,所有录像都会中断,甚至损坏数据。
所以,我们需要一个“温柔”的维护策略。假设你的NVR支持远程管理,并且你希望每天凌晨2点到3点之间进行一些轻量级的维护,比如清理临时文件、重启录像服务以释放内存,甚至重启整个设备(如果设备支持平滑重启)。
首先,我们要确定维护的时间窗口。凌晨2点到4点通常是夜深人静、访问量少的时候。我们可以设置一个定时任务,在这个时间段内执行维护脚本。
但这里有个关键问题:如何避免在重启过程中丢失正在写入的数据?
大多数现代NVR在重启前会先停止录像写入,刷新缓冲区,然后关机或重启。但为了保险起见,我们应该在脚本中加入“等待写入完成”的逻辑,或者简单地,先发送停止录像指令,等待几秒钟,再执行重启。
下面这个脚本演示了如何安全地执行一次“维护性重启”:
#!/bin/bash
# 安全维护脚本 - 仅在指定时间段执行
# 日志文件
LOG_FILE="/var/log/maintenance.log"
# 当前小时
HOUR=$(date +%H)
# 只允许在凌晨2点到4点之间执行
if [ "$HOUR" -ge 2 ] && [ "$HOUR" -lt 4 ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 开始执行维护任务..." >> $LOG_FILE
# 1. 停止录像服务(防止写入中断导致数据损坏)
echo "停止录像服务..." >> $LOG_FILE
systemctl stop recording
# 2. 等待几秒钟,确保缓冲区刷新
sleep 10
# 3. 清理临时文件和日志(节省空间)
find /tmp -type f -mtime +7 -delete 2>/dev/null
find /var/log -name "*.log.gz" -mtime +30 -delete 2>/dev/null
# 4. 重启录像服务
echo "重启录像服务..." >> $LOG_FILE
systemctl start recording
# 5. 检查服务状态
if systemctl is-active --quiet recording; then
echo "维护完成,服务运行正常。" >> $LOG_FILE
else
echo "警告:服务重启后状态异常!" >> $LOG_FILE
fi
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 当前时间不在维护窗口,跳过执行。" >> $LOG_FILE
fi
然后,我们将这个脚本设置为每天凌晨2:30执行:
30 2 * * * /usr/local/bin/safe_maintenance.sh
这样做的好处是,即使脚本因为某种原因卡住,它也只会发生在凌晨3点之前,不会影响到白天繁忙的业务时段。而且,通过先停止录像再重启,我们最大限度地减少了数据损坏的风险。
场景三:网络波动导致的NTP同步失败——用定时任务“校准时间”
第三个场景,听起来有点冷门,但后果很严重。很多监控录像机依赖网络时间协议(NTP)来同步时间。如果网络不稳定,或者NTP服务器不可达,录像机的时间就会漂移。时间不对,不仅导致录像回放时时间戳错乱,无法作为法律证据,更严重的是,多个摄像头之间的时间不同步,会让事故还原变得极其困难。
有些设备在时间偏差过大时,会直接拒绝写入新的录像文件,或者导致文件系统错误,进而引发白屏或崩溃。
我们可以利用定时任务,定期强制同步时间,并确保同步成功后再恢复录像。
下面是一个专门用于时间同步维护的脚本:
#!/bin/bash
# 时间同步维护脚本
LOG_FILE="/var/log/time_sync.log"
MAX_DRIFT=300 # 允许的最大时间偏差(秒),超过则强制同步
# 检查当前时间偏差(假设系统时钟有drift文件)
DRIFT=$(cat /var/lib/systemd/clock/last-drift 2>/dev/null || echo "0")
if [ "$DRIFT" -gt "$MAX_DRIFT" ] || [ -z "$DRIFT" ]; then
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 时间偏差较大,执行强制同步..." >> $LOG_FILE
# 停止录像,避免时间跳跃导致的数据混乱
systemctl stop recording
# 执行NTP同步
/usr/sbin/ntpd -qg
# 重新启动录像
systemctl start recording
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 时间同步完成。" >> $LOG_FILE
else
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 时间偏差正常,无需同步。" >> $LOG_FILE
fi
这个脚本设置了一个阈值,只有当时间偏差超过5分钟(300秒)时,才会触发强制同步。平时,它只是默默记录状态。我们将其设置为每6小时执行一次:
0 */6 * * * /usr/local/bin/time_sync_maintenance.sh
这样,即使网络偶尔波动,系统也能在偏差累积到危险程度之前进行修正,而不会干扰正常的录像工作。
进阶:如何确保定时任务本身不“罢工”
说了这么多,你可能会问:如果crontab本身挂了,或者脚本执行失败了怎么办?
这就涉及到一个“元监控”的问题。我们需要一个更高层级的监控,来确保我们的自动维护系统本身是健康的。
一个简单而有效的方法是,创建一个“心跳文件”。让主监控脚本每隔几分钟更新一次这个文件的时间戳。然后,再设置另一个独立的、极简的crontab任务,检查这个心跳文件。如果心跳文件超过一定时间(比如10分钟)没有更新,就判定主监控系统失效,并通过邮件或短信告警。
例如,在monitor_rec.sh的末尾,添加一行:
touch /var/run/rec_heartbeat
然后,在crontab中添加一个独立的检查任务:
*/10 * * * * [ -f /var/run/rec_heartbeat ] && find /var/run/rec_heartbeat -mmin +10 -delete && echo "告警:心跳丢失,监控系统可能异常!" | mail -s "NVR监控告警" admin@example.com
这段代码的意思是,每10分钟检查一次。如果心跳文件存在,但最近10分钟内没有被修改过(-mmin +10),就删除它(避免误判),并发送告警邮件。
总结一下
你看,解决监控半夜白屏和系统维护的问题,并不一定要靠24小时盯着屏幕。通过精心设计的crontab定时任务,我们可以实现:
- 自动健康检查:定期监控关键进程,发现异常自动重启。
- 安全维护窗口:在业务低峰期执行硬盘清理、服务重启等操作,避免影响正常录像。
- 时间同步保障:定期校准系统时间,防止因时间漂移导致的数据问题。
- 监控自身的监控:确保自动化系统本身可靠运行。
这些脚本看起来简单,但它们背后蕴含的是一个成熟的运维思维:将人为的、随机的、容易出错的巡检工作,转化为标准化的、自动化的、可追溯的程序执行。
当然,每个NVR品牌的系统架构可能略有不同,具体的进程名、服务名和命令可能需要你根据实际情况调整。但核心的逻辑是一样的:利用定时任务,在合适的时间,做合适的事,并且确保整个过程可控、可观测。
下次再遇到半夜白屏的警报,你或许可以淡定地看一眼服务器,心想:“别慌,我的隐形保安已经去处理了。”
