4. 运维数据采集与预处理:日志、监控指标、工单、CMDB等数据源的采集与清洗
说实话,做运维知识图谱这件事,最让我头疼的从来不是算法选型,也不是图数据库调优。而是——数据。数据太脏了,太散了,太乱了。
我见过太多团队,一上来就急着建模、急着推理,结果数据采集阶段就翻车了。日志格式不统一,监控指标缺字段,工单系统里的描述全是口语,CMDB里的资产信息过期了三四年。你想想看,这种数据喂给大模型,它能学到什么?
所以这一章,咱们就踏踏实实把数据采集和预处理这件事聊透。说白了,这是整个知识图谱工程的「地基」。地基不稳,上面盖什么都白搭。
4.1 数据源全景:你到底要采哪些数据?
运维领域的数据源,我习惯把它们分成四大类。每一类的特点、采集方式、坑点都不一样。
| 数据源类型 | 典型代表 | 数据特点 | 采集频率 |
|---|---|---|---|
| 日志数据 | 应用日志、系统日志、访问日志 | 半结构化、量大、噪声多 | 实时/准实时 |
| 监控指标 | CPU、内存、QPS、延迟 | 结构化、时序性强、维度多 | 秒级/分钟级 |
| 工单数据 | 故障工单、变更工单、问题单 | 非结构化、文本为主、含流程信息 | 事件驱动 |
| CMDB | 主机、应用、中间件、网络设备 | 结构化、关系复杂、更新慢 | 小时级/天级 |
嗯,这里要注意一点。很多人以为CMDB数据是最「干净」的,其实恰恰相反。我在项目中遇到过好几次,CMDB里的数据跟实际环境差了十万八千里。比如某个主机明明已经下线了,CMDB里还标记为「运行中」。这种数据要是直接拿来建图谱,那推理出来的结果你敢信?
4.2 日志采集:从混乱到有序
日志是运维知识图谱里最丰富、也最让人头疼的数据源。我个人习惯用Filebeat + Logstash这套组合拳。Filebeat负责轻量级采集,Logstash负责解析和清洗。
先看一个典型的日志采集配置:
# filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/app/*.log
multiline.pattern: '^\d{4}-\d{2}-\d{2}'
multiline.negate: true
multiline.match: after
output.logstash:
hosts: ["logstash:5044"]
这里有个坑,我必须要说。多行日志的处理,比如Java异常栈,如果不做multiline配置,一条异常会被拆成几十条日志。我曾经因为这个原因,导致知识图谱里一个故障事件被拆成了几十个孤立节点。嗯,后来我学乖了,每次上线前都会检查多行日志的处理逻辑。
Logstash这边,我一般会做三件事:
- 字段提取:用grok正则把时间戳、日志级别、类名、消息体拆出来
- 时间标准化:统一转成ISO 8601格式,方便后续时序分析
- 敏感信息脱敏:IP、用户名、密码等字段做哈希或掩码处理
# logstash.conf 片段
filter {
grok {
match => { "message" => "%{TIMESTAMP_ISO8601:timestamp} %{LOGLEVEL:level} %{JAVACLASS:class} - %{GREEDYDATA:msg}" }
}
date {
match => ["timestamp", "ISO8601"]
target => "@timestamp"
}
mutate {
gsub => ["msg", "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b", "IP_MASKED"]
}
}
4.3 监控指标采集:时序数据的处理艺术
监控指标相对规整,但数据量巨大。我一般用Prometheus做采集,然后通过Prometheus Remote Write写入Kafka,再消费到知识图谱的预处理管道里。
为什么中间要加一层Kafka?说白了,就是为了解耦。Prometheus本身不适合做长期存储,而且知识图谱的构建速度跟不上指标采集的速度。加个消息队列,两边都能按自己的节奏跑。
指标数据的预处理,我重点关注三个维度:
- 缺失值处理:对于短时间缺失(比如5分钟内),用线性插值填充;长时间缺失直接标记为「未知」
- 异常值过滤:比如CPU使用率突然跳到200%,这明显是采集错误,直接丢弃
- 降采样:原始数据是秒级的,但知识图谱里一般只需要分钟级粒度。我习惯用平均值+最大值+最小值三个值来代表一个时间窗口
# 降采样示例:Python伪代码
def downsample(series, window='1min'):
return series.resample(window).agg({
'value': ['mean', 'max', 'min']
})
4.4 工单数据:非结构化文本的炼金术
工单数据是最「值钱」的,也是最难处理的。因为它包含了大量运维人员的经验判断、排查思路、解决方案。但这些信息都藏在自然语言里。
我处理工单数据的流程大致是这样的:
- 文本清洗:去掉HTML标签、特殊符号、多余的空格和换行
- 实体识别:用NER模型提取主机名、IP、应用名、错误码等关键实体
- 关系抽取:识别「A导致B」「A依赖B」「A的解决方案是B」这类关系
- 标准化:把同义词统一,比如「宕机」「挂掉」「不可用」都映射到「故障」
举个例子,一条工单描述是:「10.0.1.5这台机器挂了,导致支付服务不可用,重启后恢复。」
经过预处理后,会变成结构化的三元组:
(主机:10.0.1.5) - [导致] -> (服务:支付服务)
(服务:支付服务) - [状态] -> (故障)
(操作:重启) - [解决] -> (故障:支付服务不可用)
你看,这样图谱就建起来了。以后再有类似问题,大模型就能直接推荐「重启」这个操作。
核心思路:工单数据预处理的目标,就是把「人读的文本」变成「机器能理解的结构」。这一步做得好,知识图谱的质量就有保障。
4.5 CMDB数据:关系图谱的骨架
CMDB数据是知识图谱的「骨架」。它定义了各个运维实体之间的关系:这个应用部署在哪台主机上?这个数据库被哪个服务依赖?这些关系构成了图谱的基本拓扑。
但CMDB数据有个老大难问题——数据质量。我见过最夸张的情况,一个中型公司的CMDB里,有30%的资产信息是过期的。
我的处理策略是:
- 数据校验:用实际采集的指标数据去验证CMDB里的信息。比如CMDB说某台主机在运行,但监控系统已经收不到它的心跳了,那就标记为「待确认」
- 增量更新:不要全量替换,而是用变更日志做增量合并。这样即使某次采集出问题,也不会把整个图谱搞乱
- 版本管理:每次CMDB数据变更都保留历史版本。万一新数据有问题,可以快速回滚
# CMDB数据校验伪代码
def validate_cmdb(host_id, cmdb_info, monitor_data):
if monitor_data.get(host_id, {}).get('alive') == False:
cmdb_info['status'] = '疑似下线'
cmdb_info['confidence'] = 0.7
return cmdb_info
4.6 数据预处理流水线:把一切串起来
好了,四种数据源都讲完了。但实际工程里,你不能一个一个手动处理。你需要一条自动化的数据预处理流水线。
下面这张图是我常用的流水线架构:
这条流水线跑起来之后,基本就不用人工干预了。每天定时检查一下数据质量报告就行。我个人习惯在流水线末尾加一个「数据质量评分」的环节,低于80分的批次自动告警,人工介入排查。
好了,数据采集和预处理这部分就聊到这儿。说白了,就是四个字——「脏活累活」。但正是这些脏活累活,决定了你的知识图谱到底能不能用、好不好用。下一节我们会把这些预处理好的数据,真正喂给大模型去构建知识图谱。嗯,到时候你就知道,前面这些功夫没白花。