生产巡检:从运行指标到异常处理
生产巡检定期检查系统是否仍能完成业务,以及运行条件是否正在恶化。已经持续报警的问题需要及时处理;磁盘增长、备份过期、证书将到期或某个副本长期脱离集群,则适合通过周期巡检提前发现。
一次有用的巡检结果,应能说明哪个对象在多长时间内出现了什么变化,是否影响业务,接下来由谁做什么。单独保存一张绿色看板或一组命令输出,无法回答这些问题。
先确定检查对象与观察窗口
从服务清单进入
巡检对象以实际交付的服务为单位,再展开到运行实例和依赖:
订单服务
├── 入口:域名、证书、代理、业务探测
├── 应用:版本、实例、健康、请求结果、线程与连接
├── 数据:数据库、缓存、消息、任务进度
├── 主机:CPU、内存、磁盘、网络、系统服务
├── 观测:采集、规则评估、通知、数据新鲜度
└── 恢复:备份、独立副本、恢复演练、接管方式服务清单应包含维护人、环境、运行位置、入口、依赖、正常副本数与维护窗口。已退役服务从监控中删除前,确认流量、定时任务和数据保留均已处理;临时关闭的告警和未完成的维护也要单独列出。
频率按风险设置:关键服务的业务探测连续运行,资源与错误趋势每天查看,容量与版本支持状态定期评估,备份恢复按业务恢复目标演练。巡检不应等待人工登录才首次发现服务不可用。
读数需要带上时间和范围
瞬时值适合观察“现在”,区间速率描述一段时间的活动,累计计数需要比较增量。同一服务在低峰与高峰的正常值可能相差很大,应同时看近期窗口和相近业务周期,而不是把统一阈值套到所有系统。
进程刚重启时,累计计数可能归零;短时图表可能只覆盖新实例,旧实例的异常仍在历史中。检查版本、实例 ID、运行时长,再解释资源和错误趋势。
记录时至少区分以下口径:
| 读数 | 比较前需要确认 |
|---|---|
| CPU 80% | 单核、整机还是容器配额;采样窗口多长 |
| 内存 90% | used/RSS/working set/堆占用;是否包含缓存 |
| 磁盘 80% | 哪个挂载点;字节还是 inode;增长多快 |
| 请求失败 5% | 哪个接口;分母多少;是否包含业务拒绝 |
| 消息积压 1000 | 新增与消费速率;最老消息等待多久 |
| 备份成功 | 哪个数据集;存在哪里;恢复验证是否完成 |
环境与权限准备
以下命令针对 Linux 主机。基础进程命令来自 procps,磁盘性能工具来自 sysstat,网络命令来自 iproute2,另外会用到 curl、openssl、lsof 和发行版的 systemd 工具。通过受批准的软件源预先安装;不要在生产故障时临时从不明地址下载脚本。
普通账户执行只读检查,读取完整 journal、进程文件描述符或某些内核信息时按现有流程提权。Linux 容器没有完整 systemd 和宿主视图;主机资源在主机上查,容器配额到对应 cgroup 查。遇到权限拒绝、工具缺失或文件不存在,记录“未取得读数”,不要把它变成零或正常。
命令输出可能含内部地址、进程参数和业务日志。采集时优先选择必要字段,不整包导出环境变量、连接凭据或完整进程命令行。
解释主机与进程的资源读数
CPU、load 与资源等待
uptime
nproc
vmstat 1 6
ps -eo pid,ppid,comm,stat,%cpu,%mem --sort=-%cpu | head -n 16uptime 给出 1、5、15 分钟 load average。Linux load 包含可运行任务及不可中断等待任务,因此 load 上升可能来自 CPU 排队,也可能来自 I/O 等待。结合可用 CPU、业务延迟和进程状态解释,不能把 load 直接换算成 CPU 使用率。
vmstat 1 6 第一行的多数速率和 CPU 统计来自启动以来的平均,随后才是每秒区间。重点关注:
r:可运行任务数量,持续排队时检查 CPU 与配额。b:不可中断睡眠任务,结合 I/O 和内核日志定位等待对象。us/sy/id:用户态、内核态与空闲 CPU 时间比例。wa:I/O 等待相关的空闲时间口径,需要结合设备与任务观察。si/so:交换读入与写出,持续活动且延迟上升时关注内存压力。
这些字段不是一组直接对应根因的开关。ps %cpu 又主要是进程生命周期内的 CPU 比率,短时尖峰应使用 pidstat -u 1 5 等区间采样。字段说明见 vmstat 手册 和 pidstat 手册。
Linux PSI 描述任务因资源不足而停顿的时间比例:
cat /proc/pressure/cpu
cat /proc/pressure/memory
cat /proc/pressure/ioavg10/avg60/avg300 对应不同平滑窗口,some 表示至少有任务被该资源阻塞,full 表示所有非空闲任务同时被阻塞的情况;系统级 CPU full 有特殊语义,不直接套用内存/IO 的解释。PSI 上升说明等待加重,仍要结合业务延迟和具体任务。定义见 Linux PSI。
容器可能在宿主还有空闲 CPU 时被自己的配额限流。cgroup v2 的 cpu.max 给出配额与周期,cpu.stat 的 throttling 计数适合比较区间增量;同时核对父级限制。路径需要从目标进程的 cgroup 成员关系定位,不假设所有主机都是同一个目录布局。完整层级和接口见 cgroup v2。
内存、Swap 与 OOM
free -h
ps -eo pid,comm,rss,vsz --sort=-rss | head -n 16
sudo journalctl -k --since '1 hour ago' --no-pagerfree 的 available 更接近无需交换即可供新工作使用的估计值,Linux 用空闲内存做缓存是正常行为。VSZ 是虚拟地址空间规模,RSS 是常驻页大小,二者都不等于 Java 堆。共享页还可能被多个进程的 RSS 重复计算;需要细分时检查 /proc/PID/smaps_rollup 中的 PSS 等数据。内存字段见 free 手册 和 proc 内存接口。
Java 服务除了堆,还有线程栈、元空间、代码缓存、直接内存和本地库开销。容器的内存上限需要容纳这些部分,不能把 -Xmx 设置成整个容器限额。堆平稳而 RSS 增长时,沿这些对象继续分析,避免反复扩大堆。
进程退出 137 通常对应被 SIGKILL 终止,但原因可能是 OOM,也可能是手工或平台终止。核对 Docker 的 OOMKilled、系统内核日志及 cgroup memory.events,再判断。cgroup 局部 OOM 可以在宿主内存尚有余量时发生。
不要通过清空页缓存来“修复”高内存占用,这可能提高后续磁盘读取压力。持续换页、PSI 与业务延迟共同恶化时,优先分析负载、泄漏与工作集,调整需要经过变更和复测。
磁盘容量、inode 与设备等待
findmnt -T /var/log
df -hT /var/log
df -i /var/log
sudo du -xhd1 /var/log
iostat -xz -y 1 5替换为实际应用或数据目录。先确认它所在的文件系统,再比较总量、剩余字节和 inode。du -x 不跨文件系统,但遍历大目录仍可能产生明显 I/O;应限定路径,在负载允许时执行。
iostat -y 配合区间采样跳过启动以来的首份报告。await 包含排队和完成时间,aqu-sz 反映平均队列深度;持续升高时进一步看请求大小、吞吐与业务访问模式。现代并行设备、RAID 和虚拟磁盘不能仅凭 %util=100 就宣布吞吐达到上限。字段解释见 iostat 手册。
如果 df 显示占用很大而目录统计找不到对应文件,检查已删除但仍打开的文件:
sudo lsof +L1目录项删除后,只要进程仍持有打开的文件,底层数据就可能继续占用空间;最后一个引用关闭后才释放。这里应按服务支持的方式重新打开日志或安排重启,不能随意终止持有者。日志轮转、补采和磁盘处理见 日志体系。
可以用一个独立小实验理解这个行为:下载打开文件实验。在 Linux 普通用户的临时目录运行 bash held-file.sh,脚本只创建 8MiB 文件,打开描述符后删除自己的文件,再读取描述符状态,最后关闭并移除空临时目录。它不会操作已有日志,也不会填满磁盘。
输出中的 path_exists=no 与 open_size=8388608 可以同时成立。目录里已没有名称,打开描述符仍能访问数据;关闭后出现 descriptor_closed=yes。实验期间不要用主机 df 的细微变化作为唯一判断,其他进程也可能同时写盘。
文件描述符、进程与服务状态
先确定目标服务和 PID,避免从文章复制一个无关数字:
set -o pipefail
UNIT=orders.service
systemctl show "$UNIT" -p ActiveState -p SubState -p MainPID -p NRestarts
PID=$(systemctl show "$UNIT" -p MainPID --value)
if test "$PID" -gt 0 && test -d "/proc/$PID"; then
cat "/proc/$PID/limits"
find "/proc/$PID/fd" -mindepth 1 -maxdepth 1 -type l | wc -l
else
printf '未取得运行中的主进程,请先检查服务状态\n' >&2
fiMainPID=0 时先查服务是否未启动或类型特殊,不继续访问 /proc/0。描述符数量是某一时刻的占用,与 Max open files 的软限制比较;权限错误时不要把管道最后得到的 0 当成真实数量。
重启次数持续增长,即使每次检查都是 active,也值得调查。读取同 unit 的退出状态和 journal,结合发布、内存与依赖变化。systemd 的状态、重启和启动限制见 systemd.service。
检查入口、依赖与恢复条件
网络检查跟随实际请求路径
ip -br addr
ip route
ss -lnt
ss -s
ip -s link网卡有地址之后,仍要检查目标路由和监听地址。127.0.0.1 监听只接受本机回环访问,0.0.0.0 表示 IPv4 通配监听,但是否从远端可达还受主机防火墙、云安全组、NAT 和入口策略影响。
ip -s link 的错误与丢弃计数应比较区间增量,累计大值可能来自历史故障。ss -s 用于看连接整体分布,具体异常再限定目标和状态;大量 TIME_WAIT 并不自动表示端口即将耗尽,持续增长的 CLOSE_WAIT 则应追查应用是否关闭连接。工具选项见 iproute2 项目。
业务探测要使用已获授权、不会产生真实业务副作用的端点。下面变量替换成服务清单中的地址:
CHECK_URL=https://api.example.com/health/ready
curl -q --noproxy '*' --fail-with-body -sS --max-time 10 \
-o /dev/null \
-w 'status=%{http_code} remote=%{remote_ip} dns=%{time_namelookup} connect=%{time_connect} tls=%{time_appconnect} first_byte=%{time_starttransfer} total=%{time_total}\n' \
"$CHECK_URL"-q 禁用用户 curl 配置,--noproxy '*' 用于明确验证直连路径;若生产访问必须经过代理,应另设带明确代理的探测,而不是强行绕过公司网络策略。各时间字段多为从请求开始累计的时间,不是可以全部相加的独立阶段。连接复用、重定向和协议也会影响解释,见 curl 手册。
健康端点应同时检查预期状态码和必要的响应字段。应用自报 ready 之后,关键业务还应有受控的合成交易或只读探测,覆盖真实入口及依赖。出现异常时先复测相同路径,再按 网络排查 区分 DNS、连接、TLS 与 HTTP。
域名、证书与时钟
证书检查需要使用真实域名执行 SNI 和主机名校验。下面在 Linux 上运行,TLS_HOST 替换为授权目标;timeout 来自 GNU coreutils:
set -o pipefail
TLS_HOST=api.example.com
timeout 10 openssl s_client \
-connect "$TLS_HOST:443" -servername "$TLS_HOST" \
-verify_hostname "$TLS_HOST" -verify_return_error </dev/null检查验证结果、证书链及目标身份;连接被拒、超时、信任失败分别记录,不使用 -k 跳过信任。内部 CA 需要显式提供受信任证书链。SNI 与验证选项见 openssl s_client。
对已经部署到本机的证书文件,可检查未来七天内是否到期:
CERT_FILE=/etc/nginx/tls/api/fullchain.pem
openssl x509 -in "$CERT_FILE" -noout -checkend 604800返回 0 表示该证书在窗口结束前不会过期,非零则要检查到期或读取解析错误;它没有验证线上服务正在提供这张证书,也没有验证域名或完整信任链。轮换后仍需重新访问线上入口。选项见 openssl x509。
证书和 DNS 巡检还需记录续期任务的最近结果、验证记录、解析到的入口及旧证书是否真正替换。TTL 是缓存控制条件,修改 DNS 后要从代表性的解析位置观察,不把某台机器已刷新当成全部客户端已切换。
时钟偏移会影响 TLS、令牌、日志关联和集群租约。systemd 环境先查看 timedatectl status;使用 chrony 时检查 chronyc tracking 与 chronyc sources -v,关注同步源、偏移和可达性。工具不存在时先核对该发行版实际运行的同步服务,不能同时随意启动另一套客户端。
容器、副本与数据依赖
docker context show
docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}'
docker stats --no-stream先确认操作的是目标 Docker daemon。docker stats 读取当前容器资源,内存和 CPU 的显示口径与宿主 free/top 不同;比较前看限制与统计方法,见 Docker stats。
指定实例后检查状态和运行身份:
CONTAINER=orders-api
docker inspect --format 'status={{.State.Status}} exit={{.State.ExitCode}} oom={{.State.OOMKilled}} restarts={{.RestartCount}} user={{.Config.User}}' "$CONTAINER"
docker inspect --format '{{json .State.Health}}' "$CONTAINER"没有配置 healthcheck 时不会得到业务健康结果。Kubernetes 还需查看期望与 Ready 副本、重启、事件、PVC、证书和节点压力;只统计 Running Pod 数会漏掉 readiness 失败。集群操作沿 Kubernetes 的环境与权限要求执行。
数据依赖检查应关注可恢复性和正在处理的工作,而不止端口:
| 依赖 | 日常判断重点 | 异常时进一步检查 |
|---|---|---|
| 数据库 | 连接、慢查询、锁等待、复制进度、磁盘 | 长事务、复制错误、只读状态及实际写入路径 |
| Redis | 内存、淘汰、阻塞、持久化和复制 | maxmemory 策略、热点、快照/AOF 错误、主从角色 |
| 消息系统 | 生产与消费速率、积压、最老消息年龄 | 消费失败、重试/死信、分区倾斜、存储与副本 |
| 注册/配置服务 | 成员、选主、配置读取及客户端状态 | 集群通信、会话、租约与权限 |
| 对象存储 | 上传/读取错误、容量、生命周期和副本 | 访问身份、桶策略、配额、版本与删除标记 |
不要在巡检时对生产队列随意消费一条消息、对数据库执行无边界扫描或对缓存运行阻塞式全量枚举。各产品的只读观察入口和恢复流程交给已配置的运行手册,异常需要变更时再申请对应操作。
备份和监控系统也要检查
备份巡检记录最新可用恢复点、复制完成时间、存储位置、加密密钥可用性和恢复演练结果。备份任务返回成功但对象无法读取、备份链缺段或密钥已失效,仍可能无法恢复。
副本复制会同步逻辑误删,不能替代独立备份;同机另一个目录也无法抵御整机故障。按业务要求分别衡量 RPO(可容忍数据损失)与 RTO(恢复时长),通过隔离恢复测量,而不是从备份文件大小推算。具体方法见 备份与恢复。
监控检查数据是否新鲜、抓取是否正常、规则是否继续评估、通知是否到达。日志平台关注采集积压和最早未入库时间,追踪平台关注采样与数据缺口。定期运行受控告警和恢复通知测试,方法见 监控告警。
把发现变成可完成的处理
按业务影响和剩余时间安排动作
| 发现 | 优先处理方向 |
|---|---|
| 关键业务不可用,数据正在损坏或泄露 | 立即进入应急,保留必要信息并按授权止损 |
| 可用副本减少、恢复能力失效、磁盘即将耗尽 | 明确剩余容量与可承受时间,安排尽快修复 |
| 资源趋势偏离但尚无业务影响 | 排查负载或配置变化,计划调整与复测 |
| 信息缺失、工具失败或权限不足 | 标记未确认并补充观察,不归入正常 |
先处理业务影响,再在安全条件下分析原因。CPU 高但服务正常与 CPU 高且延迟持续扩大,需要的响应节奏不同;备用副本长期异常,即便主实例正常,也已降低故障承受能力。
容量判断尽量换成剩余时间。例如某日志盘可用 30GiB,稳定净增长约 5GiB/天,按简单线性估算只剩约六天。轮转、备份、峰值和增长拐点会改变这个估计,应留出申请资源、扩容和验证的时间,不等占用达到某个统一百分比才行动。
保留必要信息,避免巡检变成隐蔽变更
一条可交接的记录可以写成:
对象:orders / staging / 指定实例与版本
观察:近 30 分钟日志净增长明显加快,最近 5 分钟仍持续
影响:业务探测正常;按当前增长速度,磁盘余量不足一个工作日
已检查:增长来自应用 DEBUG 文件,集中采集仍在补发
下一步:应用维护人确认临时日志开关;批准后恢复原级别
复测:增长速率下降,采集延迟回落,业务探测保持正常记录实际取得的数值、窗口、命令退出结果和关联工单;未知原因保留为未知。密码、完整客户请求和未经脱敏的日志不进入公共报告。
巡检脚本默认只读,遇到异常返回明确状态或产生待处理项。不要把自动重启、清理文件、修改参数和“继续巡检”串在同一脚本里;这些操作可能暂时隐藏问题,也会改变下一次观察的条件。需要自动恢复的动作,应作为单独受控流程,配置范围、并发、停止条件和回退。
修复后检查什么
修复后沿最初失败的路径重新检查,确认业务结果、资源趋势和副作用。例如恢复日志级别后,除了磁盘增长下降,还要确认重要错误仍会记录、采集器能追上积压;恢复消费后,除了消费者在线,还要观察积压年龄持续下降和重复处理结果。
处理记录写清执行人、变更内容、复测窗口和仍需跟进的问题。恢复期过短或只检查一次成功,可能漏掉缓存周期、定时任务或下一次流量高峰。持续出现的同类问题应更新容量计划、告警或运行配置,避免长期依赖人工巡检重复发现。
权威资料与规范地址
Linux 资源与进程
- vmstat 手册:https://man7.org/linux/man-pages/man8/vmstat.8.html
- pidstat 手册:https://man7.org/linux/man-pages/man1/pidstat.1.html
- Linux PSI:https://docs.kernel.org/accounting/psi.html
- cgroup v2:https://docs.kernel.org/admin-guide/cgroup-v2.html
- free 手册:https://man7.org/linux/man-pages/man1/free.1.html
- proc 内存接口:https://docs.kernel.org/filesystems/proc.html
- iostat 手册:https://man7.org/linux/man-pages/man1/iostat.1.html
- systemd.service:https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
网络、证书与服务
- iproute2 项目:https://git.kernel.org/pub/scm/network/iproute2/iproute2.git/
- curl 手册:https://curl.se/docs/manpage.html
- openssl s_client:https://docs.openssl.org/3.0/man1/openssl-s_client/
- openssl x509:https://docs.openssl.org/3.0/man1/openssl-x509/
- Docker stats:https://docs.docker.com/reference/cli/docker/container/stats/
