PLFM_RADAR:从进程、端口到配置,自动绘制程序资产与调用依赖

发布时间:2026/11/2 10:39:03
PLFM_RADAR:从进程、端口到配置,自动绘制程序资产与调用依赖

1. 谁在用"平台雷达":没有可视化大屏,也能看清平台全貌

先说一个我在多个项目里反复遇到的场景。你接手一套部署已久的老平台,文档过期、人员离职、代码结构混乱,运维侧只告诉你"这套系统挺重要的,别动坏了"。这时候你面临三个最原始的问题:这台平台上到底跑了哪些程序?这些程序各自在跟什么打交道?如果某个组件挂了,波及面有多广?

按传统做法,你得登录服务器逐一排查,翻配置文件、看进程列表、扫端口、查数据库连接,运气好一小时能理清楚,运气不好一天都在追着信息碎片跑。而且更麻烦的是,排查结论往往只存在于你个人脑子里,换个人来,同样的排查又得重新来一遍。

我做的 PLFM_RADAR,本质上就是这个场景的自动化答案。它是一套偏运维侧的程序资产测绘与分析工具,负责定期摸清平台上运行的程序清单、程序之间的调用关系、对外端口、依赖组件,以及这些依赖里有没有"应更新而未更新"的隐患点。数据沉淀后,以结构化报告的形式输出,让"平台全貌"不再依赖某个人的大脑,而是变成一份随时可查、持续更新的档案。

这名字没什么玄机:PLFM 就是 platform,RADAR 是雷达。合起来就是一句话——像雷达扫目标一样,周期性扫描整个平台,把看不见的程序关系网绘制出来。

我写这篇文章,不是来推广什么商业产品,因为这套东西就是我自己基于开源组件攒出来的。我更想分享的是:设计这套东西时踩过的坑、总结出的取舍逻辑、以及实际部署过程中的参数调整经验。如果你也在维护一套复杂平台,或者正在被"到底有哪些程序在跑、它们怎么互相关联"这个问题困扰,这篇内容应该能给你一套可以直接落地的思路。

1.1 这套雷达到底解决了什么问题

举一个真实案例。D 公司有一套内部业务中台,整整 62 个微服务跑在 Kubernetes 集群里,还有 11 个传统单体应用跑在若干虚拟机上。之前的维护方式很简单粗暴:谁出的问题谁去看,看得多了每个人脑子里都有一张不完全一样的"地图"。

后来做一次跨部门的数据链路整改,要求梳理出"所有涉及订单数据的程序节点",结果整整花了两周。靠的是什么?靠人肉翻代码、翻日志、翻配置中心,最后还漏了一个定时任务,差点造成数据重复推送。

PLFM_RADAR 上线后,这个场景变成了一个固定动作:每个月生成一份依赖分析报告,搜索"订单"关键词,所有涉及订单数据读写的程序节点、调用方向、数据流向全部以表格形式输出。整个过程从两周缩短到十分钟,准确率还更高——因为它是基于程序运行的动态行为采集的,不是靠人回忆的。

另一个典型场景是变更影响面评估。每次平台升级某个底层组件之前,你需要知道"这个组件变化会影响谁"。传统做法是问各个团队负责人,但总有不靠谱的时候。用 PLFM_RADAR 沉淀的调用关系数据,直接拉出该组件下游的所有消费者列表,谁受影响一目了然。

1.2 为什么不用现成的监控系统替代

你可能会问:我们已经有 Prometheus、Grafana、SkyWalking 这一堆监控工具了,为什么还要做一个 PLFM_RADAR?

这个问题我在实战中确实被问过很多次。我的回答是:监控关注的是"活着没活着",PLFM_RADAR 关注的是"谁是谁、谁在跟谁说话"。

Prometheus 告诉你某服务的 CPU 到了 90%,这是健康状态信号;但 Prometheus 不会告诉你"这个服务是订单模块在调用,它挂了会连带影响支付回调",这是资产与依赖关系信息。SkyWalking 能展示调用链,但那是流量视角的链路追踪,不是资产视角的依赖关系沉淀。

打个比方,监控系统是体检仪,告诉你各项指标正不正常;PLFM_RADAR 是家族族谱管理员,记录谁是谁家的、谁跟谁是亲戚关系,平时你可能不看族谱,但要排继承顺序了、要办家族聚会了,族谱的价值才体现出来。

所以这套系统真正的定位,不是替代监控,而是补上监控工具在"资产管理"和"依赖分析"维度的空缺。

2. 底层数据从哪来:进程信息、网络连接与配置文件的三角验证

聊完了价值,来聊点实在的:雷达扫描的数据,具体从哪里挖?这是我这套方案里最核心的设计决策,也是跟很多商业 CMDB 工具思路不同的地方。

商业 CMDB 往往依赖人工录入或 API 同步,数据准不准取决于录入勤不勤。我设计的 PLFM_RADAR 完全走自动采集路线,而且用了三个独立数据源做交叉验证,保证信息的可靠性。

2.1 第一路数据:进程与二进制文件信息

最基础的数据来自操作系统层。Linux 环境下,我会通过标准系统接口枚举当前所有运行中的进程,抓取进程 PID、PPID(父进程 ID)、启动命令、可执行文件路径、运行用户、启动时间这些基础字段。

但只抓进程列表意义不大,关键是要识别出"这是哪个程序"。我的做法是结合两类信息做判定:

  • 可执行文件的元数据:包括文件哈希、文件大小、编译时间(如果 ELF 头里有记录)、所属软件包(通过 rpm 或 dpkg 查询)。
  • 启动参数中的特征:比如 java 进程的启动参数里往往带有-Dapp.name=order-service或者-jar order-service.jar,Python 进程可能是python /opt/app/worker/main.py。

有了这两类信息,一台服务器上"跑着哪些程序"这个问题的答案就能基本定型。这不是靠猜,而是每个字段都能在生产环境验证。

我见过很多人做资产盘点只到"这台机器上有什么进程"就停了,这个粒度远远不够。因为同一个程序可能在不同机器上有不同路径、不同参数,你需要的是"程序逻辑实体",而不是"进程实例"。打个比方,MySQL 在十台机器上各跑一个实例,但你盘点资产的时候不应该记十次"MySQL",而应该识别出"这是一个 MySQL 集群,共 10 个节点"。

所以 PLFM_RADAR 在进程信息采集后,还有一个聚类归一化步骤:把二进制文件哈希一致、或可执行路径规则一致的进程,归并到同一个"程序实体"下。这个步骤当年写的时候觉得多此一举,后来在数据呈现阶段发现能省下海量的阅读成本。

2.2 第二路数据:网络连接与监听端口

进程信息能告诉你"平台上有什么",却回答不了"谁跟谁在通信"。所以第二路数据就是网络连接关系。

采集方式是利用系统内核暴露的连接表接口,周期性获取 TCP/UDP 监听端口和已建立的连接。这里最关键的信息是四元组:本地 IP、本地端口、远端 IP、远端端口。再配合进程 PID,就能反查出"这个连接属于哪个程序"。

这一步做出来的数据,就是整个调用关系图的基础原材料。

实际操作中,监听端口抓取非常顺利,已建立的连接也还行,真正的难点在于UDP 连接的采集。UDP 是无连接的,内核的连接表里通常只记录监听端点,不记录通信对端,所以很多 UDP 流量(比如 DNS 查询、NTP 同步、部分日志传输协议)会直接穿透雷达的视野。这是天然盲区,不是工具能完全解决的。

我最终的取舍是:TCP 关系作为主要分析依据,UDP 只记录监听端口,不做通信关系推断。这个取舍在准确性和完整性之间取得了平衡,也避免了大量误报。

2.3 第三路数据:配置文件特征的深度解析

进程和端口信息能回答"有什么、跟谁连",但回答不了"这个程序依赖了哪些组件、配置了什么外部资源"。这一步需要翻配置文件。

PLFM_RADAR 的配置解析设计思路:以进程的可执行文件路径和启动参数为线索,回溯程序的工作目录和常见配置目录,读取其中的 YAML、JSON、properties、conf、ini 等格式的配置文件。解析出几类关键信息:

  • 数据源配置(数据库连接串、消息队列地址、缓存服务地址)
  • 服务注册中心地址
  • 对外暴露的 HTTP 服务端口与路由前缀
  • 环境标识(dev、test、prod 等)

一开始我把这部分设计得过于激进,恨不得把配置文件的每个字段都解析出来存到库里。后来发现过了两个月,配置文件里大量字段是静态的、无分析价值的,反而让每次查数据都像在翻垃圾堆。于是收敛为"只抓与依赖关系相关的字段",数据简洁了,分析效率反而提升不少。

这三路数据采集完成后,PLFM_RADAR 的基础数据库就成型了。接下来一个重要动作是"交叉验证":进程列表里有程序 A 监听 8080 端口,网络连接表里也记录了 8080 的监听记录,配置文件里又出现了server.port=8080的字段,三个数据源互相印证,这条数据的置信度就会被标记为"高"。

如果只有端口表有记录、进程表却没有对应 PID,那大概率是内核 socket 未绑定进程的瞬时状态,或者权限不足导致的读取遗漏,这类数据会被标记为"待确认"。这个置信度机制帮我挡住了大量脏数据。

3. 动态调用关系怎么绘制:从连接四元组到业务链路的层层递进

有了基础数据之后,下一步就是把"谁能连谁"升级为"谁在调谁"。这一步是 PLFM_RADAR 从纯资产盘点工具向分析平台跃迁的关键节点。

3.1 以端口为锚点的服务身份识别

第一步是把端口翻译成服务名。比如你看到 10.0.3.11:3306,光靠看根本不知道那是 MySQL,哪怕知道也不清楚是哪个业务库的实例。

我的做法是建立一张"端口-服务"映射表。这张表不能全靠人工维护,需要通过两种方式自动生成:

  • 常见组件的默认端口启发式识别:看到 3306 就先打上 MySQL 候选标签,看到 6379 打上 Redis 候选标签,再结合配置文件里的连接串信息确认。
  • 历史数据的统计学习:如果一个端口长期被同一进程监听,且该进程的启动参数稳定,就把这次识别结果固话下来,下次直接映射。

有了映射表,网络连接记录就能翻译成有意义的语句:程序 A 的 IP:Port A1 连接到 程序 B 的 IP:Port B1,翻译过来就是"程序 A 调用了程序 B 的某端口对应服务"。

3.2 聚合与去噪:去掉心跳、日志传输这类无效关系

直接拿连接记录画依赖图,第一版跑出来的结果会让人崩溃。因为生产环境里存在大量"技术性连接":

  • 心跳检测连接(每几秒一次,短连接,大量重复)
  • 日志采集 agent 到日志中心的连接
  • 监控 agent 到监控服务端的连接
  • 定时任务的批量数据连接

这些连接从底层视角看确实存在,但从业务依赖的视角看都是噪音。PLFM_RADAR 的去噪逻辑分三层:

第一层,基于频率过滤。统计单位时间内两个程序实体之间的连接次数和连接持续时间,如果连接频率恒定、且从不传输实际业务数据(通过端口特征判断),就标记为"疑似心跳/监控连接"。

第二层,基于黑白名单。这是我强烈建议你从一开始就维护的配置项。把日志采集、监控采集这类已知的基础设施关系直接加入黑名单,库里的数据瞬间清爽一半。

第三层,基于方向语义。依赖关系记录必须区分"主动发起方"和"被动接收方"。比如平台内部程序访问 MySQL,调用方向一定是"程序 → MySQL",而不是反向。这个语义直接决定了后续影响面分析的正确性。

这套三层去噪逻辑跑完之后,依赖图的可读性大幅度提升,从原来一屏看不清线的毛线团,变成了有清晰层次和方向的结构图。

3.3 配置中心与注册中心的信息补全:让动态关系更接近真实

纯靠网络连接拼出来的调用关系,有一个致命缺陷:它只能反映"当前正在通信"的关系,反映不了"配置了但此刻没流量"的关系。

举个例子,某程序配置了三个外部服务地址做负载均衡,但只有一个服务在持续响应流量,另外两个只是备用节点。如果只看网络连接,你会漏掉两个备用节点,导致后续做高可用评估时出现严重误判。

所以 PLFM_RADAR 增加了一个配置补全通道:从配置文件里解析出的数据源地址、服务地址列表、路由配置等,都会被当作"潜在依赖关系"写入备选表。这些备选关系虽然没有实时流量佐证,一旦发生故障切换,它们随时可能变成实际依赖。

这样一来,最终呈现在报告里的依赖关系就分了两类:

  • 实测依赖:有网络连接数据支撑,置信度高。
  • 配置依赖:来自配置解析,尚未观察到实际流量,置信度中等。

两类数据分开标注,不会混在一起误导判断。这个设计是我在实际用的时候发现的刚需——很多工具把所有关系平铺在一起,反而让人分不清哪些是真实发生的、哪些只是配置层面的可能性。

4. 预警机制怎么设计才不变成"狼来了":三级分类与基线漂移

雷达如果只做测绘,价值最多发挥一半。另一半价值在于持续监控和预警:当你已知平台基线,下次扫描发现异常变动时,系统能第一时间发出警报。但这个预警机制的设计,比想象中更考验耐心。

4.1 预警规则的分类体系

我最终沉淀下来的规则体系,按严重程度分为三级:

一级规则(红色预警):高危变更类。包括新程序实体出现且不在白名单内、某个程序监听了新的高危端口、核心数据库连接用户发生变化、平台程序的身份标识(如文件哈希)发生变更。这类事件意味着平台上可能出现了未授权的代码或配置,需要立即介入核查。

二级规则(橙色预警):异常关系类。包括程序 A 访问了历史上从未访问过的程序 B、某个程序的外部依赖数量急剧增多、监听端口与进程数量不成比例地膨胀。这类事件指向"平台正在发生肉眼不可见的变化",不一定是坏事,但值得关注。

三级规则(黄色预警):基线漂移类。包括配置文件中新增了未备注的数据源地址、某个程序的启动参数相比历史基线发生了变化、依赖组件的版本号与基线不一致。这类变更单看可能无害,但累积起来往往就是事故的前兆。

4.2 控制误报的核心手段:基线学习期

预警系统最大的敌人不是漏报,而是误报。误报多了,团队的警惕性会被消磨,最终变得形同虚设。

我的应对方案是:PLFM_RADAR 部署后不立即启用预警,而是先进入基线学习期,默认持续 14 天。这期间系统只采集、不报警,把所有数据沉淀为"平台常态基线"。

14 天之后,系统开始对比新采集数据与基线数据,只有偏离基线达到一定阈值的才会触发预警。而且我设计了"每日摘要模式"和"实时告警模式"两种输出:日常跑批只发日报摘要,只有命中一级规则时才实时推送。

实际操作中我发现,基线学习期不能太短。低于 7 天的话,很多周级周期任务还没跑过一轮,基线里缺少这些数据,会导致后续误报飙升。所以建议至少覆盖一个完整业务周期,比如业务上有月结的概念,基线学习期至少要 30 天,否则"每月十号凌晨出现的批处理任务"会在每次出现时都被当成新变化报警。

4.3 预警输出的形态选择

PLFM_RADAR 的预警输出我设计了三种形态:

第一是控制台列表,适合主动查看;第二是企业微信/钉钉机器人推送,只推一级和二级规则,避免信息轰炸;第三是每周汇总邮件,面向管理视角,展示趋势性变化。

这里分享一个经验:预警推送的收件人范围要严格控制。一开始我把所有规则推送给所有相关人员,结果三天后大家就开始无视消息了。后来收敛为"一级规则推给运维负责人和值班人员,二级规则只推给组长,三级规则只进周报",反而处理效率提升明显。

预警的本质不是让所有人知道所有事,而是让最该处理的人第一时间知道最该处理的事。

5. 一次真实部署:从裸机环境到平稳运行的完整过程

讲了这么多设计思路,来记录一次完整的真实部署过程。这样你能更直观地看到每一步大概耗时多久、有哪些坑。我选的场景是一套混合部署平台:12 台虚拟机跑传统应用,1 套 Kubernetes 集群跑微服务。

5.1 部署前的基础环境准备

PLFM_RADAR 本身是 Python 写的,数据存储用 SQLite 起步,后续数据量大了才迁移到 PostgreSQL。部署它不需要重型依赖,一台 4 核 8G 的虚拟机就能跑到很舒服。

部署前的关键是权限规划。雷达采集程序需要读取系统进程信息、监听端口、网络连接信息。这些读取操作在 Linux 下需要CAP_NET_ADMIN和CAP_SYS_PTRACE权限,或者直接用 root 运行采集器。我没有用 root,而是创建了专用账号radar,然后通过 sudo 规则只授权它执行采集脚本,再通过内核审计接口校验采集结果。

这里踩过一个坑:如果不授权读取连接信息,采集器能跑起来,但网络连接表导出的是空数据,导致调用关系图直接缺半边。所以部署后的第一件事,就是验证"连接信息采集是否成功"。

5.2 采集器部署与配置

采集器我拆分成了三个独立模块,分别对应前面说的三路数据。每个模块独立部署,通过配置文件指定目标服务器列表。部署方式不复杂,直接用 Ansible 推送即可。

配置文件的简化示例:

[targets] server1 192.168.1.10 server2 192.168.1.11 k8s-node-1 192.168.1.21 k8s-node-2 192.168.1.22 [scan_interval] process_scan = 300 net_scan = 60 config_scan = 3600

这几个扫描间隔参数是我调出来的经验值:进程信息和配置文件的变更频率低,五分钟甚至一小时一次足够;网络连接是动态数据,六十秒一次能比较好地捕捉连接变化。

但要强调一个原则:扫描间隔不是越短越好。扫描会产生系统调用开销,频率太高在服务器繁忙时段影响业务。我实测 30 秒间隔会把 CPU 占用拉高到 5% 左右,60 秒间隔只有 1% 上下,所以最终选了 60 秒。

存储端初期用的 SQLite,单日数据量在 200MB 以内时体验很好。但跑了一周后发现连接表的增长远比预想快,查询开始变慢。于是迁移到 PostgreSQL,并建立了分区索引,按天分表存储原始连接数据,按周聚合存储分析结果。

5.3 部署期间遇到的三个意外

第一个意外:Kubernetes 集群里,同一个 Pod 的 IP 是漂移的,每次重建都会换地址。如果沿用传统主机资产的"IP+端口"标识方式,每次 Pod 重建都会制造大量虚假变更记录。

解决方案是在采集时优先识别 Pod 的 Owner(通过环境变量和标签注入),把身份标识从"IP"升级为"应用名",IP 只作为临时属性。这个改动让 Kubernetes 环境的数据质量提升了一个台阶。

第二个意外:部分传统应用使用了动态端口分配,每次重启会监听不同的端口,导致端口到服务的映射关系不断失效。这类应用没办法用静态映射,我最终为它们引入了"启动参数识别"方案:每次进程启动后,通过启动参数中的特征反查服务名,再关联监听端口。

第三个意外:部分服务器的系统时间和 NTP 时钟源不同步,导致连接记录的采集时间错位。后续做时间线分析时数据对不上。最后在采集端统一加了 NTP 时间同步校验,每次上报数据时附带本机时钟偏移量,分析端按偏移修正后再入库。

5.4 首轮报告的输出与人工校准

采集和入库稳定后,PLFM_RADAR 生成了第一份平台全景报告。报告里自动识别出 45 个程序实体,端口 130 多个,初步调用关系 200 多条。

这个数字跟实际平台情况相比,约 20% 的关系因为启动参数缺失或配置文件解析失败没有自动识别出来。我没有强行依赖自动化,而是组织各应用负责人花了一个下午做人工校准:对系统生成的实体清单,逐个确认真实业务名、确认关键的调用关系。

这次人工校准的意义重大。一方面是把自动识别不出来的那 20% 补全了;另一方面,负责人核对过程中纠正了 3 条之前一直理解错误的关系,这是纯自动化很难发现的。

校准结果回填到 PLFM_RADAR 后,系统就进入持续服役状态。

6. 报告怎么用:从"知道有什么"到"分析平台健康度"

报告生成不是终点,用起来才是。PLFM_RADAR 的报告输出分成三个层级,我按实际使用频率排列。

6.1 面向日常运维:变更检查清单

日常运维最常看的是一份增量变化清单——相比上次基线,平台在这一周期内新增、删除或修改了哪些程序、端口、依赖关系。

这份清单在每个部署周期前跑一遍,效果极其明显。之前升级某个应用之前,都得先人工确认"这个应用改了之后会不会影响别的程序",现在直接看雷达生成的变更清单,哪些程序会受影响一目了然。整个变更审批流程从小时级缩短到分钟级。

实际跑了一年后,运维团队还总结出一个规律:变更清单能提前几小时预警问题应用。有几次平台在凌晨出现故障,回查雷达数据时发现故障应用其实在 24 小时前就已经出现了异常的依赖变化,但当时没有人在意。这个发现让团队把"异常变更预警"从辅助功能提升到了核心功能。

6.2 面向架构治理:依赖合规性检查

第二个使用场景是架构规范性检查。很多平台都制定过架构规范,比如"业务应用不得直连数据库,必须通过数据服务层访问""生产环境禁止开放非标准端口""禁止跨环境调用"等,但执行情况全靠自觉。

PLFM_RADAR 可以把规范规则系统化:

  • 规则一:数据库端口(3306/5432/6379)只允许数据服务层的特定程序连接,其他程序连接一律算违规。
  • 规则二:监听非白名单端口,且没有备案标记的,一律算违规。
  • 规则三:不同网络区域的程序之间产生调用关系,必须走网关代理,直连一律算违规。

规则跑批之后,每次都会产出一份违规清单。这份清单是架构治理的抓手,不用去跟业务方争"你们是不是直连了数据库"——直接拿出记录,清清楚楚。

6.3 面向容量与风险的长期分析

第三个使用场景是趋势分析。如果把雷达数据按周、按月聚合,能看到一些很有意思的趋势:

  • 平台程序实体的增长曲线:是稳步增长还是突然膨胀;
  • 依赖关系的复杂度趋势:每新增一个程序,平均会增加多少条依赖关系;
  • 端口使用度分布:哪些端口范围已经接近使用上限。

这些趋势数据对容量规划很有价值。比如我发现某个平台的 IP 和端口资源消耗速度如果不加控制,八个月后就会触顶,提前知道了就能在规划新项目时把资源申请提上日程。这类"从数据看到未来问题"的能力,是任何单次排查都无法提供的。

7. 运行一年后的沉淀:值得改进的部分和正在推进的方向

最后说点坦诚的话。PLFM_RADAR 到目前为止运行了一年多,好处不用多提,我更想聊聊暴露出来的不足。

第一,配置文件解析的脆弱性。不同团队写配置文件的风格差异太大,有的喜欢把数据源写在环境变量里,有的放在独立的配置中心,配置文件解析覆盖率大约只有 80%,剩下的需要人工补全。后续想引入语义解析模型,先对配置文件做语法树分析,再提取依赖信息。

第二,容器化环境的支持还偏浅。目前对 Kubernetes 环境的识别停留在 Pod 和 Deployment 级别,StatefulSet、DaemonSet、Service Mesh(特别是 Istio 注入后的流量拓扑)还没有完全覆盖。这部分代码重构比较费力,但目标平台往容器化迁移的趋势是不可逆的,必须补上。

第三,数据保留策略。原始连接数据如果全部保存,一年下来存储量不小。目前的策略是原始数据保留 30 天,聚合数据保留 13 个月,超过 13 个月的按季度再聚合为趋势数据。这个策略基本够用,但如果你要回溯"一年前的某一天到底发生过什么连接",数据已经不在了。建议实际部署时根据监管要求提前确认清楚。

第四,多平台适配。目前采集脚本适配了 CentOS 7、Ubuntu 18.04/20.04 和部分 macOS 环境,Windows Server 平台还没有适配。如果平台里有 Windows 节点,雷达目前是盲区,只能靠其他工具补位。Windows 环境的进程和端口信息采集方式与 Linux 差异很大,不是简单移植就能解决的,需要专门开发。

关于后续的方向,我在重点推进两件事。一是把配置中心和注册中心的 API 对接做扎实——既然 Spring Cloud 的注册中心里已经存了完整的服务注册表,直接拉取比每次扫描后推理要高效得多,识别精度也能大幅提升。二是尝试构建"依赖关系画像":连续观察一个程序三个月后,系统自动生成它的特征画像,今后每次扫描如果画像出现结构性变化,就提示该程序的行为模式可能发生了重大调整。

雷达这种工具的价值是慢慢释放的。刚部署的几天可能觉得不过是一堆表格数据,等数据积累到一个月、三个月、半年之后,你回头看平台的样子,会庆幸当初做了这件事。平台在变、程序在变、依赖在变,唯一能让你持续看清真相的办法,就是长期保持观察——这正是雷达该干的事。