简介:这份QC课题文档面向IT运维人员与质量管理小组成员,聚焦通信行业中间件故障处理效率低、根因定位耗时长的问题,完整呈现从选题、现状调查、原因分析到要因确认、对策制定与效果检查的QC活动全流程。资源包共1个docx文件,约604KB,内容涵盖小组介绍与名词解释、五条要因的逐项验证、接入自动化智能化维护管理平台的实施过程,以及效果检查、巩固措施和下一步打算等章节,目录层级清晰,便于按模块查阅。已有244人学习。读者可从中获取一套可复用的故障诊断改进思路:如何用定制化执行脚本结合运维管理平台实现一键故障诊断,如何量化目标(如诊断时间降低30%),以及如何组织QC课题的材料撰写与成果总结,适合运维骨干、QC推进者参考借鉴。
1. 从 56 分钟压到 44 分钟:一份能照着复现的中间件故障诊断 QC 课题
凌晨两点被告警叫醒,登录跳板机,翻三台机器的 catalina.out,grep 关键字,再登监控看 JVM 堆内存曲线——这套动作熟练的运维工程师走一遍大概二十分钟,不熟练的能折腾一小时。这份 QC 课题记录的就是把这段"救火式"流程压进工具里的完整过程:某通信企业运维小组用 53 个系统、67 宗历史故障做基线,把平均故障处理时长从 56 分钟降到 44 分钟,效率提升 21.4%。它不是一个能直接双击运行的软件包,而是一套"采集脚本 + 运维平台调度 + 关键字字典 + 诊断模板"的落地方案,适合手里有中间件集群、正在被重复排障拖住的运维和 SRE 照着搭一遍。下面按"它到底怎么设计的、脚本怎么写、坑在哪"拆开讲。
2. 故障诊断工具的四段式架构:采集、处理、分析、输出
这套方案最值得抄的地方不是某个脚本,而是把一次故障诊断拆成了四个可以独立替换的环节。小组调研过市面上的根因分析产品,结论是通用工具对自家 Tomcat、Weblogic、ActiveMQ 混跑的异构环境适配成本太高,于是退回到"自己写原子脚本 + 借运维管理平台批量下发"的路子。四段式的好处是:采集层挂了不影响分析逻辑,分析规则改了不用动采集脚本,每一段都能单独灰度。
2.1 为什么选"平台调度 + 原子脚本"而不是一体化 Agent
一体化 Agent 的典型问题是升级要全量推、出问题要全量回滚,而 53 个系统里既有 A 级核心系统也有边缘业务,不可能同一时间窗口停机升级。原子脚本方案把每个采集动作做成独立可执行单元,平台只负责"在哪些主机上、按什么顺序、跑哪个脚本",脚本本身无状态、可重复执行。这意味着新增一种中间件类型,只需要加一个采集脚本和一份指标模板,不用碰平台代码。
代价也很明确:脚本的健壮性全靠自己写。平台不会帮你处理"目标主机 SSH 超时""脚本执行到一半被 OOM Killer 干掉"这类情况,这些必须在脚本层做超时和兜底。我一般会在每个采集脚本头部统一加set -euo pipefail和timeout包裹,宁可采不到数据返回非零码让平台标记失败,也不要产出一份半截的脏数据进分析环节。
2.2 采集模块:OS 参数与中间件参数各采什么
采集范围在课题里列得很清楚,分两类。主机 OS 层采 CPU 使用率、内存使用率、磁盘使用率、磁盘 IO 繁忙度、监听端口、网络流量;中间件层按类型分别采,Tomcat 和 Weblogic 采 JVM 堆内存使用率、进程状态、端口状态、每分钟 FGC 频次是否异常、FGC 总次数、活动线程数占比、JDBC 连接池活动数占比、年轻代与年老代内存使用率;Nginx 采后端请求响应时间、服务状态、端口、文件权限与内容状态、error 与 exception 关键字;Redis 采服务端口、阻塞客户端连接数、当前内存使用率、上次 RDB 持久化状态、因内存限制被拒连接数、key 命中率。
下面是一个可直接改用的 OS 层采集脚本骨架,输出成平台能解析的 key=value 格式:
#!/bin/bash # os_collect.sh - 主机 OS 指标采集,输出 key=value 供处理模块解析 set -euo pipefail HOST=$(hostname -s) TS=$(date +%Y%m%d%H%M%S) OUT="/data/diag/raw/${HOST}_os_${TS}.log" # CPU 使用率:取 1 秒采样,用 100-idle 计算 cpu_idle=$(top -bn1 | awk '/Cpu\(s\)/ {print $8}') cpu_used=$(awk -v i="$cpu_idle" 'BEGIN{printf "%.2f", 100-i}') # 内存使用率:排除 cache/buffer mem_used=$(free | awk '/Mem:/ {printf "%.2f", $3/$2*100}') # 磁盘使用率:取根分区 disk_used=$(df -h / | awk 'NR==2 {gsub("%","",$5); print $5}') # 磁盘 IO 繁忙度:取 sda 的 %util io_util=$(iostat -dx 1 2 2>/dev/null | awk '/^sda/ {v=$NF} END{print v+0}') # 监听端口清单 ports=$(ss -lntp 2>/dev/null | awk 'NR>1 {print $4}' | awk -F: '{print $NF}' | sort -un | paste -sd,) { echo "host=${HOST}" echo "ts=${TS}" echo "cpu_used_pct=${cpu_used}" echo "mem_used_pct=${mem_used}" echo "disk_used_pct=${disk_used}" echo "disk_io_util=${io_util}" echo "listen_ports=${ports}" } > "$OUT" echo "OK ${OUT}"逻辑说明:top -bn1只取一次快照,避免脚本挂住;free用$3/$2而不是$3/($2+$4),是因为课题里关注的是应用可用内存压力,cache 部分不计入。iostat -dx 1 2跑两轮取第二轮,第一轮是自开机以来的平均值,直接拿来判断当前 IO 会失真。listen_ports用sort -un去重排序,方便后续和基线端口清单做 diff。参数上唯一需要按环境调的是磁盘设备名sda,NVMe 机器要改成nvme0n1,这个在推广到 50+ 系统时是第一个翻车点,后面避坑章节细说。
2.3 处理模块:Python 解析脚本把原始数据转成可读指标
采集出来的是原始文本,处理模块负责按目录和文件格式分类,再用 Python 脚本把原始值换算成带阈值判断的易读文档。课题里提到"设置好指标计算逻辑",实际落地时这部分最容易写成一坨 if-else,我的做法是把阈值和计算规则抽成配置,脚本只做执行。
# parse_metrics.py - 读取 raw 目录下的采集文件,输出结构化诊断数据 import os, re, json, glob # 阈值配置:按中间件类型分组,后续新增类型只改这里 THRESHOLDS = { "os": {"cpu_used_pct": 85, "mem_used_pct": 90, "disk_used_pct": 85, "disk_io_util": 80}, "tomcat": {"heap_used_pct": 85, "fgc_per_min": 5, "thread_active_pct": 80, "jdbc_active_pct": 85}, "redis": {"mem_used_pct": 85, "blocked_clients": 10, "rejected_conn": 0}, } def parse_kv(path): data = {} with open(path, encoding="utf-8", errors="ignore") as f: for line in f: if "=" in line: k, v = line.strip().split("=", 1) data[k] = v return data def judge(mw_type, metrics): """按阈值判定异常,返回异常项列表""" rules = THRESHOLDS.get(mw_type, {}) abnormal = [] for key, limit in rules.items(): if key not in metrics: continue try: val = float(metrics[key]) except ValueError: continue if val > limit: abnormal.append({"metric": key, "value": val, "limit": limit}) return abnormal def main(raw_dir, out_dir): os.makedirs(out_dir, exist_ok=True) for path in glob.glob(os.path.join(raw_dir, "*_os_*.log")): metrics = parse_kv(path) abn = judge("os", metrics) result = {"source": os.path.basename(path), "type": "os", "metrics": metrics, "abnormal": abn} name = os.path.basename(path).replace(".log", ".json") with open(os.path.join(out_dir, name), "w", encoding="utf-8") as f: json.dump(result, f, ensure_ascii=False, indent=2) if __name__ == "__main__": main("/data/diag/raw", "/data/diag/parsed")逻辑说明:parse_kv容错读取,遇到非 key=value 行直接跳过,因为采集脚本可能混入平台注入的日志行。judge把"超过阈值"统一抽象成val > limit,注意 Redis 的rejected_conn阈值是 0,任何非零都算异常,这个语义和百分比指标不同,配置里用同一个比较符是刻意的简化,实际项目里如果出现"低于阈值才异常"的指标(比如 key 命中率),要单独加方向字段。参数上THRESHOLDS的数值不是拍脑袋定的,课题里 FGC 频次异常标准是 1 分钟内超过 5 次,堆内存 85% 是行业常见告警线,这两个值在推广到不同业务系统时要按基线重新校准,直接照搬会误报。
2.4 分析模块:关键字字典才是这套工具的灵魂
很多人以为这套工具的价值在采集,其实真正省时间的是分析模块里的关键字字典。课题里给了一张错误关键字与解决方法的对照表,覆盖Java.net.SocketTimeoutException、Address already in use、Connection refused、Too many open files、OutOfMemoryError: PermGen space、OutOfMemoryError: Java heap space、unable to create new native thread、Could not create the Java Virtual Machine等十余类高频报错。这张表把"看到报错 → 想起怎么处理"的脑内检索变成了查表,对新手尤其友好。
分析逻辑是:筛选中间件指标做批量比对,超过告警阈值就把告警信息输出到异常目录,否则输出到诊断正常目录。关键字匹配则对日志文件做正则扫描,命中即附带对应解决方法。这里有个设计取舍值得说:课题没有做"根因推断",只做"异常聚合 + 关键字命中",因为根因推断在异构环境里误判率太高,反而增加运维的确认成本。宁可给三条可能原因让人判断,也不要给一条错误结论让人走弯路。
3. 从试点到 50+ 系统:推广阶段的三个关键动作
工具在 E 掌通和 Portal 两个系统跑通,不等于能在 BM 域 50+ 系统跑通。推广阶段课题用了"以测代训"和"灰度改版"两个动作,这部分是很多同类课题写得最虚、实际最要命的地方。
3.1 以测代训:用试点比对筛出通用诊断模型
不同业务系统的架构差异直接体现在指标基线上。A 级核心系统的 Tomcat 堆内存常年 70% 以上是正常的,边缘系统到 70% 就该查内存泄漏了。课题的做法是在试点系统上做比对、筛选、归并:把两个试点系统跑出来的指标分布和实际故障记录对齐,找出哪些阈值是通用的、哪些必须按系统分组。归并后的结果是形成一套"系统故障快速定位模型",按业务层级(A 级 / 普通)分档配置阈值,而不是一套阈值打天下。
具体操作上,我一般会拉一张对照表,把每个系统的历史故障时刻的指标快照和当时的人工判断结论并排放,看工具判定和人工判定的一致率。一致率低于 80% 的系统不进第二批推广,先单独调阈值。这个动作看起来慢,但比推上去之后天天误报、运维直接关掉告警要快得多。
3.2 灰度改版:业务变更时诊断方案怎么跟着改
课题提到"及时收取开发方业务变更,进而优化适配诊断方案"。这句话翻译成操作就是:业务方每次发版,运维侧要同步更新三样东西——端口清单基线、关键字字典、指标阈值。新增一个下游接口,listen_ports基线要加;框架升级换了异常类名,关键字字典要加;连接池参数调整,JDBC 活动数阈值要跟着动。
落地时建议把这三样做成版本化配置,和业务发版单挂钩。我见过太多团队把诊断脚本写完就扔在那,半年后业务改了三次,脚本还在按老端口探测,天天报"端口未监听"的假故障,最后整个工具被贴上"不准"的标签弃用。这不是工具的问题,是配置没跟着业务走。
3.3 效果验证:44 分钟这个数是怎么算出来的
课题的效果数据是:部署后 7 月到 8 月共 25 宗故障,总处理时长 1110 分钟,平均 44 分钟,对比基线 56 分钟降低 12 分钟,效率提升 21.4%。这个算法本身没问题,但看数的时候要注意两点:一是样本量 25 宗偏小,单宗超长故障就能把均值拉偏,严谨一点应该同时看中位数和 P90;二是"故障处理时长"的起止点定义要和基线一致,基线是从告警产生到闭环,部署后如果工具在告警产生前就通过巡检发现了问题,这部分时长算不算进去,口径不同结论会差很多。
验证方法上,建议在工具上线后保留一段"双轨期":工具给出诊断结论的同时,人工照常排查,记录两者耗时和结论差异。双轨跑一个月,既能拿到可信的对比数据,也能暴露关键字字典的漏配项。课题里配监督员监控半年执行效果,本质就是这个思路的延长版。
4. 避坑清单:这套方案落地时最容易翻车的五个地方
4.1 采集脚本在部分主机上静默失败
现象:平台显示任务成功,但分析目录里缺了好几台主机的数据。原因:脚本里某条命令在特定 OS 版本上不存在(比如老系统没有ss只有netstat),set -e让脚本中途退出,但退出码被平台的批量执行框架吞掉了。解决:脚本内每条外部命令都做存在性判断,command -v ss >/dev/null || use netstat,并且在脚本末尾显式exit 0前校验输出文件非空,空文件主动返回非零码让平台标记失败。
4.2 阈值照搬导致误报淹没告警
现象:工具上线第一周,异常目录里堆了几百条告警,运维看都不看直接忽略。原因:试点系统的阈值直接推到了全部 53 个系统,边缘系统负载天然低,85% 的堆内存线对它们永远触发不了,而核心系统又频繁越过。解决:按业务层级分档,先用一周的纯观察模式(只记录不告警)收集各系统的指标分布,取 P95 作为初始阈值,再人工校准。课题里"以测代训"的比对动作就是干这个的,跳过它必然翻车。
4.3 关键字字典漏配新异常类
现象:某次故障日志里明明有异常堆栈,工具却判定"诊断正常"。原因:框架升级后异常类从java.net.SocketException变成了带包名的新类,字典里的正则没覆盖。解决:字典匹配用宽松正则(如Socket.*Exception)而不是精确字符串,同时每周对"诊断正常但人工确认有故障"的案例做一次漏配复盘,把新关键字补进字典。字典是活的,不是写完就封版。
4.4 日志文件过大导致采集超时
现象:采集任务在日志量大的节点上超时,平台重试三次后放弃。原因:脚本对整个catalina.out做全量扫描,几个 G 的文件在低配机器上读不完。解决:只扫最近 N 分钟增量(用tail -c或按文件修改时间过滤),关键字匹配限定在增量窗口内。故障诊断要的是"当前这次故障的现场",不是历史全量,这个边界不划清,脚本迟早被大日志拖死。
4.5 诊断结论被当成最终结论
现象:运维照着工具输出的"建议措施"操作,结果没解决问题,反而多绕了半小时。原因:关键字字典给的是"这类报错的常见处理方式",不是"你这个故障的根因"。Connection refused可能是对端没起,也可能是防火墙、也可能是端口配错,字典只能给方向。解决:在诊断报告模板里明确标注"以下为常见原因,需结合现场确认",并且把"最近一次同关键字故障的实际处理记录"附在建议后面,让人看到历史案例而不是干巴巴的条目。
5. 把诊断报告做成可回溯的资产:一个模板和一条习惯
工具跑通之后,真正拉开差距的不是采集了多少指标,而是诊断报告能不能被下一次故障复用。课题的巩固措施里写了"编写维护管理平台流程操作手册"和"收集使用过程中遇到的问题持续优化",这两条落到实操上,我建议做成一个固定模板加一条固定习惯。
模板长这样,每次诊断输出一份,存进知识库按关键字和时间索引:
| 字段 | 内容要求 | 示例 |
|---|---|---|
| 故障时间窗 | 告警产生到闭环的起止 | 2022-07-14 02:11 ~ 02:49 |
| 命中关键字 | 字典匹配到的异常条目 | OutOfMemoryError: Java heap space |
| 指标快照 | 异常时刻的堆内存、FGC、线程数 | heap 96%, FGC 12/min, thread 78% |
| 工具建议 | 字典给出的常见处理方式 | 调整 -Xmx,排查内存泄漏 |
| 实际根因 | 人工确认后的结论 | 某定时任务全量加载导致堆暴涨 |
| 处置动作 | 实际执行的操作 | 临时扩容堆至 2G,次日修复任务分批 |
| 耗时拆分 | 发现/定位/处置/闭环各段时长 | 3 / 18 / 6 / 11 分钟 |
有了这张表,下次再命中同一个关键字,工具建议旁边就能挂出"上次实际根因是 XX",把字典从静态条目变成带案例的活知识。课题里"运维经验易流失"这个非要因,其实靠这张表就能部分解决——老师傅的判断逻辑被结构化记录下来了,新人查表就能拿到八成信息。
那条习惯是:每次故障闭环后,强制走一遍"报告归档 + 字典复盘"两步,哪怕这次故障只花了五分钟。我吃过亏,早期觉得小故障不值得记,结果同一个Too many open files三个月内踩了四次,每次都要重新查 ulimit 怎么调。从那以后我每次处理完故障,不管多小,都强制把关键字和实际根因补进字典再关单。这套 QC 课题的价值不在于它把 56 分钟压到了 44 分钟,而在于它证明了"把排障过程结构化"这件事本身能持续产生复利。希望帮到你。
本文还有配套的精品资源,点击获取