第285篇:Telemetry 数据采集与模型驱动

关键词:YANG模型、OpenConfig、模型驱动、IETF YANG、数据建模、Telemetry采集、NETCONF


一、引言

第284篇介绍了Telemetry与gRPC的基础架构和部署方式。本节深入探讨Telemetry背后的核心基石——模型驱动(Model-Driven)理念,以及YANG数据模型如何在网络设备Telemetry采集中实现标准化和结构化。

模型驱动网络管理(MD-NMS)的核心思想是:用统一的YANG数据模型描述设备状态和配置,用NETCONF/RESTCONF管理配置,用gNMI/Telemetry采集状态,从而打破不同厂商设备的私有协议壁垒。

二、YANG 数据模型基础

2.1 YANG 模型结构

YANG(Yet Another Next Generation)是IETF定义的数据建模语言,用于描述网络设备的数据结构和操作语义。

一个典型的YANG接口模型片段:

module openconfig-interfaces {
  yang-version 1.1;
  namespace "http://openconfig.net/yang/interfaces";
  prefix "if";

  import ietf-inet-types { prefix "inet"; }
  import openconfig-yang-types { prefix "oc-yang"; }

  // 容器: 接口列表
  container interfaces {
    description "Top-level container for interfaces";

    // 列表: 每个接口一个entry
    list interface {
      key "name";
      description "List of interfaces";

      leaf name {
        type string;
        description "Interface name, e.g., 100GE1/0/1";
      }

      container state {
        description "Operational state data";

        leaf oper-status {
          type identityref {
            base IF-STATE;
          }
          description "Operational status (UP/DOWN/UNKNOWN)";
        }

        leaf admin-status {
          type enumeration {
            enum UP { value 1; }
            enum DOWN { value 2; }
            enum TESTING { value 3; }
          }
          description "Administrative status";
        }

        container counters {
          description "Interface counters";

          leaf in-octets {
            type oc-yang:zero-based-counter64;
            description "Total bytes received";
          }

          leaf out-octets {
            type oc-yang:zero-based-counter64;
            description "Total bytes transmitted";
          }

          leaf in-pkts {
            type oc-yang:zero-based-counter64;
            description "Total packets received";
          }

          leaf out-pkts {
            type oc-yang:zero-based-counter64;
            description "Total packets transmitted";
          }

          leaf in-errors {
            type oc-yang:zero-based-counter64;
            description "Inbound error count";
          }

          leaf out-errors {
            type oc-yang:zero-based-counter64;
            description "Outbound error count";
          }
        }

        leaf speed {
          type oc-yang:bps;
          description "Physical speed in bits per second";
        }
      }

      container config {
        description "Configuration data";

        leaf description {
          type string;
          description "Interface description";
        }

        leaf enabled {
          type boolean;
          description "Enable/disable interface";
        }
      }
    }
  }
}

2.2 YANG 模型分类

模型类型 说明 示例
IETF标准模型 IETF官方维护 ietf-interfaces, ietf-ip, ietf-routing
OpenConfig模型 OpenConfig联盟维护 openconfig-interfaces, openconfig-bgp
厂商私有模型 设备厂商自定义 huawei-ifm, cisco-ios-xe-interfaces
扩展模型 基于标准模型的扩展 厂商增强字段

2.3 YANG 与 NETCONF 的关系

YANG 与 NETCONF 的关系 - 图示

三、模型驱动 Telemetry 采集

3.1 采集路径与 YANG 映射

Telemetry的采集路径(Subscription Path)直接对应YANG模型的节点路径:

Telemetry路径 YANG节点 数据类型 说明
/interfaces/interface/state/counters/in-octets interfaces/interface/state/counters/in-octets uint64 接口入字节数
/interfaces/interface[name=100GE1/0/1]/state/oper-status interfaces/interface[name]/state/oper-status string 接口状态
/bgp/neighbors/neighbor[state=ESTABLISHED]/state/uptime bgp/neighbors/neighbor/state/uptime int64 BGP会话Uptime
/system/cpu/state/cpu-usage system/cpu/state/cpu-usage uint8 CPU使用率

3.2 结构化采集 vs 原始采集

采集方式 数据格式 优点 缺点
结构化采集 GPB (编码为YANG路径+值) 标准化、可跨设备对比 依赖设备YANG支持
原始采集 原始二进制/ASCII 灵活性高 解析复杂、不可移植
JSON编码 JSON 可读性好 体积大、解析开销大

3.3 Telemetry 数据流完整流程

Telemetry 数据流完整流程 - 图示

3.4 华为 CE 设备支持的 YANG 模型

YANG模型 说明 采集能力
huawei-ifm 接口管理 接口状态、计数器、光模块
huawei-system 系统管理 CPU、内存、温度、风扇
huawei-bgp BGP管理 BGP状态、Peer、路由
huawei-isis IS-IS管理 IS-IS状态、邻居、LSDB
huawei-ospf OSPF管理 OSPF状态、邻居、LSA
huawei-vxlan VXLAN管理 VTEP、隧道、转发表
huawei-aaa AAA管理 用户会话、认证状态

四、模型驱动管理实战

4.1 NETCONF 配置下发示例

使用YANG模型通过NETCONF下发配置:

<!-- NETCONF Edit-Config 请求 -->
<rpc message-id="101"
    xmlns="urn:ietf:params:xml:ns:netconf:base:1.0">
  <edit-config>
    <target>
      <running/>
    </target>
    <config xmlns:xc="urn:ietf:params:xml:ns:netconf:base:1.0">
      <!-- 使用 OpenConfig 接口模型 -->
      <interfaces xmlns="http://openconfig.net/yang/interfaces">
        <interface>
          <name>100GE1/0/1</name>
          <config>
            <description>Uplink_to_Spine_01</description>
            <enabled>true</enabled>
          </config>
        </interface>
      </interfaces>
      <!-- 配置BGP -->
      <bgp xmlns="http://openconfig.net/yang/bgp">
        <global>
          <config>
            <as>65001</as>
            <router-id>10.255.1.1</router-id>
          </config>
        </global>
        <neighbors>
          <neighbor>
            <neighbor-address>10.255.0.1</neighbor-address>
            <config>
              <peer-as>65001</peer-as>
              <auth-password cipher>Admin@123</auth-password>
            </config>
          </neighbor>
        </neighbors>
      </bgp>
    </config>
  </edit-config>
</rpc>

4.2 NCClient(Python)NETCONF 操作

from ncclient import manager
import xml.etree.ElementTree as ET

# NETCONF连接CE交换机
with manager.connect(
    host="10.255.1.1",
    port=830,
    username="admin",
    password="Admin@123",
    hostkey_verify=False,
    device_params={"name": "huawei"}
) as m:

    # 1. 获取接口配置 (get-config)
    filters = [('subtree', '''
        <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
            <interface>
                <name>100GE1/0/1</name>
            </interface>
        </interfaces>
    ''')]

    result = m.get_config(source="running", filter=filters)
    print(ET.tostring(ET.fromstring(result.xml), encoding="unicode"))

    # 2. 下发配置 (edit-config)
    config = '''
    <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
        <interface>
            <name>100GE1/0/1</name>
            <description>Updated by NETCONF</description>
            <enabled>true</enabled>
        </interface>
    </interfaces>
    '''

    m.edit_config(target="running", config=config)
    print("Configuration updated successfully")

    # 3. 获取状态数据 (get)
    state_result = m.get(filter=('subtree', '''
        <interfaces xmlns="urn:ietf:params:xml:ns:yang:ietf-interfaces">
            <interface>
                <name>100GE1/0/1</name>
                <oper-status/>
            </interface>
        </interfaces>
    '''))
    print(f"Interface state: {state_result.xml}")

4.3 基于 YANG 的 Telemetry 订阅脚本

from gnmi_cli import gNMI_Subscriber
import json

class TelemetrySubscriber:
    """基于YANG模型的Telemetry订阅器"""

    # 定义YANG路径到监控指标的映射
    YANG_PATHS = {
        # 接口监控
        "/interfaces/interface/state/counters/in-octets": "if_in_octets",
        "/interfaces/interface/state/counters/out-octets": "if_out_octets",
        "/interfaces/interface/state/counters/in-errors": "if_in_errors",
        "/interfaces/interface/state/counters/out-errors": "if_out_errors",
        "/interfaces/interface/state/oper-status": "if_oper_status",
        # 系统监控
        "/system/cpu/state/cpu-usage": "cpu_usage",
        "/system/memory/state/memory-usage": "memory_usage",
        "/system/state/temperature": "temperature",
        # BGP监控
        "/bgp/neighbors/neighbor/state/session-state": "bgp_session_state",
        "/bgp/neighbors/neighbor/state/uptime": "bgp_uptime",
    }

    def __init__(self, device_ip, port=4073):
        self.device_ip = device_ip
        self.port = port
        self.subscriber = None

    def subscribe_all(self):
        """订阅所有预定义YANG路径"""
        paths = list(self.YANG_PATHS.keys())

        self.subscriber = gNMI_Subscriber(
            target=f"{self.device_ip}:{self.port}",
            paths=paths,
            mode="sample",
            interval=10000  # 10秒
        )

        self.subscriber.start(callback=self.on_update)

    def on_update(self, update):
        """处理Telemetry更新"""
        for path, value in update.items():
            metric_name = self.YANG_PATHS.get(path, path)

            # 计算接口带宽利用率(每秒)
            if "octets" in metric_name:
                # 需要与前一次采样值对比计算速率
                rate = self._calculate_rate(metric_name, value)
                print(f"[{metric_name}] rate={rate:.2f} B/s")
            else:
                print(f"[{metric_name}] value={value}")


if __name__ == "__main__":
    subscriber = TelemetrySubscriber("10.255.1.1")
    subscriber.subscribe_all()

4.4 YANG 模型与 Prometheus 集成

# gnmi_exporter.yml - gNMI到Prometheus的导出配置
collection:
  - name: dc1_leaf_01
    address: 10.255.1.1:4073
    port: 9399  # Prometheus scrape端口
    path:
      - /interfaces/interface/state/counters/in-octets
      - /interfaces/interface/state/counters/out-octets
      - /system/cpu/state/cpu-usage
    interval: 10s
    encoding: json_ietf

metrics:
  - name: interface_in_octets
    path: /interfaces/interface/state/counters/in-octets
    type: counter
    labels:
      - name  # 接口名作为标签
    description: "Total bytes received on interface"
    rate: true  # 自动计算速率

  - name: interface_out_octets
    path: /interfaces/interface/state/counters/out-octets
    type: counter
    labels:
      - name
    description: "Total bytes transmitted on interface"
    rate: true

  - name: system_cpu_usage
    path: /system/cpu/state/cpu-usage
    type: gauge
    description: "CPU usage percentage"

五、模型驱动管理的优势与挑战

5.1 优势

维度 说明
标准化 YANG模型提供统一的数据结构,跨厂商可互操作
可编程 数据结构化,便于程序化处理和分析
版本管理 YANG模型本身支持versioning,兼容性好
自动化 模型驱动的配置和采集天然适合自动化编排
一致性 配置和状态使用同一模型,减少数据映射错误

5.2 挑战

挑战 说明 应对方案
模型差异 不同厂商YANG模型不一致 优先使用OpenConfig/IETF标准模型
设备支持 老旧设备不支持YANG/NETCONF 通过适配器层转换CLI到YANG
模型版本 YANG模型频繁更新导致兼容性问�� 使用最新的稳定版本,做好回归测试
性能 大模型解析开销 精确订阅所需路径,避免全量订阅

六、总结

能力 传统CLI 模型驱动(YANG)
数据格式 自由文本 结构化XML/JSON/GPB
可编程性 低(需正则解析) 高(直接API调用)
标准化 无 IETF/OpenConfig标准
配置管理 手动/脚本 NETCONF/RESTCONF
状态采集 CLI抓取/SNMP gNMI/Telemetry
版本兼容 差 YANG版本号管理
最佳实践 说明
优先标准模型 使用OpenConfig/IETF标准模型,避免厂商私有模型
精确订阅 只订阅需要的YANG路径,减少带宽和存储开销
模型版本控制 将YANG模型纳入版本管理,跟踪模型变更
模型验证 使用YANG编译器(如pyang)验证模型语法
渐进迁移 从标准接口/YANG模型逐步扩展到BGP/ISIS等复杂模型

思考

  1. YANG模型定义了数据的结构,但不同厂商对同一YANG模型(如openconfig-interfaces)的支持程度可能不同,如何检测设备的模型支持差异?
  2. 当YANG模型版本升级时(如从1.0到1.1),已有的Telemetry订阅和NETCONF配置是否需要修改?如何平滑迁移?
  3. OpenConfig模型和IETF YANG模型在某些领域存在重复定义(如接口模型),实际部署中如何选择?

下篇预告:第286篇:数据中心网络运维 AI 辅助分析