从功能分册到资源模型:网络资源管理系统通用能力实践
2026/9/23 20:43:18 网站建设 项目流程

简介:这份技术规范是中国移动通信集团公司发布的企业标准,用于指导和规范综合网络资源管理系统的建设与运营,适合电信行业网络资源管理、系统建设及运维人员参考。标准覆盖了系统定位与总体目标、业务需求背景、建设原则,以及通用功能架构,包括系统基础维护、资源存量管理、资源应用功能和资源数据共享服务等核心内容。其中,基础维护涵盖资源模型管理、命名管理、数据质量管理、批量导入导出与系统管理;存量管理涉及空间、物理、逻辑、业务资源及拓扑管理;应用功能包括调配、分析、展现和其他类应用,为网络资源的高效配置、优化调度和决策支持提供了明确的规范指引。资源包为单个doc文档,大小约1.03MB,内容版式清晰、目录完整,便于按章节查阅。目前已有303人浏览学习,适合需要系统了解中国移动网络资源管理标准体系的技术人员研读。

1. 综合网络资源管理系统通用功能分册到底在规范什么

这个标题看着像一份归档文档,实际上它比很多源码都值得先读。综合网络资源管理系统负责把核心网、传送网、接入网、无线网等多个专业的资源统一管起来,而通用功能分册刻意把专业差异拿掉,只回答一个问题:不管资源是哪一类的,系统都应该具备哪些能力。资源建模、状态变更、拓扑呈现、数据同步、权限控制,这些功能放在哪个专业都能复用,所以它才叫“通用”。我见过不少团队把这个分册当成验收后入库的合订本,等二期需要扩展新资源类型时才回来翻,结果模型已经写死,只能推翻重来。正确做法是把它当成需求源头,从第一天就把每个功能点对到数据表、状态机、接口字段上。适合做系统设计的研发、写测试用例的QA、控需求范围的产品经理。分册篇幅通常不短,但它隐含的抽象层很薄,读的时候抓住“资源对象 + 状态 + 关联关系”三条线,后面所有功能都是在这三条线上做组合。

2. 从功能分册到资源模型:先把“网络资源”翻译成数据结构

一份通用功能分册不会像专业分册那样讲“SDH的VC4如何交叉连接”,它只会写“支持资源查询、资源新增、资源变更、资源删除”。想落地,就得先确定系统里的资源到底长什么样。我一般会把网络资源先切成三类,再决定模型怎么建。

2.1 资源对象分类:物理资源、逻辑资源与业务资源

把资源分为物理、逻辑、业务三层,是为了避免不同专业开发各自建表,最后数据对不上。物理资源是能摸到的,比如机房、机架、板卡、端口、电源端子;逻辑资源是在物理资源上衍生出来的,比如VLAN、IP地址、伪线、隧道、SR转发实例;业务资源是直接对客户交付的,比如专线、宽带接入、云专线。同一个端口,在物理层是一条记录,在逻辑层可能绑定了多个VLAN,在业务层又有对应的客户订单号。

资源分类典型对象通用功能分册对应能力
物理资源机房、机架、设备、板卡、端口资源入库、位置管理、生命周期变更
逻辑资源VLAN、IP、MPLS隧道、路由协议资源分配、占用与释放、连通性关系
业务资源专线、互联网专线、云连接业务编排、客户视图、故障定位影响分析

分册里只要有“资源查询”,就必须有一个能容纳这三种对象的查询入口。如果一开始只建了“物理设备表”,后面加逻辑资源时就要再造一张表,功能分册里的统一查询就做不到了。我通常建一张资源主表,用product_type字段区分类别。

CREATE TABLE resource_instance ( resource_id VARCHAR(64) PRIMARY KEY, product_type VARCHAR(16) NOT NULL COMMENT 'PHYSICAL / LOGICAL / BUSINESS', resource_type VARCHAR(64) NOT NULL COMMENT 'EQUIPMENT、PORT、VLAN、CIRCUIT 等', parent_id VARCHAR(64) COMMENT '父资源ID,用于层级关系', status VARCHAR(16) NOT NULL DEFAULT 'PLAN', owner_system VARCHAR(32) COMMENT '来源网管或手工维护', biz_code VARCHAR(64) COMMENT '业务编码,关联订单或客户', extend_attrs JSON COMMENT '扩展属性,不同资源差异很大', created_time DATETIME DEFAULT CURRENT_TIMESTAMP, updated_time DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, KEY idx_resource_type (product_type, resource_type), KEY idx_parent (parent_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这张主表有两个容易忽略的点。parent_id是层级关系的核心,物理设备到机架、端口到板卡都靠它形成树;extend_attrs用JSON承载各专业差异,不需要为每种设备类型建字段。业务上如果要求“资源编码唯一”,需要在应用层先确定编码规则,数据库唯一键建议用resource_id加上owner_system组合,避免多个网管系统上报时ID互相冲突。

2.2 资源关系表与“资源详情”功能的支撑

通用功能分册里经常出现“查一个端口,要能看到它所在设备、绑定的VLAN、经过的物理路由”。这是典型的关系查询,但很多系统用一张resource_instance的parent_id很难表达“端口关联VLAN”这种非父子关系。我的做法是单独建资源关系表,把“连接”“绑定”“依赖”“承载”全部抽象成relation_type。

CREATE TABLE resource_relation ( relation_id BIGINT PRIMARY KEY AUTO_INCREMENT, src_id VARCHAR(64) NOT NULL, dst_id VARCHAR(64) NOT NULL, relation_type VARCHAR(32) NOT NULL COMMENT 'PARENT / CONNECT / BIND / CARRY', effective_time DATETIME DEFAULT CURRENT_TIMESTAMP, expire_time DATETIME NULL, source_system VARCHAR(32) COMMENT '关系发现来源:手工、LLDP、网管', KEY idx_src (src_id), KEY idx_dst (dst_id), KEY idx_relation (relation_type) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

这里最需要想清楚的是relation_type。PARENT表示树形父子,比如机架属于机房;CONNECT表示物理端口之间的跳线连接;BIND表示逻辑资源绑定到物理端口;CARRY表示业务路由经过某个隧道。分册里“资源详情”“资源影响分析”本质都是查这张关系表。

查询一个端口影响了多少业务时,先查端口绑定的VLAN,再顺着VLAN查承载的隧道,最后找到业务。这个链路不能靠写死SQL,应该做成配置化查询,后续新增资源类型时只要注册新的relation_type就行,不需要改功能菜单。

2.3 把功能分册的功能点映射到数据字典

拿到通用功能分册后,第一件事不是设计前端页面,而是做“功能点—数据对象—数据项”的映射。比如分册写“支持资源的组合查询”,你就要问:按哪些字段查?专业、区域、资源状态、维护状态、供应商。我把这组字段称为“查询字典”。在资源表里没有的字段,要么加到extend_attrs,要么拆成扩展表,不能允许“这个需求我们页面里手动过滤”这种临时方案。

功能分册描述涉及资源对象需要的数据字段系统动作
按区域查询资源所有资源所属区域、纬度信息从资源主表按区域维度过滤
查看资源使用情况端口、IP、VLAN状态、占用订单、更新时间关联业务表和占用记录
资源影响分析端口、电路、业务关系类型、路径顺序遍历resource_relation

映射完成后,写一个数据字典校验SQL,能很快找出“规范要求了但表里还没有”的字段。比如检查资源实例里是否出现了未注册的resource_type,避免各专业自行造类型。

SELECT product_type, resource_type, COUNT(*) AS cnt FROM resource_instance GROUP BY product_type, resource_type HAVING cnt > 0 AND (product_type, resource_type) NOT IN ( SELECT product_type, resource_type FROM sys_resource_type_config );

这个SQL的作用是发现没有登记的资源类型。resource_type是字典项,必须先由模型管理员在sys_resource_type_config里注册,各专业才能使用。否则维表越来越大,通用查询下拉框会被塞入几十种彼此重叠的类型。参数说明:product_type限定大类,resource_type是细分类型,HAVING子句负责把“有数据但无配置”的组合筛出来。日常可以用定时任务跑一遍,输出结果进工单。

3. 通用功能落到代码:资源生命周期与拓扑管理怎么做

分册里的“资源新增”“资源变更”“资源退网”如果只是做成页面按钮,系统一定失控。核心是先把生命周期状态机定清楚,再让所有操作都通过状态机校验。否则一个退网设备上的端口仍可能被分配出去,功能分册验收时一条用例就会打回。

3.1 状态机先于数据库逻辑:生命周期状态流转

我经验证,综合网络资源管理系统最容易出错的就是状态字段的过渡。新资源录入后直接置为“在用”,会导致后续发起退网时不知道它是否已被业务占用。通用功能分册里通常隐含了这样一条状态链:计划 → 库存 → 预留 → 在用 → 退网,中间还有故障、维修等扩展状态。

状态编码含义允许的操作
PLAN计划新建,尚未物理入库修改信息、取消归档
IN_STOCK已入库可用分配、预留、退网
RESERVED已预留,暂不分配释放为库存、分配为在用
IN_USE被业务占用加故障、退网
FAULT故障维修修复后回到在用
RETIRED已退网不可用仅可查看,不可分配

这个状态机必须在后端校验,不能只在前端做下拉框。我一般用Python写一个严格的转移表,接口调用时先执行这个函数,不通过直接报错。

from enum import Enum class ResourceStatus(Enum): PLAN = "PLAN" IN_STOCK = "IN_STOCK" RESERVED = "RESERVED" IN_USE = "IN_USE" FAULT = "FAULT" RETIRED = "RETIRED" ALLOWED_TRANSITIONS = { ResourceStatus.PLAN: {ResourceStatus.IN_STOCK, ResourceStatus.RETIRED}, ResourceStatus.IN_STOCK: {ResourceStatus.RESERVED, ResourceStatus.IN_USE, ResourceStatus.RETIRED}, ResourceStatus.RESERVED: {ResourceStatus.IN_STOCK, ResourceStatus.IN_USE}, ResourceStatus.IN_USE: {ResourceStatus.FAULT, ResourceStatus.RETIRED}, ResourceStatus.FAULT: {ResourceStatus.IN_USE, ResourceStatus.RETIRED}, ResourceStatus.RETIRED: set(), } def can_transit(current: ResourceStatus, target: ResourceStatus) -> bool: return target in ALLOWED_TRANSITIONS[current]

这段代码把状态转移集中到了一个字典里。can_transit接收当前状态和目标状态,返回是否允许。好处是,资源变更接口、分配接口、退网接口共用同一套校验逻辑,不会出现“创建接口允许跳级,退网接口又拦一道”的偏差。实际项目中,再把current和target换成proposed_time、operator_id写入变更流水表,就满足分册的审计要求了。

3.2 资源导航与拓扑自动发现的数据结构支撑

通用功能分册会要求“支持按专业、局向、区域逐级查看资源”,这个功能最直观的实现就是递归查询。依赖关系表后,用一条递归CTE就能把指定资源的所有下级资源查出来。

WITH RECURSIVE resource_tree AS ( SELECT resource_id, resource_type, status, 0 AS depth FROM resource_instance WHERE resource_id = 'RES-PORT-0001' UNION ALL SELECT c.resource_id, c.resource_type, c.status, t.depth + 1 FROM resource_instance c JOIN resource_relation r ON c.resource_id = r.dst_id JOIN resource_tree t ON r.src_id = t.resource_id WHERE r.relation_type = 'PARENT' AND t.depth < 20 ) SELECT * FROM resource_tree;

这个查询先定位起点资源,再沿PARENT关系向下钻取,最多20层防止环路死循环。参数说明:RES-PORT-0001是起点资源ID,depth是层级深度,relation_type='PARENT'决定了只沿着树形关系走。如果分册里的“拓扑视图”还要显示端口直连关系,就把relation_type条件改成CONNECT,并把JOIN方向调整一下。这样一套接口就能同时支撑资源导航和拓扑展示。

自动发现关系的部分,我常用的方案是:从网管系统采集LLDP或物理连线表,解析出源端口和目的端口,然后批量写入resource_relation,relation_type为CONNECT。写入前要先去重,防止两边网管各自上报同一条关系,产生重复记录。

INSERT INTO resource_relation (src_id, dst_id, relation_type, source_system) SELECT DISTINCT src.resource_id, dst.resource_id, 'CONNECT', 'LLDP-AGENT' FROM raw_lldp_link l JOIN resource_instance src ON src.external_id = l.local_port_id JOIN resource_instance dst ON dst.external_id = l.remote_port_id LEFT JOIN resource_relation r ON r.src_id = src.resource_id AND r.dst_id = dst.resource_id WHERE r.relation_id IS NULL;

这段SQL的关键是LEFT JOIN后取空值,只插入此前没有的关系,避免每次采集都产生脏数据。字段说明:external_id是各网管系统里设备的自有编码,在resource_instance中必须建立唯一索引,否则接不上。

3.3 数据同步接口的增量与幂等设计

分册对“数据同步功能”的标准描述往往是“支持多系统间资源增量同步”。这里最重要的是幂等。网管接口重试后,同一批数据重复上报,不能造成资源重复或状态回退。

def sync_resources(source_data, db_session): changed_count = 0 for item in source_data: res = db_session.query(Resource).filter_by(resource_id=item["resource_id"]).first() if res is None: db_session.add(Resource(**item)) changed_count += 1 continue if item.get("updated_at") and res.updated_time >= item["updated_at"]: continue for key, value in item.items(): setattr(res, key, value) changed_count += 1 db_session.commit() return changed_count

这段逻辑先按resource_id查出已有记录,没有就直接新增;有则比较时间戳,如果上报数据的updated_at不新,就跳过。这样即使消息队列重复投递,也不会把旧数据覆盖新数据。注意参数:source_data每条都要包含resource_id、updated_at和业务字段,db_session可以是SQLAlchemy的会话对象。生产环境需要在resource_id上加唯一索引,并且源系统要保证同一条资源上报到同一个分区。

同步方式触发时机适合场景失败处理
全量同步每日凌晨资源总量少,允许短时偏差失败重跑,全量重建索引
增量同步变更后实时资源量大,需要准实时幂等合并,失败进入重试队列
定时对账每30分钟校验两系统间差异输出差异报告,人工仲裁

实际项目里三种方式会同时存在。全量用来保证基线,增量用来保证时效,对账用来发现漏采和错采。分册中的“一致性”功能要求,你可以在对账任务里对相同resource_id的资源,比较状态、所属区域、设备型号这三个关键字段,只把差异行输出。

4. 按功能分册做验收:覆盖度分析与自动化测试

分册写得很全,但开发完成后怎么证明“我做了”?不能靠一个截图。需要把功能分册的每一条描述拆成功能点,再用接口测试去验证。拆解的过程本身也会暴露需求理解不一致的问题。

4.1 建立功能追溯矩阵,先回答“做没做”

追溯矩阵是测试和验收的基本盘。纵向是分册中的功能点,横向是系统模块、接口地址、测试用例、状态。梳理时我习惯用表格,但正式交付时会落到项目管理系统的字段里。

分册描述功能点ID系统模块接口用例状态
资源新增支持校验编码唯一F-1001资源维护POST /api/resourcesTC-1001已通过
资源状态支持预留与释放F-1002生命周期PUT /api/resources/{id}/statusTC-1002已通过
资源查询支持组合条件F-1003资源查询GET /api/resourcesTC-1003已通过

如果功能点ID和分册章节号对不上,后期追查会很痛苦。比如F-1001就是分册第二章第三节第一条,这样线上出了bug能直接定位到规范条目。建议代码提交信息里也带上功能点ID,例如“feat: F-1001 resource create unique validation”,这样评审时可以直接看到需求来源。

4.2 用 pytest 把关键功能固化成接口测试

手动验收只能证明测试当天可用,接口测试才能防止回归。我通常挑状态机、资源查询、生命周期三个最核心的能力写pytest用例。下面是一个创建资源的用例。

import pytest import requests BASE_URL = "http://127.0.0.1:8000" def test_create_resource_should_return_plan(): payload = { "product_type": "LOGICAL", "resource_type": "VLAN", "parent_id": None, "extend_attrs": {"vlan_id": 100} } response = requests.post(f"{BASE_URL}/api/resources", json=payload) assert response.status_code == 201 body = response.json() assert body["status"] == "PLAN" detail = requests.get(f"{BASE_URL}/api/resources/{body['resource_id']}") assert detail.json()["resource_type"] == "VLAN"

这个用例有两个断言。第一是创建接口返回201,并且新资源的状态是PLAN,不是直接用。第二是查询详情能查到刚才创建的资源。如果分册里写了“新资源应处于计划状态”,这个用例就能拦住“开发直接置为在用”的简化实现。参数说明:product_type和resource_type必传,extend_attrs里的vlan_id是业务扩展项。实际工程中还需要在teardown里调用删除接口,或使用数据库事务回滚,避免用例之间相互影响。

状态流转的测试更值得写。比如退网接口只能接受IN_USE或FAULT状态的资源,如果传PLAN状态应该返回400。这类用例能保护状态机的约束不被后续改动破坏。

4.3 性能压测的参数与判断阈值

通用功能分册不会给出性能数字,但实际验收时业务方会问“同时多少人用会不会卡”。我一般把资源查询接口的响应时间作为核心观测对象。压测工具用JMeter,命令行执行方便集成到流水线。

jmeter -n -t resource_query.jmx -l result.jtl -e -o report/ \ -Jthreads=50 -Jrampup=10 -Jduration=300

参数说明:-Jthreads=50表示50个并发用户,-Jrampup=10表示10秒内陆续启动,-Jduration=300表示持续压测300秒。-n表示非GUI模式,-e和-o是生成HTML报告。resource_query.jmx里需要预先定义一个HTTP请求,路径是GET /api/resources,并添加随机查询参数,避免命中缓存导致结果失真。

接口压测场景目标值
GET /api/resources?type=PORT在线人员查询TP95 < 1秒
POST /api/resources批量录入TP95 < 2秒
PUT /api/resources/{id}/status状态变更TP95 < 1秒

如果TP95超过目标值,先看SQL执行计划,再看是否缺少索引。资源查询最常慢在parent_id和relation_type上没有索引,检查resource_instance的idx_parent和resource_relation的idx_relation是否被使用。

5. 把通用功能分册变成版本计划的三个技巧

第一个技巧是拆用户故事不要按页面拆,按“资源对象 + 状态 + 动作”拆。评价标准很直接:读完这个用户故事,开发能说出改哪张表、动哪个状态、调哪个接口。比如“作为网络管理员,我要对PLAN状态的逻辑资源执行归档,使该资源从可用列表中消失,且不能再次分配”,这句话已把status和API路径都限定死了。

第二个技巧是让分册里的每条功能点都对应到一个接口契约。交付之前先给测试一份接口文档,不用写太多,但要标明每个字段是否必填、状态流转的约束、错误码。我习惯直接在项目里维护openapi.yaml,每次评审分册需求时同步更新这个文件,避免功能做完了文档还是旧版。

第三个技巧是上线前用资源一致性SQL打一次分。综合网络资源管理系统最容易积累脏数据,比如内存中的配置和数据库不一致、已退网资源还挂在业务上。我会在割接前跑下面这段SQL,快速找出“在用但没关联任何业务”的资源。

SELECT r.resource_id, r.resource_type, r.status, r.updated_time FROM resource_instance r WHERE r.status = 'IN_USE' AND NOT EXISTS ( SELECT 1 FROM resource_relation rr WHERE rr.src_id = r.resource_id AND rr.relation_type IN ('CARRY', 'BIND') ) LIMIT 100;

这段SQL列出所有状态为在用,但没有绑定关系、也没有承载业务的资源。如果是端口,说明可能漏录了关联;如果是业务资源,说明已退订但状态没变更。把这些数据导出工单,让对应专业负责人处理后再放量,能避免上线后出现“明明已退网,还在客户拓扑里显示”的争议。核查周期定在每周一和周四,比月末突击对账更可靠。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询