一日双检:用脚本与监控实现服务器每日两轮巡检

发布时间:2026/9/1 13:59:18
一日双检:用脚本与监控实现服务器每日两轮巡检 一日双检在运维语境下并不神秘它指的是每天固定两个时间点对服务器、应用、数据和安全项做两轮完整检查。很多团队把这四个字当成口号真正实行时却常常变成“定时跑两个脚本”。脚本跑完没人看告警发出来没人处理检查点一两个月不更新这样的双检没有意义。下面从检查点设计开始逐步讲到脚本实现、定时调度、监控告警、异常排查和生产落地清单适合运维工程师、后端开发以及刚接手服务稳定性的SRE同学。1. 一日双检怎么理解和普通巡检的差别在哪1.1 一日双检的基本含义一日双检是每天两次固定的巡检动作一次安排在业务高峰前一次安排在关键任务结束时。上午那轮主要确认系统是否以健康状态进入业务时段夜间那轮主要确认当天运行结果是否被完整保存、任务队列是否清空、有没有需要次日处理的遗留问题。它解决的是“系统看起来没问题但没人真正检查过”的盲区。有些团队会把“检查”和“监控”混在一起这需要分开看。监控负责持续采集指标做异常阈值触发一日双检则强调在一个明确的时间点由固定的检查清单、固定的执行脚本、固定的负责人主动确认一批关键项。监控是“被动等待异常”双检是“主动寻找异常”。1.2 双检和“定期巡检”的差别定期巡检可能每周一次或每月一次重点放在容量预测、配置审计和长周期变化上一日双检则更贴近当天运行状态频率更高检查项更短。两者可以共存但定位不同。下面的表格适合用来给团队成员对齐概念。维度一日双检每周/每月巡检监控告警频率每天两次固定时间每周或每月7x24小时持续目的确认当天业务运行状态发现周期性问题、容量趋势实时发现异常指标结果形式检查报告、失败项巡检报告、改进项告警事件执行人值班或运维人员运维或架构负责人系统自动执行关注点CPU、磁盘、进程、端口、任务、日志配置漂移、补丁、容量、备份指标越线、错误率、延迟从这张表可以看出一日双检并不替代另外两种机制它负责的是“今天有没有出事”和“现在能不能正常开展业务”。1.3 什么系统适合用一日双检一日双检最适合两类场景。一是核心在线系统比如网关、支付、订单、数据库重要到不能等到用户投诉后再处理。二是批处理型系统比如每日报表、离线数据同步、消息对账这类任务的运行结果往往在固定时间才能确认最合适在任务结束后的时间点做一次检查。如果系统本身非常轻量、没有独立部署价值或者监控覆盖已经足够完整也可以适当简化双检项不用为了“每天两次”而硬造两个检查点。这里可以遵循一个原则检查项必须和当天业务结果强相关否则双检容易变成形式打卡。1.4 一日双检必须避开的误区第一个误区是“把双检当成跑两个脚本”。脚本执行完不等于检查完成结果需要有人看、有异常要有后续动作。第二个误区是“检查点永远不变”。业务迭代后端口会变、目录会变、依赖进程会变检查点必须跟着变。第三个误区是“用双检替代业务监控”。一日双检只能覆盖部分高频和关键点真正的延迟和错误率必须由监控体系完成。第四个误区是“只记录不反馈”。检查日志写了一大堆却没有汇总失败项没有负责人那检查本身就没有闭环。理解了这层含义再进入设计环节会更清楚为什么要按“早检、晚检、结果存储、告警联动”的思路来搭建。2. 双检方案的整体设计和检查点选择2.1 早检和晚检如何划分职责早检建议安排在上午业务进入高峰之前比如八点到九点之间。早检的重点是确认“经过夜间变化后系统处于正常状态”。夜间可能发生批处理任务、备份任务、数据库维护窗口、证书轮换等操作早检要把这些变化的残留影响找出来。晚检建议安排在当天业务基本结束或关键任务完成后比如二十点到二十二点之间。晚检的重点是确认“今天的任务是否全部完成数据是否落库队列是否清空”。晚检的结果会直接决定明天早上的启动条件。可以把早检理解成开机自检晚检理解成关机前检查。2.2 检查点分类基础设施、应用、数据、安全检查点不宜拍脑袋随手加建议按四个维度分类。基础设施类包括磁盘使用率、内存水位、CPU负载、系统时间同步、swap占用。这些指标最容易获取也最能反映主机层面是否已经出现问题。应用类包括进程是否存活、端口是否监听、关键接口是否可以访问、日志中最近一小时内是否有严重错误。业务和应用是双检的重点不能只停留在“服务器活着”这一层。数据类包括定时任务是否成功、数据库备份文件是否生成、消息队列积压量是否在预期范围、关键表是否有新增数据。对于数据类检查项阈值往往和业务量有关不能用固定值一杆子打死。安全类包括证书剩余有效期、账号锁定时长、异常的sudo日志、防火墙规则是否被意外改动。安全类检查项不需要每天全部执行但双检时至少要覆盖证书和登录异常两个基础项否则证书到期这类问题很容易在业务高峰突然爆发。2.3 双检结果怎么存储文件、数据库、监控平台结果存储方式决定后续查询和告警的便利程度。最简单的是落盘成文本日志适合单机或少量服务器。稍微规范一点可以把结果写入SQLite或MySQL便于按时间查询和汇总。再进一步是写入监控平台比如Prometheus指标或Elasticsearch日志这样可以和告警联动。存储方式优点缺点适合场景文本日志实现简单定位快查询不便难聚合单机、学习环境SQLite/MySQL可查询、可统计需要建表和维护中小规模集群Prometheus指标和告警联动自然不适合存详细日志已部署监控的环境Elasticsearch查询灵活支持全文成本较高日志平台成熟的环境2.4 双检的检查频率和预期输出一日双检里“一日”和“双”是固定参数但具体时间可以按业务错峰。如果业务有两个高峰可以调整为上午十点和下午四点。频率可以改但不要频繁改动否则团队成员会失去节奏。预期输出应该包含检查时间、检查阶段、每一项的结果、失败总数以及失败项明细。这样无论是人工查看还是后续自动化处理都能快速判断当天是否健康。输出结果建议同时具备“人类可读的摘要”和“机器可读的指标”后面接入监控时会更方便。3. 用脚本把一日双检落地到服务器3.1 检查脚本的结构脚本设计的核心是可重复、可定位、不阻塞。可重复意味着脚本不依赖上一次运行状态可定位意味着每次运行都会生成带时间戳的结果文件不阻塞意味着单次检查不能因为某个命令等待过久导致整个调度卡住。推荐的结构是把每个检查项封装成独立函数。一个函数只做一件事返回0表示成功返回非0表示失败。脚本最后累加失败数量并写入汇总文件。3.2 编写一个最小可运行的巡检脚本下面这个脚本只做四个检查根分区磁盘使用率、nginx进程是否存活、3306端口是否监听、总失败数是否异常。它用于说明思路实际项目需要结合自己的服务名、端口和阈值调整。#!/usr/bin/env bash # daily_double_check.sh CHECK_TIME$(date %Y-%m-%d %H:%M:%S) CHECK_STAGE${1:-morning} LOG_DIR/var/log/double_check RESULT_FILE${LOG_DIR}/${CHECK_STAGE}_$(date %Y%m%d_%H%M%S).log mkdir -p $LOG_DIR fail_count0 check_disk() { local usage usage$(df / | awk NR2 {print $5} | tr -d %) if [ $usage -gt 85 ]; then echo [FAIL] root disk usage ${usage}% exceeds 85% return 1 fi echo [OK] root disk usage ${usage}% } check_process() { local name$1 if pgrep -f $name /dev/null 21; then echo [OK] process ${name} is running else echo [FAIL] process ${name} is not running return 1 fi } check_port() { local port$1 if ss -lnt | grep -q :$port ; then echo [OK] port ${port} is listening else echo [FAIL] port ${port} is not listening return 1 fi } { echo check_time${CHECK_TIME} echo check_stage${CHECK_STAGE} check_disk || fail_count$((fail_count 1)) check_process nginx || fail_count$((fail_count 1)) check_port 3306 || fail_count$((fail_count 1)) echo total_fail${fail_count} } $RESULT_FILE echo double_check_failed${fail_count} exit $fail_count脚本运行后会在 /var/log/double_check 目录下生成一个带阶段和时间戳的日志文件。执行exit $fail_count的目的是把失败数量暴露给调度系统如果cron启用MAILTO失败时管理员能收到邮件。3.3 用cron安排一日双检把脚本放到 /usr/local/bin 或者 /opt/scripts 后先手动运行一次确认没有问题再配置cron。30 8 * * * /usr/local/bin/daily_double_check.sh morning 30 20 * * * /usr/local/bin/daily_double_check.sh evening这里安排在上午八点半和晚上八点半执行。cron的执行结果会通过本机邮件发送到MAILTO配置的地址但生产环境建议关闭系统邮件改成脚本主动上报比如把失败记录写入监控指标或消息队列。3.4 双检结果落盘和日志轮转日志文件会越来越多需要配置logrotate避免磁盘被检查日志占满。下面是一份最小配置。/var/log/double_check/*.log { daily rotate 14 compress missingok notifempty copytruncate }copytruncate的作用是在复制和清空文件时不中断正在写入的句柄。对于低频写入的巡检日志这个配置足够。日志保留14天基本可以覆盖一次周报和月度问题回溯。4. 接入监控平台让双检结果不再靠登录服务器查看4.1 双检和监控平台的关系脚本落地后每天会在服务器上生成两轮检查结果。但只存在本机日志里意味着每次查看都要登录服务器异常无法主动触达。生产环境需要把双检结果接入监控平台常见的做法是通过node_exporter的textfile collector把脚本生成的结果暴露成Prometheus指标。4.2 通过文本暴露指标给Prometheus抓取在脚本末尾追加一段指标写入逻辑。假设node_exporter的采集目录是 /var/lib/node_exporter/textfile_collector那么可以用如下方式写入指标。METRIC_DIR/var/lib/node_exporter/textfile_collector mkdir -p $METRIC_DIR cat ${METRIC_DIR}/double_check.prom EOF # HELP double_check_failed 当日双检失败标记大于0表示失败 # TYPE double_check_failed gauge double_check_failed{stage${CHECK_STAGE}, host$(hostname)} ${fail_count} EOF这里的指标名是 double_check_failed取值为失败数量。写入完成后node_exporter会自动读取该目录下的 .prom 文件Prometheus就能在下一个采集周期中看到这个指标。4.3 配置告警规则Prometheus侧配置一条告警规则当双检指标大于0时触发告警。groups: - name: double_check_alerts rules: - alert: DoubleCheckFailed expr: double_check_failed 0 for: 5m labels: severity: warning annotations: summary: 双检失败 {{ $labels.host }} {{ $labels.stage }} description: {{ $labels.stage }}阶段双检失败失败数为 {{ $labels.instance }}for: 5m的作用是防止因为指标文件写入时的瞬时抖动导致告警误发。告警持续时间超过5分钟才触发能过滤掉大部分短暂的采样异常。4.4 告警通知分级告警发出后需要通知到对应负责人。建议按严重程度分级普通失败发到值班群或邮件影响业务的关键失败直接电话或短信通知。分级可以在告警路由里实现。下面的表格可以用来和通知平台对齐。等级条件通知方式响应时限P0关键服务不可用、数据写入失败电话短信15分钟P1磁盘超阈值、进程不存在邮件IM30分钟P2证书临期、日志异常增多IM、群通知当天5. 运行验证和常见问题排查5.1 先验证脚本本身配置双检的第一件事不是直接上cron而是手动运行脚本。执行bash /usr/local/bin/daily_double_check.sh morning然后检查返回码echo $?再打开日志文件确认每一行都符合预期。如果脚本返回非0先根据日志修复不要急着调度。5.2 如何确认cron任务真的执行cron没有执行是双检落地初期最高频的问题。排查顺序是先查看/var/log/cron或执行journalctl -u crond确认任务是否被调度再检查脚本权限和shebangcron环境不加载用户profile脚本内部要使用绝对路径或显式定义PATH然后检查MAILTO是否配置否则cron的执行输出会丢失。下面是一段通过日志确认cron执行的命令。grep daily_double_check /var/log/cron journalctl -u crond --since today | grep daily_double_check5.3 常见坑1误报率太高导致告警被忽略现象双检脚本每天都报告失败但人工检查后发现只是阈值设置过紧或者检查项本身不适合当前业务。比如晚间的消息队列积压量总是超过固定阈值但业务周期决定它就是要到深夜才能消费完。解决方式不是直接删检查项而是把固定阈值改成基于历史分位数的动态阈值或者把告警判断从“单次失败”改成“连续三次失败”。宁可让告警晚一点触发也不要让告警失去可信度。5.4 常见坑2双检脚本阻塞现象cron任务启动后一直没有结束下一次执行又被卡住系统负载持续升高。原因往往是脚本内部执行了长时间扫描命令比如对整个日志目录执行大范围grep或者等待某个远程接口响应。解决方式是在外部使用timeout包裹脚本例如30 8 * * * /usr/bin/timeout 60 /usr/local/bin/daily_double_check.sh morning同时脚本内部对每个远程检查项使用curl的--connect-timeout和--max-time避免网络异常拖住整个检查流程。5.5 常见坑3检查点过期和版本漂移现象某次服务升级后3306端口改到了3307nginx进程改成了容器方式运行但双检脚本还在检查旧进程和旧端口。结果每天都报告失败管理员逐渐麻木最终真正出问题时反而没有人在意告警。解决方式是在每次发布流程中加入“检查专属任务”发布单里要求同步更新双检清单。双检清单本身建议纳入版本管理和代码一起评审、一起变更。5.6 双检异常的整体排查链路当收到一条双检失败告警时按下面这个顺序排查。确认当前时间是哪个阶段早检还是晚检检查项是否和当前时间段强相关。查看对应时间点的巡检日志定位是哪个检查项返回失败。如果是磁盘、内存、进程等基础项先登录服务器确认实际状态。如果是应用接口或数据任务失败查看应用日志和调度平台日志。修复后重新运行一次脚本确认返回码为0并观察Prometheus指标是否恢复为0。在当日双检结果里补充备注说明原因和处理动作避免下次复盘时无从查起。6. 从开发到生产的落地建议6.1 开发、测试、生产环境的双检差异不要把生产环境的双检脚本原样复制到开发环境。开发环境的核心目的是快速验证功能不需要每天盯磁盘和证书测试环境的双检则要服务于发布验证检查项应该围绕新版本涉及的服务、依赖和回滚条件展开。生产环境的双检最严格需要同时覆盖基础设施、应用、数据和安全。环境检查频率检查重点失败处理开发按需服务是否可启动、端口是否占用开发自行解决测试每次发布前后新功能相关服务、依赖、数据迁移阻断发布生产每日两次系统健康、任务结果、证书、备份告警升级6.2 可复用的一日双检检查清单下面是落地一日双检时可以直接对照的检查清单。[ ] 是否定义了明确的早检和晚检时间并公布给值班团队[ ] 是否按基础设施、应用、数据、安全四个维度设计了检查点[ ] 每个检查点是否有明确阈值和判断规则阈值是否经过实际运行确认[ ] 双检脚本是否可重复运行是否生成带时间戳的结果文件[ ] 是否配置了cron任务并通过日志确认至少连续执行三次[ ] 是否把结果暴露到Prometheus或其他监控平台[ ] 是否配置告警规则并且告警可以触达到值班人[ ] 是否配置了日志轮转避免检查日志占满磁盘[ ] 是否在发布流程中加入了双检清单更新步骤[ ] 是否规定失败后的响应时限和处理流程6.3 后续扩展方向如果团队已经稳定运行一日双检可以考虑三个扩展方向。一是把脚本检查项抽象成配置文件让不同业务线只维护自己的检查点列表而不是复制脚本。二是把双检结果写入任务管理平台自动创建待办项完成从检查到处理的全链路闭环。三是接入更多的自动化探测能力例如基于真实流量构造一次低风险请求验证关键接口的返回码和延迟让双检从“检查进程是否在”上升到“检查业务是否真能走通”。一日双检本身是一件很朴素的事难的是坚持和闭环。脚本可以被替换检查点可以调整但“每天固定两次主动确认系统状态、对异常有明确处理路径”这一原则对大多数核心系统来说依然是性价比很高的稳定性手段。下一步可以把自己团队最常出问题的三个检查项放进去先跑两周再根据结果调整阈值和频率会比一开始追求大而全更有效。