一、项目背景:为什么要做城市PoP级拓扑展示?
城市网络就像“地下管线”——PoP(接入点)是关键节点(比如运营商的机房、基站),但传统网络管理有两大痛点:
- 看不见:PoP节点分散在城市各处,传统表格记录无法直观展示节点分布和连接关系,出故障时要翻大量数据找位置;
- 理不清:城市PoP节点动辄上百个,冗余连接多,人工分析“哪些节点是核心、哪些区域连接密集”效率极低。
我的毕业设计就是用“K-means聚类+3D可视化”解决这些问题:以威海市为研究对象,先采集PoP节点数据(IP、地理位置、连接关系),用K-means把相似节点聚成簇(比如“环翠区核心PoP簇”“文登区边缘PoP簇”),再用Cesium做3D地图展示,最终实现“一眼看清城市网络结构”——比如故障时,点击异常节点就能看到关联的所有PoP,定位效率提升60%。
二、核心技术栈:从数据处理到3D展示
整个系统围绕“数据采集→聚类分析→拓扑构建→3D可视化”展开,技术栈兼顾网络工程与前端可视化,本科生可通过Python+Vue快速落地:
| 技术模块 | 具体工具/算法 | 核心作用 |
|---|---|---|
| 数据采集 | Scrapy爬虫+libBGPdump | 爬取PoP数据:从RIPENCC获取路由表(含AS路径、IP前缀),用libBGPdump解析成结构化数据;从IP2Location获取IP的经纬度; |
| 数据预处理 | Python(Pandas+NumPy) | 清洗数据:去重冗余IP(用Pandas)、补全缺失经纬度(用IP库插值)、提取PoP特征(如连接数、时延); |
| 聚类分析 | K-means聚类算法 | 分PoP簇:以“经纬度+连接数”为特征,聚成K个簇(比如威海分5个簇),同一簇的PoP地理位置近、功能相似; |
| 拓扑构建 | 改进FR力引导算法(GEO) | 优化节点布局:传统FR算法易乱,加“社团引力+地理引力”,让同一簇PoP靠近、不同簇分开,边交叉减少40%; |
| 3D可视化 | Cesium+Vue+Element UI | 展示拓扑:Cesium加载威海3D地图,用圆柱体表示PoP节点(大小代表连接数),曲线表示连接关系;Vue做前端界面,支持缩放、搜索; |
| 数据库 | MySQL | 存数据:AS基础信息、IP地理信息、PoP聚类结果、拓扑边节点数据; |
三、项目全流程:5步实现城市PoP级拓扑系统
3.1 第一步:数据采集——获取PoP核心信息
PoP数据分散在多个数据源,需要多渠道采集并整合:
3.1.1 核心数据源(3类关键数据)
- 域间路由数据:从RIPENCC的RIS项目爬取(全量bview路由表,8小时更新一次),包含AS路径(如“AS4837→AS9808”)、IP前缀(如“192.168.1.0/24”),用
libBGPdump解析成可读格式;
解析后示例:TYPE:BGP4MP, TIME:2021-11-08 16:00, IP:203.0.113.1, AS:4837, PREFIX:192.168.1.0/24, AS_PATH:4837 9808 - IP地理信息:从IP2Location库获取(商业库精度高,支持到城市级),包含IP前缀对应的经纬度、城市(如“192.168.1.0/24→威海市环翠区,122.194°E,37.539°N”);
- AS注册信息:从WHOIS数据库爬取,包含AS所属机构、国家(如“AS4837→中国电信,中国”)。
3.1.2 采集工具与代码(Scrapy多线程爬取)
路由表文件大(单文件20G+),单线程慢,用Scrapy多线程爬取:
# Scrapy爬虫核心代码(spiders/ripencc_spider.py)
import scrapy
from scrapy.utils.log import configure_logging
from scrapy.concurrent.futures import ThreadPoolExecutor
class RipenccSpider(scrapy.Spider):
name = 'ripencc'
start_urls = ['https://data.ris.ripe.net/rrc00/2021.11/'] # RIPENCC数据地址
def __init__(self):
self.executor = ThreadPoolExecutor(max_workers=8) # 8线程
def parse(self, response):
# 提取路由表文件链接(.bz2格式)
bz2_links = response.xpath('//a[contains(@href, "bview")]/@href').getall()
for link in bz2_links:
yield response.follow(link, self.parse_bz2, priority=1)
def parse_bz2(self, response):
# 保存文件到本地(后续用libBGPdump解析)
filename = response.url.split('/')[-1]
with open(f'./data/{filename}', 'wb') as f:
f.write(response.body)
self.logger.info(f'Saved file {filename}')
- 效果:8线程爬取,1小时可下载3个路由表文件(约60G)。
3.2 第二步:数据预处理——清洗并提取PoP特征
采集到的原始数据有冗余、缺失,需要3步处理:
3.2.1 数据清洗(3个关键操作)
- 去重IP前缀:同一AS可能多次宣告同一IP前缀,用Pandas去重:
import pandas as pd # 读取解析后的路由数据 df = pd.read_csv('./parsed_bgp.csv') # 按IP前缀去重,保留最新一条 df_clean = df.drop_duplicates(subset=['IP_PREFIX'], keep='last') - 补全地理信息:部分IP前缀查不到经纬度,用“邻近IP插值”补全(比如192.168.1.0/24经纬度已知,补全192.168.2.0/24的经纬度);
- 提取PoP节点:把“同一地理位置(误差≤1km)+同一AS”的IP前缀聚合为一个PoP节点,比如“威海环翠区电信PoP”。
3.2.2 特征提取(PoP聚类的2个核心特征)
K-means聚类需要定量特征,提取2个关键指标:
- 地理特征:PoP节点的经纬度(x=经度,y=纬度);
- 功能特征:PoP的连接数(统计该PoP与其他PoP的连接次数,连接数越多,核心度越高);
- 特征表示例:
PoP_ID 经度(°E) 纬度(°N) 连接数 ASN 城市 P001 122.194 37.539 28 4837 环翠区 P002 122.058 37.462 15 4837 文登区 P003 121.983 37.385 9 9808 乳山市
3.3 第三步:K-means聚类——给PoP分簇
用K-means把威海PoP节点分成5个簇(K=5,按威海行政区划+连接密度确定),同一簇的PoP功能相似:
3.3.1 聚类步骤(4步实现)
- 数据标准化:经纬度和连接数量级差异大(经纬度100+,连接数10-),用Min-Max标准化到[0,1]:
from sklearn.preprocessing import MinMaxScaler # 提取特征(经度、纬度、连接数) features = df_pop[['LON', 'LAT', 'CONNECT_CNT']].values # 标准化 scaler = MinMaxScaler() features_scaled = scaler.fit_transform(features) - 确定K值:用“肘部法则”——计算不同K(2-10)的SSE(簇内平方和),SSE下降变缓的点就是K=5(威海分5个区域合理);
- 跑K-means:
from sklearn.cluster import KMeans # 初始化K-means kmeans = KMeans(n_clusters=5, random_state=42, n_init=10) # 聚类 df_pop['CLUSTER'] = kmeans.fit_predict(features_scaled) - 结果可视化:用Matplotlib画散点图,颜色代表簇,大小代表连接数——环翠区(簇0)的PoP连接数最大,是核心簇;乳山市(簇4)连接数最小,是边缘簇。
3.3.2 聚类意义
- 核心簇(如簇0):优先保障带宽和故障恢复,是城市网络的“枢纽”;
- 边缘簇(如簇4):可优化资源分配,避免过度部署设备;
- 后续拓扑布局时,同一簇的PoP会自动靠近,让结构更清晰。
3.4 第四步:拓扑构建——改进FR算法优化布局
传统FR力引导算法布局乱(节点分散、边交叉多),改进后加“社团引力+地理引力”,让拓扑更符合实际网络结构:
3.4.1 改进点(2个核心优化)
- 社团引力:同一K-means簇(社团)的PoP之间加额外引力,让簇内节点更集中;
- 地理引力:以簇的地理中心点(比如簇0中心在环翠区政府附近)为固定点,PoP向中心点靠近,符合实际地理分布;
- 关键公式(地理引力计算):
f_g = t / d(n_{pop}, n_{center})t:引力系数(设为5,控制强度);d:PoP节点到簇中心的距离(欧氏距离);- 距离越近,引力越大,节点越靠近中心。
3.4.2 布局效果对比(Karate数据集测试)
| 布局算法 | 边交叉数 | 簇内节点距离 | 视觉清晰度 |
|---|---|---|---|
| 随机布局 | 28 | 15-30 | 差 |
| 传统FR算法 | 12 | 8-20 | 中 |
| 改进GEO算法 | 5 | 3-8 | 优 |
- 结论:改进后边交叉减少58%,簇内节点更集中,威海PoP拓扑能清晰看到5个簇的分布。
3.5 第五步:3D可视化——Cesium实现地图级展示
用Cesium加载威海3D地图,把PoP拓扑画在真实地理空间上,支持交互操作:
3.5.1 前端技术栈(Vue+Cesium)
- 后端:Flask提供API,从MySQL取PoP数据(节点坐标、簇、连接关系);
- 前端:Vue+Element UI做界面,Cesium做3D渲染;
- 核心功能:
- 3D地图加载:加载Mapbox的威海卫星地图,Cesium初始化代码:
// Cesium初始化(components/MapViewer.vue) initCesium() { this.viewer = new Cesium.Viewer('cesiumContainer', { imageryProvider: new Cesium.MapboxStyleImageryProvider({ styleId: 'ckhqb9qsz08911ip7e6e74w68', // Mapbox威海地图样式ID accessToken: '你的Mapbox密钥' }), baseLayerPicker: false, // 隐藏图层选择器 geocoder: true // 启用搜索(支持搜威海地名) }); // 定位到威海(经纬度122.1°E,37.5°N,高度5000米) this.viewer.camera.flyTo({ destination: Cesium.Cartesian3.fromDegrees(122.1, 37.5, 5000), orientation: { heading: 0, pitch: -45 } }); } - PoP节点绘制:用圆柱体表示PoP,大小=连接数/5(避免太大),颜色代表簇(簇0红色,簇1蓝色等):
// 绘制PoP节点 drawPoPs(popData) { popData.forEach(pop => { const entity = this.viewer.entities.add({ position: Cesium.Cartesian3.fromDegrees(pop.LON, pop.LAT, 100), // 高度100米 cylinder: { length: 200, // 圆柱体高度 topRadius: pop.CONNECT_CNT / 5, // 顶部半径(连接数越大,半径越大) bottomRadius: pop.CONNECT_CNT / 5, material: Cesium.Color.fromCssColorString(this.clusterColors[pop.CLUSTER]) }, name: `PoP-${pop.POP_ID}`, // 鼠标悬浮显示名称 description: `<div>连接数:${pop.CONNECT_CNT}</div><div>所属AS:${pop.ASN}</div>` // 点击显示详情 }); }); } - 连接关系绘制:用曲线表示PoP之间的连接,颜色代表连接强度(连接次数多→红色,少→灰色);
- 交互功能:支持缩放(鼠标滚轮)、平移(拖拽)、搜索(输入PoP_ID定位)、点击节点看详情。
- 3D地图加载:加载Mapbox的威海卫星地图,Cesium初始化代码:
3.5.2 最终效果
- 3D地图上,威海5个PoP簇清晰分布:环翠区(红色大节点)是核心,文登区(蓝色节点)次之,乳山市(绿色小节点)在边缘;
- 点击环翠区核心PoP(P001),显示“连接数28,所属AS4837(中国电信)”,并高亮所有与它连接的PoP,故障时能快速定位影响范围。
四、毕业设计复盘:踩过的坑与经验
4.1 那些踩过的坑
- 路由表解析失败:一开始用Python直接读.bz2文件,内存不够崩溃——解决:先用
libBGPdump(C工具)把.bz2解析成.csv,再用Pandas读,内存占用从20G降到2G; - K值选不准:一开始K=3,簇太大(环翠区和文登区归为一簇),不符合实际——解决:结合威海行政区划(5个区市)和肘部法则,最终K=5;
- Cesium加载慢:3D地图和节点多(100+PoP),页面卡顿——解决:用“层级加载”,远视角只显示核心簇,近视角再显示边缘簇,加载速度提升50%。
4.2 给学弟学妹的建议
- 先跑通小数据:不要一开始就用威海全量数据,先用Karate小数据集(34个节点)测试K-means和布局算法,没问题再换大数据;
- 地理信息要准:IP地理信息选商业库(如IP2Location),免费库(如GeoLite2)精度不够(只能到省),会导致PoP聚类错;
- 答辩突出“可视化价值”:评委更关心系统的实际用途——比如现场演示“点击故障PoP,10秒定位影响的3个区域”,比讲算法公式更有说服力。
五、项目资源获取
完整项目包含:
- 代码文件:Scrapy爬虫(爬取RIPENCC路由表)、K-means聚类脚本(Python+Scikit-learn)、改进FR布局算法(GEO算法Python实现)、Cesium可视化前端代码(Vue+JS)、Flask后端API(对接MySQL与前端),均带详细注释;
- 数据集:威海市PoP节点预处理数据集(含经纬度、连接数、聚类结果)、Karate测试数据集、IP2Location地理信息库(精简版);
- 部署文档:MySQL数据库建表语句(6张核心表)、Cesium环境配置指南(Mapbox密钥申请、依赖安装)、系统部署架构图;
- 答辩资料:PPT模板(含算法流程图、聚类结果图、3D可视化截图)、核心公式推导文档(GEO算法、K-means距离计算)。
六、系统测试与效果验证
为确保系统能用、好用,从“功能+性能+可视化效果”三方面做测试,以威海市138个PoP节点数据为测试对象:
6.1 功能测试(核心用例)
| 测试场景 | 预期结果 | 实际结果 |
|---|---|---|
| 数据采集 | 1小时内爬取3个路由表文件(60G),解析率≥95% | 解析率98.2%,无数据丢失 |
| K-means聚类 | 138个PoP分成5簇,簇内节点地理距离≤5km | 簇内平均距离3.2km,符合预期 |
| 3D可视化-节点点击 | 点击PoP节点显示连接数、AS编号等信息 | 响应时间≤0.5s,信息展示完整 |
| 故障定位模拟 | 标记某核心PoP故障,高亮关联12个PoP | 高亮准确,关联节点无遗漏 |
| 跨浏览器访问 | 支持Chrome、Edge、Firefox | 均正常加载,无布局错乱 |
6.2 性能测试(关键指标)
- 聚类效率:138个PoP节点跑K-means(K=5),耗时≤2s(Python环境,i5-5200U处理器);
- 可视化加载:首次加载威海3D地图+138个PoP节点,耗时≤3s(网速100Mbps);
- 交互响应:地图缩放、平移、节点搜索,响应时间≤0.3s,无卡顿。
6.3 可视化效果验证
对比传统2D表格与本系统的效果:
| 展示方式 | 信息密度 | 故障定位效率 | 地理关联性 |
|---|---|---|---|
| 传统2D表格 | 低(仅文字) | 30分钟 | 无 |
| 本系统3D可视化 | 高(节点+连接+地理) | 1分钟 | 强(与真实地图对应) |
- 结论:系统能直观体现PoP的地理分布与连接关系,故障定位效率提升30倍,满足城市网络管理需求。
七、总结与展望
7.1 项目成果
- 技术层面:提出“K-means聚类+改进FR布局”的PoP拓扑构建方案,解决了传统布局乱、地理关联性差的问题;
- 应用层面:实现威海市PoP级拓扑3D可视化系统,支持数据采集、聚类分析、故障定位,可直接给网络管理员用;
- 性能层面:聚类准确率≥92%,可视化响应快,兼容主流浏览器,稳定性达标。
7.2 未来改进方向
- 实时数据更新:目前数据是离线爬取(8小时一次),后续可对接BGP实时流(如BGPStream),实现拓扑动态更新;
- AI故障预测:基于PoP的连接数、时延等数据,加LSTM模型预测故障风险,提前预警;
- 多城市扩展:当前只支持威海,后续可增加北京、上海等城市数据,做全国PoP拓扑联动展示。
如果本文对你的网络空间安全、网络可视化相关毕业设计有帮助,欢迎点赞 + 收藏 + 关注,后续会分享更多工程化实战案例!