gNMI 上的遥测数据订阅准则
本节介绍 gNMI 连接支持的订阅模式。
gNMI 协议定义用于订阅遥测数据的 Subscribe RPC。遥测收集器使用此 RPC 从网络设备请求状态和配置数据的更新。
新订阅请求封装在包含一个或多个资源路径的消息中SubscribeRequest。订阅的路径与目标网络设备上的特定数据实例相关。请求可以包含基于 OpenConfig 或原生 Junos® OS 模式的路径。
订阅请求还必须包括以下模式之一:
-
ONCE- 一次性数据请求。 -
POLL- 用于定期按需检索数据。 -
STREAM- 根据指定触发器流式传输数据的长期订阅。
模式下的 STREAM 订阅必须指定以下子模式之一:
-
ON_CHANGE- 仅当数据项的值发生变化时,才会发送数据更新。 -
SAMPLE- 根据订阅请求中指定的间隔期,每个采样间隔发送一次数据更新。默认采样间隔为 30 秒。 -
TARGET_DEFINED- 接收订阅请求的网络设备根据每叶确定数据的最佳传输类型。如果消息中指定的路径引用事件驱动的数据,则ON_CHANGE可能会创建订阅。对于表示计数器值的数据,SAMPLE可以创建订阅。注意:TARGET_DEFINED配置路径的订阅请求仅被视为ON_CHANGE请求。
对于 ONCE、 ON_CHANGE 和 SAMPLE 订阅,收集器可以请求包含订阅中路径的当前状态的初始更新。初始同步更新很有价值,因为:
-
收集器可以完整查看设备上传感器路径上每个磁场的当前状态。
-
在下一次事件发生之前,收集器至少接收一次事件驱动的数据 (
ON_CHANGE),以确保收集器事先了解数据状态。 -
还发送包含零计数器值的数据包转发引擎传感器,由于零抑制功能,这些计数器值通常不会显示在流数据中。这可确保收集器知道每个线卡中的所有字段。
目标设备通过一条 SubscribeResponse 消息响应订阅请求。如果订阅请求调用初始同步,则目标会发送数据,后跟响应消息,并将 sync_response 标志设置为 true。初始同步后,目标设备会根据订阅模式继续更新路径。
该 SubscribeRequest 消息包含一个名为 updates_only的标志。当此标志设置为 true时,目标设备不会发送初始同步,只会发送后续更新,如下所示:
-
对于
STREAM处于模式的SAMPLE订阅,更新将在下一个采样间隔发送。 -
对于
STREAM处于模式的ON_CHANGE订阅,更新将在下一次值更改时发送。 -
对于
ONCE订阅,仅SubscribeResponse发送sync_response设置为false,并且订阅将关闭。 -
TARGET_DEFINED订阅被视为ON_CHANGE配置路径,并在下次值更改时发送更新。
和 SubscribeResponse 消息的内容SubscribeRequest在 gnmi.proto 文件中定义。有关订阅 RPC 和订阅模式的详细信息,请参阅 gNMI 规范,网址为:gNMI 规范:订阅遥测更新。
配置路径具有以下限制:
-
POLL不支持订阅。 -
更新消息中不包含前缀路径。
-
特定于瞻博网络的元数据作(如
active/inactive、insert before/after、comment/annotate和protect/unprotect不支持 gNMI 响应。这些可能会出现在消息中,但无效。 -
包括
suppress_redundant、heartbeat_level、allow_aggregation和qos中不支持的SubscribeRequest参数。 -
PROTO 编码是唯一受支持的编码。
-
不支持消息中的
SubscribeRequest扩展 -
订阅路径筛选仅在密钥级别受支持。
和
TARGET_DEFINED订阅不支持ON_CHANGE以下提交变体:commit at、commit prepare/activate和批处理提交。不支持从
edit dynamic以及edit private编辑或配置模式。-
不会为状态容器发送更新消息。
-
只有一个已配置的叶作为标识符或密钥的订阅列表可能不会生成更新消息。
通过 gNMI 实现“ON CHANGE”传感器支持
从 Junos OS 16.1 版开始,可以定期流式传输 OpenConfig作状态和计数器,将遥测数据从瞻博网络设备导出到外部收集器。尽管它在收集所有需要的信息和创建基线“快照”方面很有用,但对于时间紧迫的任务来说,定期流式传输的用处不大。将外部收集器的ON_CHANGE流配置为仅在作状态发生变化时接收信息。
为了支持ON_CHANGE流式处理,实施了一个名为 gRPC 网络管理接口 (gNMI) 的新规范,用于修改和检索网络元素中的配置。此外,gNMI 规范还可用于生成和控制从网络元素到数据收集系统的遥测流。新的 gNMI 规范允许一个 gRPC 服务定义在网络元素上提供单个实现,以进行配置和遥测。它还允许网络管理系统 (NMS) 通过统一遥测和配置 RPC 与设备进行交互。
Junos 文件包 (junos-telemetry-interface) 包括 gnmi.proto 文件和 GnmiJuniperTelemetryHeader.proto 瞻博网络扩展,以支持 gNMI。
有关支持此功能的 RPC 的信息在 gNMI Proto 文件版本 0.4.0(支持的版本)和发布的规范中
gNMI 服务下的遥测 RPC subscribe 支持ON_CHANGE流式传输。RPC subscribe 允许客户端请求目标以发送数据树中特定路径的值。值可以流式传输 (STREAM)、在长期信道 (POLL) 上一次性发送,也可以作为检索 (ONCE) 一次性发送。
如果订阅采样频率为 0 的顶级容器,则会根据事件流式传输支持ON_CHANGE的叶。其他叶子不流式传输。
要让设备确定哪些节点流式传输为 ON_CHANGE 节点或哪些节点是 SAMPLE,收集器必须通过 sample_interval 订阅 TARGET_DEFINED。
通过 gNMI 启用“TARGET_DEFINED”订阅模式
Junos OS 20.2R1 版在 MX5、MX10、MX40、MX80、MX104、MX150、MX204、MX240、MX480、MX960、MX2008、MX2010、MX2020、MX10003、MX10008 和 MX10016 路由器上添加了对带有 gRPC 网络管理接口 (gNMI) 服务的TARGET_DEFINED订阅模式的支持。
使用 gNMI 订阅的外部收集器决定传感器数据的传输方式:
-
STREAMING 模式以指定的时间间隔定期从 DUT 流式传输传感器数据。
-
只有当数据值发生变化时,ON_CHANGE模式才会从 DUT 发送传感器数据的更新。
-
新支持的TARGET_DEFINED模式(子模式 0)指示 DUT 选择相关模式(STREAMING 或 ON_CHANGE)以将传感器数据的每个元素(叶)传送到外部收集器。当外部收集器向 DUT 发送子模式为 0 的传感器订阅时,DUT 会做出响应,激活传感器订阅,以便定期流式传输不包括任何ON_CHANGE更新。每当发生符合条件的ON_CHANGE事件时,DUT 都会通知收集器。
订阅默认为 30 秒的定期流式处理频率,除非收集器在订阅请求中另有指定。
下面的 JavaScript 对象标记 (JSON) 文件显示了一个示例 gNMI 订阅。TARGET_DEFINED模式是为 submode=0 资源(传感器)路径 /interfaces/interface[name='lo0']/state 设置的。
$ cat gnmi.json
{
"dut_list":[
{
"port":32767,
"rpc":["sub_request"],
"sub_request":{
"subscription":[
{
"path":"/interfaces/interface[name='lo0']/state",
"submode":0,
"sample_interval":30
}
],
"mode":0,
"encoding":2
}
}
]
$ python ./gnmi_subscribe_client_sample.py -c ./gnmi.json -d 10.53.32.102 -l client.log
Junos 文件包 (junos-telemetry-interface) 包括 gnmi.proto 文件和 GnmiJuniperTelemetryHeader.proto 瞻博网络扩展,以支持 gNMI。
有关更多信息,请参阅此处的 gNMI 规范和 gNMI 协议文件:
通过 gNMI 启用“INITIAL_SYNC”订阅模式
从 Junos OS 20.2R1 版开始,可支持使用 gNMI 服务从数据包转发引擎传感器INITIAL_SYNC统计数据。此功能适用于 MX960、MX2008、MX2010、MX2020、PTX1000 和 PTX5000 路由器。路由器、瞻博网络® QFX5100 交换机和 瞻博网络® QFX5200交换机的瞻博网络®PTX10000 系列也提供此支持。
从 Junos OS 演化版 20.4R1 开始,支持使用 gNMI 服务从数据包转发引擎传感器获取INITIAL_SYNC统计数据。® 瞻博网络 QFX5130-32CD 交换机包含此支持。
当外部收集器向具有 INITIAL_SYNC (gnmi-submode 2) 的传感器发送订阅请求时,主机将该资源路径下所有支持的目标叶(字段)至少一次发送到具有当前值的收集器。收集这些统计数据是有益的,因为:
-
收集器可以完整查看设备上传感器路径上每个磁场的当前状态。
-
事件驱动的数据 (ON_CHANGE) 在下一个事件发生之前至少到达收集器一次。此方法可确保收集器在下一个事件发生之前了解数据状态。
-
具有零计数器值(零抑制)且通常不会出现在流数据中的数据包转发引擎传感器至少发送一次。此方法可确保收集器能够查看每个线卡(通常称为源)中的所有字段。
INITIAL_SYNC子模式要求设备向收集器发送至少一个副本,但发送多个副本是可以接受的。
订阅将默认为 30 秒的定期流式处理频率,除非收集器在订阅请求中另有指定。
下面的 JavaScript 对象标记 (JSON) 文件显示了一个示例 gNMI 订阅。INITIAL_SYNC模式是使用 gnmi_submode 2 用于资源(传感器)路径 /interfaces/ 设置的。的设置为 gnmi_mode 0。协议编码设置为 2 GBP。
{
"influx": {
"server": "server1",
"port": 8086,
"dbname": "gD40",
"measurement": "OC",
"user": "influx",
"password": "influxdb",
"recreate": true
},
"gnmi": {
"mode": 0, <---- STREAM
"encoding": 2, <--- PROTO encoding
"prefix": "/x/y/z"
},
"host": "10.10.130.73",
"port": 10162,
"user": "user1",
"password": "password1",
"cid": "cid-1jk",
"paths":[
{
"path": "/interfaces/",
"Freq": 10000000000,
"gnmi_submode": 2 <---- SAMPLE
}
]
}
Junos 文件包 (junos-telemetry-interface) 包括 gnmi.proto 文件和 GnmiJuniperTelemetryHeader.proto 瞻博网络扩展,以支持 gNMI。
有关更多信息,请参阅此处的 gNMI 规范和 gNMI 协议文件:
gNMI 遥测规范 gNMI 协议定义
例子
以下示例以 protobuf 格式显示 gNMI 客户端和目标设备发出的订阅请求和响应。
示例:ONCE 模式
以下示例显示了以 protobuf 格式从 gNMI 客户端发送的订阅请求。订阅模式为 ONCE ,OpenConfig 资源路径为 /system/aaa/authentication/users:
root@controller:~# /usr/local/bin/gnmic sub -a 10.225.0.0:32767 --mode once --path /system/aaa/authentication/users -u <username> -p <password> --format prototext
目标以一次性更新作为响应:
update: {
timestamp: 1676294840
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test2"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}
示例:ON_CHANGE
以下示例显示了模式 STREAM 下具有 ON_CHANGE 子模式的订阅请求。OpenConfig 资源路径为 /system/aaa/authentication/users/user[username=“test1”]:
root@controller:~# /usr/local/bin/gnmic sub -a 10.225.0.0:32767 --mode stream --stream-mode on-change --path /system/aaa/authentication/users -u <username> -p <password> --format prototext
订阅请求时的 OpenConfig 配置:
user@root> show configuration openconfig-system:system aaa authentication | display set set openconfig-system:system aaa authentication users user test1 config password $ABC123 set openconfig-system:system aaa authentication users user test1 config role superuser
示例响应消息显示配置路径的值,并将 sync_response 标志设置为 true:
update: {
timestamp: 1676311979
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}
sync_response: true
将对订阅路径进行以下配置更改:
-
为 添加用户
test1名。 -
删除 的
test1密码。
目标设备发送以下更新作为响应:
update: {
timestamp: 1676312428
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
delete: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
}
示例:SAMPLE
以下示例显示了模式和SAMPLE子模式下的STREAM订阅请求。OpenConfig 资源路径为 /system/aaa/authentication/users/user[username=“test1”]:
root@controller:~# /usr/local/bin/gnmic sub -a 10.225.0.0:32767 --mode stream --stream-mode sample --sample-interval 5s --path /system/aaa/authentication/users -u <username> -p <password> --format prototext
订阅请求时的 OpenConfig 配置:
user@root> show configuration openconfig-system:system aaa authentication | display set set openconfig-system:system aaa authentication users user test1 config username test1 set openconfig-system:system aaa authentication users user test1 config password "$ABC123" set openconfig-system:system aaa authentication users user test1 config role superuser
示例响应消息显示发送的初始更新(标志 sync_response 设置为) true 以及以 5 秒的间隔发送的后续更新:
update: {
timestamp: 1676295454
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}
sync_response: true
update: {
timestamp: 1676295459
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}
update: {
timestamp: 1676295464
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "username"
}
}
val: {
string_val: "test1"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "password"
}
}
val: {
string_val: "$ABC123"
}
}
update: {
path: {
elem: {
name: "system"
}
elem: {
name: "aaa"
}
elem: {
name: "authentication"
}
elem: {
name: "users"
}
elem: {
name: "user"
key: {
key: "username"
value: "test1"
}
}
elem: {
name: "config"
}
elem: {
name: "role"
}
}
val: {
string_val: "superuser"
}
}
}