结论: 服务器日常维护做五件事——周期性巡检(日看健康、周做清理与补丁、月做容量与安全、季做演练与复盘)、变更管理(申请→评估→备份→窗口→执行→验证→回滚)、补丁管理、容量管理、备份验证与文档交接。核心不是"操作本身",而是把操作变成有周期、有标准、有记录的制度。
为什么维护必须制度化?
很多小团队的服务器维护是这样的:机器跑着就不管,等网站打不开了才去查;改配置直接在生产上 vim 一把梭,改完不记录也没备份;补丁想起来才打,打完发现服务起不来。这种"救火式运维"的代价是——故障发生在最不合适的时间、排查时找不到上次改了什么、恢复时才发现备份根本不可用。
服务器维护的本质,是用可控的、低成本的例行动作,去替换不可控的、高成本的突发故障。 一个成熟的维护体系应该做到:80% 的问题在巡检阶段被发现,15% 在演练中被暴露,只有 5% 真正走到用户面前。
本文不重复"巡检清单看哪些项"(那是快速清单篇的内容),而是讲维护动作怎么组织:多久做一次、谁来做、做到什么程度算合格、改错了怎么退回来、容量什么时候该扩、文档怎么留给下一个人。
一、日 / 周 / 月 / 季维护任务表
结论:把维护拆成四档周期,日档看健康、周档做清理与补丁、月档做容量与安全、季档做演练与复盘。 下表是完整任务表,含具体命令与判定标准。
| 周期 | 任务项 | 命令 / 操作 | 判定标准(合格线) | ||
|---|---|---|---|---|---|
| 每日 | 服务与端口存活 | systemctl is-active nginx mysql redis | 全部返回 active | ||
| 每日 | 资源水位 | df -h、free -h、uptime | 磁盘 < 85%,内存 < 90%,负载 < CPU 核数 | ||
| 每日 | 错误日志扫描 | journalctl -p err --since "24 hours ago" | 无新增 ERROR 或已知可忽略 | ||
| 每日 | 备份任务结果 | 查看备份日志 / ls -lh /backup | 昨日备份文件存在且大小合理 | ||
| 每日 | 证书有效期 | `echo \ | openssl s_client -connect domain:443 2>/dev/null \ | openssl x509 -noout -dates` | 剩余 > 30 天 |
| 每周 | 安全补丁评估与安装 | apt list --upgradable / dnf check-update | 高危 CVE 补丁在 7 天内完成 | ||
| 每周 | 日志轮转与清理 | logrotate -f /etc/logrotate.conf | /var/log 占用 < 5GB,无 30 天前日志 | ||
| 每周 | 备份恢复抽样验证 | 恢复 1 个库到临时实例并查询 | 能成功恢复且数据可查 | ||
| 每周 | 账号与密钥审计 | awk -F: '$3>=1000' /etc/passwd | 无未知账号、无离职人员账号 | ||
| 每月 | 容量趋势分析 | 统计磁盘/内存 30 天增长曲线 | 预估剩余天数 > 60 天 | ||
| 每月 | 安全基线复核 | lynis audit system 或手动检查 | 无高危项,SSH 禁用密码登录 | ||
| 每月 | 数据库慢查询与索引 | 分析 slow log,mysqldumpslow | 无 > 2s 的常态化慢查询 | ||
| 每月 | 灾备演练(小范围) | 单机恢复演练 / 主从切换演练 | RTO 达标,有演练记录 | ||
| 每月 | 密码与密钥轮换检查 | 检查密钥最后修改时间 | 关键密钥 90 天内已轮换 | ||
| 每季 | 固件与 BIOS 升级评估 | 查厂商公告,评估后安排窗口 | 无未处理的高危固件漏洞 | ||
| 每季 | 全量恢复演练 | 从备份完整重建一台机器 | 业务可完整拉起 | ||
| 每季 | 架构与容量复盘 | 对比季度增长与预算 | 有下季度扩容计划 | ||
| 每季 | 文档与 Runbook 更新 | 核对文档与实际配置 | 文档与实际一致,无过期内容 |
每日巡检:一条命令看完健康状态
结论:把每日巡检固化成一个脚本,30 秒内拿到结论,避免靠记忆逐条敲命令。
#!/usr/bin/env bash
# /opt/ops/daily-check.sh 每日巡检脚本,可配合 cron 每日 8:30 执行
set -euo pipefail
echo "===== 巡检时间: $(date '+%F %T') 主机: $(hostname) ====="
echo -e "\n[1] 关键服务状态"
for svc in nginx mysql redis sshd; do
state=$(systemctl is-active "$svc" 2>/dev/null || echo "missing")
printf " %-10s : %s\n" "$svc" "$state"
[ "$state" = "active" ] || echo " >>> 告警: $svc 状态异常"
done
echo -e "\n[2] 磁盘水位(警戒 85%)"
df -hP | awk 'NR>1 {
gsub("%","",$5);
flag = ($5+0 >= 85) ? " >>> 告警" : "";
printf " %-20s %s/%s 已用%s%%%s\n", $6, $3, $2, $5, flag
}'
echo -e "\n[3] 内存与负载"
free -h | awk 'NR==2{printf " 内存: 已用 %s / 共 %s\n", $3, $2}'
load=$(awk '{print $1}' /proc/loadavg); cores=$(nproc)
awk -v l="$load" -v c="$cores" 'BEGIN{printf " 负载: %s (CPU %d 核) %s\n", l, c, (l>c?">>> 告警":"正常")}'
echo -e "\n[4] 近 24 小时系统错误日志"
journalctl -p err --since "24 hours ago" --no-pager | tail -n 20 || true
echo -e "\n[5] 昨日备份文件"
find /backup -maxdepth 1 -type f -mtime -2 -printf " %p %s bytes %TY-%Tm-%Td %TH:%TM\n" | tail -n 5
echo -e "\n===== 巡检结束 ====="# 赋权并加入 crontab,每天 8:30 执行,结果落盘留存
sudo chmod +x /opt/ops/daily-check.sh
echo "30 8 * * * root /opt/ops/daily-check.sh >> /var/log/daily-check.log 2>&1" \
| sudo tee /etc/cron.d/daily-check每周维护:日志轮转与补丁
结论:日志必须用 logrotate 自动轮转压缩,不能靠人工删;补丁要分层处理——安全补丁尽快打,内核补丁先评估再打。
# /etc/logrotate.d/myapp —— 应用日志轮转配置
/var/log/myapp/*.log {
daily # 每天轮转
rotate 14 # 保留 14 份
compress # 压缩归档
delaycompress # 延后一天压缩,避免正在写入的文件被处理
missingok # 文件不存在不报错
notifempty # 空文件不轮转
create 0640 app app
sharedscripts
postrotate
# 通知应用重新打开日志文件( Nginx 用 USR1 信号)
[ -f /run/nginx.pid ] && kill -USR1 $(cat /run/nginx.pid)
endscript
}# 手动强制执行一轮,验证配置是否正确(-d 为调试模式,不实际执行)
sudo logrotate -d /etc/logrotate.d/myapp
sudo logrotate -f /etc/logrotate.d/myapp二、变更管理流程:七步闭环
结论:任何对生产环境的操作都必须走"申请 → 评估 → 备份 → 窗口 → 执行 → 验证 → 回滚"七步,缺任何一步都会埋雷。
- 申请:写清楚改什么、为什么改、影响范围(哪些服务、哪些用户)、预计时长。
- 评估:影响面分析(是否中断服务、是否涉及数据结构变化)、风险等级(低/中/高)、是否需要审批。
- 备份:变更前必须完成可回滚的备份——配置文件备份、数据库备份、云主机快照三选二。
- 窗口:选择业务低峰期(通常是凌晨 1:00~5:00 或业务量最低的时段),并提前公告。
- 执行:按预写的步骤逐步执行,禁止临场发挥。每一步执行完立即记录结果。
- 验证:功能验证(核心接口是否正常)+ 监控验证(错误率、延迟是否异常)+ 观察时长(至少 15 分钟)。
- 回滚:一旦验证不通过,立即执行回滚预案,而不是"再试试能不能修好"。
# 变更前的标准备份动作(示例:改 Nginx 配置前)
sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak.$(date +%Y%m%d%H%M)
sudo nginx -t # 校验语法
# 执行变更
sudo vim /etc/nginx/nginx.conf
sudo nginx -t && sudo nginx -s reload
# 验证:核心接口探活 + 错误码统计
curl -s -o /dev/null -w "HTTP %{http_code} 耗时 %{time_total}s\n" https://www.example.com/api/health
tail -n 200 /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn
# 回滚(验证失败时,一条命令退回去)
sudo cp /etc/nginx/nginx.conf.bak.202603181030 /etc/nginx/nginx.conf && sudo nginx -t && sudo nginx -s reload变更记录模板(建议放在内部 Wiki 或工单系统里):变更单号、申请人、执行人、变更内容、影响范围、风险等级、备份位置、回滚步骤、验证结果、实际耗时、结论。
三、补丁策略:什么补丁能立刻打,什么补丁要等等
结论:安全补丁(尤其是高危 CVE)7 天内打完;内核补丁必须先在与生产一致的测试环境验证再打;大版本升级永远不要在生产上直接做。
补丁分三档处理:
- 安全补丁(高危/严重 CVE):立即评估,7 天内完成。这类补丁通常改动小、向后兼容,风险低于被攻击的风险。
- 内核补丁与驱动更新:内核升级会影响网卡驱动、IO 调度、容器运行时兼容性。正确做法是——先在测试机验证(跑一轮业务压测)→ 安排窗口 → 逐台滚动更新 → 每台更新后观察 15 分钟 → 出问题立刻回滚到旧内核(GRUB 里保留旧内核启动项)。
- 大版本升级(如 MySQL 5.7 → 8.0、Ubuntu 20.04 → 24.04):禁止原地升级。正确做法是新建一套环境、做数据迁移、灰度切流、观察 24 小时后再下线旧环境。
# Ubuntu / Debian:只安装安全更新,避免顺带升级大版本
sudo apt update
sudo apt list --upgradable
sudo unattended-upgrade --dry-run -v # 先看会自动装什么
sudo apt install -y --only-upgrade $(apt list --upgradable 2>/dev/null | grep -i security | cut -d/ -f1)
# Rocky Linux / AlmaLinux:查看是否有涉及内核的更新,内核更新单独处理
sudo dnf check-update
sudo dnf update --security -y # 仅安全更新
sudo dnf update -y kernel && sudo reboot # 内核更新需重启,务必安排在窗口期
# 更新后确认当前生效内核,并保留旧内核以便回滚
uname -r
sudo grubby --default-kernel
sudo grubby --info=ALL | grep -E "^kernel|^index"四、容量管理:什么时候该扩容?
结论:容量管理的关键不是"现在用了多少",而是"按当前增速还能撑几天"。 建立增长趋势预测,设定明确的扩容触发线。
推荐触发线(可按业务调整):
- 磁盘:使用率 > 85% 告警;按近 7 天日均增长量预测,若剩余可用天数 < 30 天,立即扩容或清理。
- 内存:使用率 > 90% 且持续 1 小时,或 swap 使用量 > 1GB,需要扩容或优化。
- CPU:日均 CPU > 70% 持续 3 天,说明冗余不足,需要扩容。
- 带宽:峰值带宽达到购买带宽的 80%,提前扩容(带宽扩容往往有生效延迟)。
- 连接数:数据库连接数达到
max_connections的 70%,需要扩连接池或加从库。
#!/usr/bin/env bash
# /opt/ops/capacity-forecast.sh 磁盘容量增长预测
# 思路:用近 7 天的使用率差值推算日均增速,算出还能撑几天
MOUNT=${1:-/}
now=$(df -P "$MOUNT" | awk 'NR==2{gsub("%","",$5); print $5}')
total_kb=$(df -P "$MOUNT" | awk 'NR==2{print $2}')
used_kb=$(df -P "$MOUNT" | awk 'NR==2{print $3}')
# 若 7 天前有巡检记录则对比,否则用近 24 小时增量估算
hist=$(grep -h "^$MOUNT " /var/log/df-history.log 2>/dev/null | tail -n 1 | awk '{print $2}')
if [ -n "$hist" ]; then
days=7
else
hist=$((used_kb - 102400)); days=1
fi
growth_kb=$(( (used_kb - hist) / days ))
if [ "$growth_kb" -le 0 ]; then
echo "磁盘 $MOUNT 当前已用 ${now}%,近期无明显增长。"
else
remain_kb=$((total_kb - used_kb))
remain_days=$(( remain_kb / growth_kb ))
echo "磁盘 $MOUNT 当前已用 ${now}%,日均增长 $((growth_kb/1024))MB,预计 ${remain_days} 天后写满。"
[ "$remain_days" -lt 30 ] && echo ">>> 触发扩容线:剩余不足 30 天,请安排扩容或清理。"
fi
# 记录本次采样,供下次对比
echo "$MOUNT $used_kb $(date +%F)" >> /var/log/df-history.log# 每天采样一次,攒够 7 天数据后预测就有意义了
echo "0 9 * * * root /opt/ops/capacity-forecast.sh / >> /var/log/capacity.log 2>&1" \
| sudo tee /etc/cron.d/capacity-forecast五、备份验证与恢复演练
结论:没验证过的备份等于没有备份。 备份验证的最低要求是每周抽样恢复一次,每季度做一次完整恢复演练,并如实记录 RTO(恢复时间目标)与 RPO(恢复点目标)。
# 备份完整性校验:比对源库与备份文件的记录数
mysqldump -u root -p'RootStrongPass2026' --single-transaction --routines app_db \
| gzip > /backup/app_db_$(date +%F).sql.gz
# 记录校验值,便于日后核对备份是否被篡改或损坏
sha256sum /backup/app_db_$(date +%F).sql.gz >> /backup/CHECKSUM.txt
# 抽查验证:恢复到临时实例并查一条数据
gunzip < /backup/app_db_2026-03-17.sql.gz | mysql -u root -p'RootStrongPass2026' app_db_restore_test
mysql -u root -p'RootStrongPass2026' -e "SELECT COUNT(*) FROM app_db_restore_test.users;"
mysql -u root -p'RootStrongPass2026' -e "DROP DATABASE app_db_restore_test;"
# 异地备份:备份文件必须有一份在另一台机器/另一个地域
rsync -avz --delete -e "ssh -p 22" /backup/ backup@10.0.1.50:/backup/offsite/演练要记录三个数字:实际 RTO(从开始恢复到业务可用用了多久)、实际 RPO(丢了多少数据)、失败点(哪一步卡住了)。这三个数字是唯一能证明备份体系有效性的证据。
六、文档与值班交接
结论:文档的最低标准是"一个不熟悉这台机器的人,照着文档能完成日常操作与常见故障处理"。 达不到这个标准,就等于人肉单点。
每台服务器至少维护四份文档:
- 资产信息:主机名、IP、配置、上架位置、购买/维保到期时间、负责人。
- 部署文档:装了什么、怎么装的、配置文件路径、端口与账号(密码进密钥管理系统,不进文档)。
- Runbook:常见故障的处理步骤(磁盘满、CPU 高、服务起不来、数据库连不上),每条都写清"现象 → 判断 → 操作 → 验证"。
- 变更记录:历次改了什么、什么时候改的、为什么改。
值班交接要做到三点:未闭环的告警必须当面交接、正在进行的变更必须写明进度和回滚点、当天异常必须写进交接日志。
# 用一条命令生成标准化的交接快照,方便值班记录留痕
cat </dev/null || echo 0)
进行中变更 : $(tail -n 5 /var/log/change.log 2>/dev/null || echo 无)
今日异常 : $(journalctl -p err --since today --no-pager | wc -l) 条 ERROR
备份状态 : $(ls -1t /backup/*.gz 2>/dev/null | head -1 || echo 未找到)
EOF
企业QQ咨询




