网络拓扑图绘制与自动化生成实战:物理逻辑分离、LLDP发现与排障
简介网络拓扑图资源包是一套用于绘制与管理网络拓扑的Web项目源码面向网络管理员、IT运维人员及Java Web开发者用于呈现设备、连接和数据流的物理或逻辑布局。包内包含拓扑图核心绘制逻辑、前端页面及PNG/GIF图标资源附带XML配置和数据库文件用于存储拓扑结构可满足物理、逻辑、层次和混合拓扑图的绘制需求也便于二次开发与自定义图标。压缩包共507个文件大小仅2.65MB除285个SVN元数据文件外还有XML配置、JS/JSP页面、CSS样式、PNG/GIF图片和数据库文件等结构清晰适合导入IDE运行。目前已有1083人学习/下载适用于想深入理解网络拓扑绘制原理的技术人员。无论是规划网络、故障排查还是安全监控都可基于这份源码快速搭建可视化平台提升网络运维效率。1. 网络拓扑图为什么半夜被叫起来时最缺的就是这一张图凌晨两点被电话叫醒核心交换机连业务区的端口突发丢包。你打开电脑先登汇聚再查接入一层层敲 show 命令半小时后才把故障范围圈出来。如果桌上有一张准确到端口和 VLAN 的网络拓扑图这三十分钟可以压成三分钟。网络拓扑图就是把盲人摸象时脑子里转的东西固定成一张图设备、链路、IP 子网、路由关系都摊开在眼前。它不解决协议问题但能加快定位速度能防止改错设备能让你把一个陌生网络快速接手。这篇文章适合需要自己画图或维护网络图的运维和基础设施工程师我会把画图选型、自动生成和排障用法一起讲透。2. 先分清要画哪种拓扑图物理、逻辑与VLAN视图决定工具和数据结构很多人第一次画网络拓扑图抓起 Visio 或 draw.io 就按机房照片画画完发现排障时根本帮不上忙。问题不是画得不好而是没分清画的是物理拓扑还是逻辑拓扑。物理拓扑回答“线插在哪个口”逻辑拓扑回答“数据走哪条路”。两者数据来源不同更新节奏也不同。我一般会在同一份维护文档里分开维护不强行塞进一张图。一张图塞进所有信息之后画图的人看着爽看图的人想哭。2.1 物理拓扑图链路、端口和机房位置是唯一真相物理拓扑图最基本的元素是设备和设备之间的实线。每条线上要标两端端口、线缆编号、带宽。数据中心最常见的物理链路图是把核心到汇聚、汇聚到接入的光纤跳线画清楚再标注光模块型号。这看起来琐碎却是割接和查光衰时的救命信息。物理拓扑图的数据来源不是脑子和厂家宣传图而是设备实际学习到的邻居关系。最靠谱的来源是 LLDP以及 Cisco 私有协议 CDP。在交换机上可以直接看到本端端口和对端端口的一一对应关系$ ssh -o ConnectTimeout3 -o StrictHostKeyCheckingno admincore01 show lldp neighbors Local Intf Neighbor Neighbor Intf Gi1/0/47 dist01 Gi1/0/23 Gi1/0/48 dist01 Gi1/0/24这一行的意思很直接core01 的 Gi1/0/47 插着一条线另一端是 dist01 的 Gi1/0/23。我按设备逐台执行一遍就凑齐了二层物理链路关系。这里有个关键限制show lldp neighbors 只显示接口 up 的邻居down 的备用链路不会出现在表里。要画全还需要再拉一次接口状态表把 up 和 down 都列出来否则图上会漏掉备用链路。我在实际维护中会把这两份数据合并成一份 links 清单再做后续画图。物理拓扑图和逻辑拓扑图的维护应该分开用对比来理解最直接维度物理拓扑图逻辑拓扑图关注重点端口、线缆、设备位置子网、VLAN、路由协议主要数据来源LLDP/CDP、SNMP、机房线缆表路由表、VLAN 配置、ACL 策略典型工具draw.io、diagrams、NetBoxdiagrams、graphviz、NetBox更新节奏线缆或端口变更后立即更新配置或路由变更后立即更新物理图不关心 VLAN只关心一根线从哪里插到哪里。割接时让施工队按图插光纤拿物理图排 VLAN 不通看逻辑图。两种图共用同一套设备名但信息和数据来源不能混。2.2 逻辑拓扑图VLAN、三层网关和路由协议才是排障关键逻辑拓扑图要回答“为什么这栋楼能上网对面那栋楼不能”。图中不关心光模块只关心 VLAN、三层网关、路由邻居。我见过最典型的例子核心到汇聚的物理链路是通的trunk 里却没有放行 VLAN 10接入层 PC 拿得到地址就是出不了网关。物理图画不出这个问题逻辑图上把这条边标成 trunk 10, 20就能一眼看出来漏了哪个 VLAN。画逻辑拓扑图我一般按三步走。第一步在交换机上执行 show vlan brief拿到 VLAN 和对应端口列表第二步执行 show ip route提取直连网段和默认路由第三步执行 show ip ospf neighbor 或 show bgp summary把三层邻居关系抓全。然后把三层网关标注到对应交换机上比如 dist01 的 Vlanif10 是 10.10.10.1就直接把这个地址写进图里的节点备注。逻辑图同样不能贪多。核心思路是只画影响业务路径的元素安全域之间的 ACL 用带方向的箭头表示不画具体的五元组规则。如果想把安全策略画进去单独开一张图否则一张图里既有点线又有策略读起来很累。我见过一张三层设备、二层设备、VLAN、防火墙策略、专线全画在一起的图一百多个节点、两百多条线画的人很有成就感看的人完全不知道从哪读起。这里的顺序很重要先物理后逻辑。物理不通时逻辑图上的邻居关系全是残废的逻辑不通时物理图往往看着正常。我通常是先确认物理图上的链路状态再看逻辑图上的路由和 VLAN两层配合才不会被表象骗。2.3 画图前先定三个约定层级、命名和图例画图最怕每个人一套风格。同一个设备名有人写 core01有人写核心1同一个端口有人写 Gi有人写 Ethernet。图一旦要交接给别人这些差异就是灾难。我在团队里强制约定三件事。第一是层级。布局统一按上中下上为出口和核心中为汇聚下为接入服务器和专线放在右侧。这个方向不一定要最“好看”但必须全团队一致看久了肌肉记忆就形成了。第二是命名。设备名写 hostname不改写接口名用设备上 show 出来的完整形式比如 Gi1/0/1不缩写。VLAN 只写数字不写部门名。第三是图例。实线只画物理链路虚线只画逻辑关系红色标注故障或异常链路灰色标注未启用接口箭头一律表示数据流向不表示指挥关系。图例要写进模板文件每次新建画布从模板复制。提示这些约定要留在团队文档里并在代码生成拓扑图时通过参数实现。人工画图可以靠自觉脚本画图必须靠配置。3. 用代码批量生成网络拓扑图从Excel、NetBox到SVG的落地路径手工画图的最大问题是更新滞后。配置变更一次没记图就失真一次失真两次之后团队就不再信任它。我的习惯是让网络拓扑图从代码里长出来设备清单和链路关系是唯一数据源脚本负责画图。数据源更新图自动变不需要人反复点鼠标。3.1 用diagrams库画一张三层网络逻辑拓扑diagrams 是 Python 生态里比较适合画网络架构图的库它把机房常见的设备类型封装成节点用一条边表达连接关系生成 SVG 或 PNG。我常用它画网络逻辑拓扑因为能看出设备层级而不只是一堆孤立的点。from diagrams import Diagram, Cluster from diagrams.network.generic import Router, Switch, Server with Diagram(三层网络逻辑拓扑, filenamethree_tier, showFalse, directionLR): core Router(core01) with Cluster(汇聚层): dist1 Switch(dist01) dist2 Switch(dist02) with Cluster(接入层): acc1 Switch(acc01) acc2 Switch(acc02) core dist1 core dist2 dist1 acc1 dist2 acc2这段脚本做的事很直白with Diagram 是画布Cluster 是分组 生成一条有向边。filename 决定了输出文件前缀这里会生成 three_tier.pngshowFalse 适合在服务器上跑不会弹出预览窗口directionLR 让布局从左向右设备层级感更强。执行前需要 pip install diagrams并且系统里装了 graphviz。如果缺 graphviz脚本会报 ExecutableNotFound看到这个报错第一反应不是改代码而是装系统依赖。这个方案适合数十台设备以内的规模设备超过上百台时diagrams 的节点标签会显得拥挤我一般换 Graphviz。3.2 从NetBox导出的CSV批量生成拓扑pandas graphviz现实中设备清单通常来自 CMDB 或 NetBox导出来是表格。我不建议在这一步手工画直接让表格变成图。用 pandas 读取链路关系再用 graphviz 生成 SVG是一个低成本、可跑在 cron 里的方案。import pandas as pd from graphviz import Digraph df pd.read_csv(links.csv) df df.drop_duplicates(subset[src, dst, port]) g Digraph(auto_physical_topology) g.attr(rankdirLR, nodesep0.6) for _, r in df.iterrows(): g.node(r[src], labelr[src]) g.node(r[dst], labelr[dst]) g.edge(r[src], r[dst], labelr[port]) g.render(topology_from_csv, formatsvg, cleanupTrue)这里假设 links.csv 长这样src,dst,port core01,dist01,Gi1/0/47 core01,dist02,Gi1/0/48 dist01,acc01,Gi1/0/23 dist02,acc02,Gi1/0/24代码逻辑是先把重复链路去掉防止表格里有历史记录导致一条边画两次然后给每个节点设置名字用 Graphviz 的有向边连接节点并在边上标端口。rankdirLR 让图从左到右排列nodesep0.6 控制横向间距cleanupTrue 会在渲染后删掉中间生成的 dot 文件。和 diagrams 相比Graphviz 更适合表达“链路表变图”这种关系。因为链路表天然是边集合Graphviz 的自动布局能整理得比较像样。但要记住它只能画拓扑不会帮你判断设备类型所以输出的是纯粹的节点和边。设备形状、设备色块的区分需要在数据源里额外标记。注意如果 CSV 里设备名大小写不一致先统一成小写否则同一个设备会画成两个节点。这个坑我在自动生成第一版时踩过一度以为拓扑里多了几十台不存在的设备。3.3 接入CMDB数据流定时重画、git版本管理批量生成解决了“怎么画”还要解决“什么时候重画”。我的做法是把生成脚本挂到 cron每天凌晨从 CMDB 拉一次设备表重画拓扑图并把生成的 SVG 提交到 git 仓库。0 4 * * * cd /srv/topology python3 gen_topology.py git add -A git commit -m daily topology refresh from cmdb || echo topology generation failed /var/log/topology.log这句话拆开看有三层cd 进入工作目录保证脚本相对路径不漂移python3 gen_topology.py 执行生成git add -A 和 git commit 把当天图存进历史。只要 CMDB 数据正常每天早上都会有一张新图。如果脚本出错|| 后面的 echo 会把失败写进日志方便第二天排查。git 在这里不只是备份它给排障提供了后悔药。割接之后发现网络不对劲拿当天和昨天的拓扑图 diff新增或消失的链路一眼就能看出来。不要小看这一步回滚前能少打一半问号。4. 避坑我画网络拓扑图踩过的五个坑条条都能省你半天自动化能解决画图效率但画出来的图对不对最后还是取决于数据源和人的判断。下面这五条是我这些年最典型的翻车记录每一条背后都能省下半天排障时间。4.1 现象图上链路全绿实际机房已经在环路曾经有段时间我的物理拓扑图看着很漂亮所有链路都是绿色实线。直到一个接入段广播报文异常多排查才发现接入交换机到汇聚之间有两条物理链路同时转发而我的图上只画了一条主链路没画备用链路。原因很简单画图的时候只画了“正在用的”没画“已经插着但没转发”的线。解决物理图必须画出所有物理连接包括被生成树阻塞的端口。在边上标注 STP 角色区分根端口、指定端口、阻塞端口。定期拉生成树状态端口角色一变化就触发重画。这样图才不是“理想状态”而是“当前状态”。很多团队只画在用链路导致环路风险明明已经在图上出现过却被自动过滤掉了。4.2 现象端口名标成Gi0/1show run里却是Gi1/0/1有一次我按旧的命名习惯把端口写成 Gi0/1施工人员拿着图找不到端口回来问我是不是型号搞错了。实际交换机上写的是 Gi1/0/1。不同厂商甚至同一厂商不同系列接口命名规范都不一样人脑根本记不全。手工录入时用缩写几乎是必然发生的。解决所有端口名只从 LLDP 或 SNMP 抓不手工录入。脚本里维护一张接口归一化映射表比如统一转成 Gi1/0/1 这种完整形式。宁可让脚本多处理一步也不能让人在图上用缩写。设备型号越杂这一步越值得做成独立模块因为它不属于某个厂商属于全局规范。4.3 现象把VLAN和物理链路混在一张图没人看得懂我见过最夸张的一张图三层设备、二层设备、VLAN、防火墙策略、专线全画在一起图上一百多个节点、两百多条线。画的人很有成就感看的人完全不知道从哪读起。这张图最后变成摆设谁也不愿意打开它。解决拆图。物理链路一张VLAN 一张路由协议一张。每张图只允许出现同类元素跨图用同一个设备名串联。读图的人先从物理图看链路再从 VLAN 图看隔离需要三层路径时打开路由图。这样每张图的信息量都小维护成本也低团队才愿意持续更新。4.4 现象自动发现把防火墙误画成二层交换机用 LLDP 做自动发现时很多防火墙在二层模式下也会发 LLDP自动脚本看到它有邻居就直接归进交换机。但防火墙有安全策略流量方向和交换机完全不同把它当成交换机画进拓扑排障时会被严重误导。比如你以为防火墙两边是同一台交换机实际上策略方向已经截断了整条业务。解决设备类型表手工维护脚本只负责补充链路不负责猜设备角色。防火墙、负载均衡器这类设备标记成特殊设备在图上用单独形状并且不能被自动发现脚本覆盖。自动发现只能发现“连接”不能发现“角色”角色判断需要人提供一个可信的清单。4.5 现象画完一次之后一年没更新排障时反而误导运维里有一句很真实的话没有时效性的拓扑图比没有图更危险。图上标的是上一季度的链路你按照它去拔线可能把正在跑业务的链路拔了那就是事故。很多人觉得拓扑图画完就完事但网络每天都在变VLAN 改了、链路加了、设备撤了图不跟着变就是一张废纸。解决把生成脚本绑定到变更流程变更单关闭时自动对比新旧 edges把变化部分附在变更记录里。图上必须盖生成时间戳超过设定周期就自动标灰提醒看的人这图可能过期。这个方案看起来比手工维护多了一步实际做下来反而是最省心的因为更新变成了流程的自动产物。5. 拿图排障环路、丢包和变更回退怎么用拓扑图快速定位网络拓扑图不只是画给别人看的文档更是排障时的一把尺子。故障发生时我不会盲目登录所有设备而是先看图找到最短排查路径再带着问题登录设备验证。下面三个场景是我用得最多的操作。5.1 二层环路先从图上看STP阻塞口还在不在二层环路的典型症状是广播报文飙升、CPU 升高、丢包间歇性出现。排查的第一步不是登录设备看 CPU而是打开物理拓扑图看接入层到汇聚层之间有没有两条以上链路再看图上标注的 STP 阻塞口是否发生变化。然后登录交换机验证show spanning-tree blockedports这条命令列出的是当前被阻塞的端口。如果图上一个端口标的是阻塞命令输出里却没有它说明生成树刚刚重算环路风险已经形成。反过来也一样命令里列出的端口在图上看不到说明图漏画了一条线。部分设备不支持 blockedports 参数就退一步看 show spanning-tree 输出里端口角色为 disabled 的行。不论用哪种目的都是把图和现实做对照。我的习惯是把图上的端口角色和命令输出做成对照表每次重画都做一次校验。生成树状态是排障时最该标在图上的参数因为它是看不见的默认没人会去背。5.2 丢包定位把traceroute逐跳结果标到图上丢包排障最怕的是“中间链路看不见”。从源端一路 traceroute每一跳延迟和丢包率都不亮但又不确定是哪一个节点的问题。这时把结果按跳数拆出来再叠加到逻辑拓扑图上就能看到流量实际走了哪条路径。import re, sys for line in sys.stdin: line line.strip() m re.match(r\s*(\d)\s([\d.]), line) if m: hop, ip int(m.group(1)), m.group(2) print(fhop {hop}: {ip})这段脚本把 traceroute 输出里的跳数序号和 IP 抽出来按顺序排好。然后拿着这个顺序和图上期望路径对比。比如图上是 core01 到 dist01 再到 acc01实际多跳了一个 10.10.100.1说明流量拐到了别的地方。把跳数和延迟变化标在图上之后丢包范围能缩小到一段链路不用每台设备都登录一遍。traceroute 在有些网络环境里表现像玄学* 号出现得很频繁。要记住* 号表示那一跳没有回复探测包不代表一定丢包。很多设备默认不回应 traceroute 的探测包见到 * 别急着断言链路故障先对比多个源端的探测结果再下结论。5.3 变更回退的后悔药变更前拍图、变更后对图网络割接或者配置变更时我做的最有价值的一步不是去背命令而是在变更前把当前拓扑的 edges 清单拍下来。变更结束后再采集一次用脚本对比两张清单。def load_edges(path): edges set() for line in open(path): line line.strip() if line: edges.add(tuple(sorted(line.split(,)))) return edges old load_edges(edges_before.txt) new load_edges(edges_after.txt) print(新增链路:, new - old) print(消失链路:, old - new)这里用 set 是为了让边无序core01,dist01 和 dist01,core01 是同一条链路排序后比对结果一致。如果消失链路里出现了核心到汇聚的主干那这个变更大概率是失败的回滚命令可以直接根据差异链路去定位。如果新增链路和预期一致说明变更生效可以放心。这个脚本看起来很朴素但它是拓扑图和变更流程结合的精髓不是事后补文档而是变更决策的输入数据。我给自己的要求是动设备之前先让脚本把现状记录下来而不是凭记忆。6. 让拓扑图自己长出来用LLDP自动发现的最小闭环静态图即使定期重画仍然依赖 CMDB 数据。想再往前走一步就从设备本身去发现拓扑。最小闭环只需要一台跳板机和一份设备清单SSH 免密登录配好脚本就可以每天去抓邻居关系。for ip in $(cat devices.txt); do ssh -o ConnectTimeout3 -o BatchModeyes admin$ip show lldp neighbors lldp_$ip.txt done python3 parse_lldp.py lldp_*.txt | python3 gen_topology.py第一段循环逐台设备抓结果BatchModeyes 防止脚本挂在密码输入上第二段把抓到的文本解析成链路关系再丢给第3章的生成脚本拓扑图就自动长出来了。关键点是第一版必须人工核对一次让脚本认识现有的设备命名和端口格式否则一个型号差异就会让脚本产生一堆噪音。边界要清楚LLDP 只能看到接口 up 的端口down 的备用链路抓不到三层路由关系还要靠路由表补充单纯的 LLDP 闭环画不出 OSPF 邻居。所以这个方案适合耕二层物理拓扑不适合做完整路由视图需要更强的路由视图就要在上面叠加第5章说的路由表采集。最早我手动画三十二台设备的图画了两周刚画完就有一台接入设备换了型号图又废了。后来改成 LLDP 自动发现核心只是每天多跑一次脚本。我现在的习惯是画图先画数据流不画架构图墙上挂的图永远标注生成时间任何链路变化都要能从 git 看回退。这听起来朴素但真的能在半夜排障时少走弯路。希望帮到你。本文还有配套的精品资源点击获取