1. 为什么监控网络设备时,Prometheus 和 SNMP 总是被一起提起?
在数据中心机房巡检时,我见过太多次这样的场景:运维同事盯着 Grafana 看着交换机端口流量曲线平稳上升,突然某条线骤降为零——他立刻切到终端敲snmpwalk -v2c -c public 10.1.5.22 ifDescr,三秒后确认是光模块离线;而隔壁开发正用 Prometheus 的rate(ifInOctets[5m])告警触发 Slack 消息。这两套工具像左右手:一个负责“听见设备说什么”,一个负责“记住它说了什么、说了多久、说了多少次”。
这不是巧合。Prometheus 本身不原生支持 SNMP 协议——它只认 HTTP 上的/metrics接口,返回的是纯文本格式的指标数据(如http_requests_total{method="GET",status="200"} 12345)。而 SNMP 是一套运行在 UDP 之上的独立网络管理协议,设备通过 OID 树暴露状态(比如1.3.6.1.2.1.2.2.1.10.1表示第一个接口的入向字节数)。两者之间隔着一道“协议鸿沟”。
于是,snmp_exporter应运而生。它不是 Prometheus 的插件,而是一个独立的、专为“翻译”而生的中间服务:监听 Prometheus 的拉取请求,主动向目标设备发起 SNMP 查询,把原始 OID 响应解析成 Prometheus 能懂的指标格式,再以标准/metrics接口吐出来。整个过程没有代理、不转发原始 SNMP 报文,纯粹是“问-答-转译-交付”。这解释了为什么你在prometheus.yml里配置的是snmp_exporter的地址,而不是直接写交换机 IP;也解释了为什么snmp_exporter必须和 Prometheus 部署在同一网络平面——它需要能直连被监控设备。
这个设计背后有明确取舍。Prometheus 坚持“拉模式”(pull),拒绝被动接收 SNMP Trap(推模式),是因为拉模式天然具备可追溯性:每次采集都有明确时间戳、有失败日志、可重试、可限速;而 Trap 一旦丢包就永远丢失,且缺乏上下文(比如 Trap 来的时候,设备 CPU 是 98% 还是 12%?)。所以当你看到“Prometheus 监控 SNMP 设备”,实际是三层协作:设备用 SNMP 协议说话 →snmp_exporter当翻译官 → Prometheus 当档案管理员,把翻译结果存进时序数据库。
提示:很多新手误以为
snmp_exporter是 Prometheus 的一个内置模块,试图在prometheus.yml里直接配置snmp:字段。这是行不通的。它必须作为独立进程运行,Prometheus 只通过static_configs指向它的:9116/metrics接口。
2. snmp_exporter 的核心机制:从 OID 到指标的完整翻译链
snmp_exporter的工作流程远非简单地把snmpget结果贴上标签。它有一套精密的“翻译规则引擎”,其核心是SNMP Collector + Generator + Metrics Mapping三层结构。理解这三层,才能真正掌控监控精度。
2.1 Collector 层:一次采集,多维覆盖
当你在 Prometheus 中配置一个目标(如10.10.20.5:9116),Prometheus 会向snmp_exporter发起 GET 请求,附带一个关键参数:?module=if_mib。这个module不是随便写的,它对应snmp_exporter内置的采集模块名,而每个模块背后是一组预定义的 OID 列表和采集策略。
以if_mib模块为例,它并非只查ifInOctets这一个 OID。打开snmp_exporter的默认generator.yml文件,你会看到:
modules: if_mib: walk: - 1.3.6.1.2.1.2.2.1.1 # ifIndex - 1.3.6.1.2.1.2.2.1.2 # ifDescr - 1.3.6.1.2.1.2.2.1.10 # ifInOctets - 1.3.6.1.2.1.2.2.1.16 # ifOutOctets - 1.3.6.1.2.1.2.2.1.19 # ifOperStatus metrics: - name: ifIndex oid: 1.3.6.1.2.1.2.2.1.1 type: gauge # ... 其他指标定义注意walk:字段——它告诉snmp_exporter:不要单个snmpget,而是用snmpbulkwalk一次性遍历整棵子树。这对网络设备至关重要:一台 48 口交换机,ifIndex从 1 到 48,ifInOctets就有 48 个值。如果逐个get,48 次 UDP 往返可能耗时 2 秒以上;而bulkwalk一次请求就能拿到全部,实测耗时通常 <200ms。这就是为什么snmp_exporter的采集延迟远低于脚本轮询。
但bulkwalk也有代价:它会拉取所有实例,包括你不需要的(比如ifIndex=100可能是内部 loopback 接口)。这时metrics:下的regex过滤就派上用场了:
- name: ifInOctets oid: 1.3.6.1.2.1.2.2.1.10 type: counter help: The total number of octets received on the interface. indexes: - labelname: ifIndex type: gauge regexes: - "^1$|^2$|^3$|^4$|^5$|^6$|^7$|^8$|^9$|^10$|^11$|^12$" # 只保留前12个物理口这段配置的意思是:只把ifIndex值为 1 到 12 的ifInOctets指标暴露出去,其余全部丢弃。这直接减少了 Prometheus 存储的压力——少存 36 个无用时间序列,一年下来能省下数 GB 的磁盘空间。
2.2 Generator 层:YAML 驱动的指标生成器
snmp_exporter的灵魂在于generator.yml。它不是一个静态配置文件,而是一个“指标生成蓝图”。snmp_exporter启动时,会先用 Go 工具generator解析这个 YAML,生成 Go 代码,再编译成最终的二进制。这意味着:你改的不是运行时配置,而是编译时的逻辑。
为什么这么设计?因为 SNMP OID 的结构千差万别。有些 OID 是标量(scalar),如sysUpTime.0,只有一个值;有些是表格(table),如ifTable,有多个行(row)和列(column)。generator必须在编译期就确定:哪些 OID 是索引(index),哪些是值(value),如何把它们组合成 Prometheus 的标签(label)。
看一个真实案例:华为 S5735 交换机的端口光功率监控。它的 OID 是1.3.6.1.4.1.2011.5.25.31.1.1.1.1.10(hwOpticalModuleRxPower),但这个 OID 本身不带端口信息。真正的索引藏在1.3.6.1.4.1.2011.5.25.31.1.1.1.1.1(hwOpticalModuleIfIndex)里。generator.yml必须这样写:
- name: hwOpticalModuleRxPower oid: 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.10 type: gauge help: Optical module receive power in dBm. indexes: - labelname: ifIndex type: gauge oid: 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.1这里indexes:明确指定了ifIndex的来源 OID。generator编译时会把这两个 OID 绑定,确保hwOpticalModuleRxPower{ifIndex="12"}的标签值,一定来自同一行的hwOpticalModuleIfIndex值。如果没有这层绑定,你拿到的可能是hwOpticalModuleRxPower{ifIndex="999"}——一个根本不存在的端口。
注意:
generator.yml修改后,必须重新运行make build(或./scripts/build.sh)生成新的snmp_exporter二进制。直接重启服务无效。这是新手踩坑最高频的操作——改完 YAML 就systemctl restart,发现指标没变,其实是旧二进制还在跑。
2.3 Metrics Mapping 层:标签、类型与语义的精准对齐
Prometheus 指标有三要素:名称(name)、标签(labels)、值(value)。snmp_exporter的映射必须精确到每一个细节,否则 Grafana 图表会乱套。
名称(name):不能含空格、特殊字符,推荐小写下划线。
ifInOctets是标准写法,if-in-octets会被 Prometheus 拒绝。标签(labels):
indexes:定义的标签是“维度”,lookups:定义的标签是“描述”。比如:- name: ifDescr oid: 1.3.6.1.2.1.2.2.1.2 type: DisplayString help: A textual string containing information about the interface. indexes: - labelname: ifIndex type: gauge lookups: - labels: [ifIndex] oid: 1.3.6.1.2.1.2.2.1.2这段配置让
ifDescr{ifIndex="1"}的值(如"GigabitEthernet0/0/1")成为ifInOctets{ifIndex="1"}的一个附加标签。最终在 Prometheus 中,你可以写ifInOctets{ifDescr=~"Gigabit.*"},而不是记一堆数字 ID。类型(type):
counter和gauge的选择决定告警逻辑。ifInOctets是计数器(counter),它的值只会增长,rate()函数计算每秒增量;而ifOperStatus是仪表(gauge),值在 1(up)和 2(down)之间跳变,适合用== 2做状态告警。选错类型,rate()会报错,==会永远不触发。
实测中,我们曾因把sysUpTime错配成gauge,导致 Grafana 显示“设备已运行 2147483647 秒”(32 位整数溢出),而实际是 12 天。根源就是sysUpTime是TimeTicks类型,本质是 counter,必须配type: counter。
3. 从零部署:一个可落地的交换机监控实战流程
纸上谈兵不如亲手搭一遍。下面是以一台 Cisco Catalyst 9200 交换机(IP192.168.10.100)为对象,从零开始部署 SNMP 监控的完整流程。所有命令均在 Ubuntu 22.04 LTS 上验证,步骤可直接复制粘贴。
3.1 交换机侧:开启 SNMP v2c 并配置只读团体名
登录交换机 CLI,执行以下命令。注意:v2c 是最简方案,生产环境建议升级到 v3(但 v3 配置复杂度高 5 倍,本文聚焦快速验证):
# 进入全局配置模式 Switch> enable Switch# configure terminal # 创建只读团体名 "public-read",限制仅允许来自 192.168.10.0/24 网段访问 Switch(config)# snmp-server community public-read ro 192.168.10.0 0.0.0.255 # (可选)启用 SNMP trap,用于故障通知(虽 Prometheus 不收,但可发给其他系统) Switch(config)# snmp-server host 192.168.10.200 version 2c public-read # 保存配置 Switch(config)# end Switch# write memory验证是否生效:在监控服务器上执行snmpwalk -v2c -c public-read 192.168.10.100 1.3.6.1.2.1.1.1.0,应返回类似SNMPv2-MIB::sysDescr.0 = STRING: Cisco IOS Software [Catalyst L3 Switch Software], Version 17.9.4的结果。若超时,请检查交换机防火墙、网络连通性及 ACL 规则。
提示:很多企业网络默认关闭 SNMP。如果你的交换机返回
Timeout,第一反应不是 exporter 配错了,而是去确认设备侧是否真的开启了 SNMP 服务。我们曾在一个金融客户现场,花 2 小时排查 exporter,最后发现是网络策略禁止了 UDP 161 端口。
3.2 监控服务器侧:安装并配置 snmp_exporter
下载最新版snmp_exporter(截至 2024 年 7 月为0.24.0):
# 创建工作目录 mkdir -p /opt/snmp_exporter && cd /opt/snmp_exporter # 下载并解压(替换 URL 为最新版) curl -L https://github.com/prometheus/snmp_exporter/releases/download/v0.24.0/snmp_exporter-0.24.0.linux-amd64.tar.gz | tar xz # 重命名并赋予执行权限 mv snmp_exporter-0.24.0.linux-amd64 snmp_exporter chmod +x snmp_exporter # 创建配置目录 mkdir -p config生成基础snmp.yml配置(使用官方默认模块):
# 下载默认 generator.yml(用于生成 snmp.yml) curl -L https://raw.githubusercontent.com/prometheus/snmp_exporter/main/generator/generator.yml -o config/generator.yml # 运行 generator(需先安装 Go 环境) # 若未安装 Go,可跳过此步,直接使用预编译的 snmp.yml # ./generator generate为节省时间,我们直接使用社区验证过的snmp.yml(已包含 Cisco、Huawei、H3C 主流厂商模块):
curl -L https://raw.githubusercontent.com/prometheus/snmp_exporter/main/examples/generator/snmp.yml -o config/snmp.yml创建 systemd 服务文件/etc/systemd/system/snmp_exporter.service:
[Unit] Description=SNMP Exporter Wants=network-online.target After=network-online.target [Service] Type=simple User=prometheus Group=prometheus ExecStart=/opt/snmp_exporter/snmp_exporter \ --config.file=/opt/snmp_exporter/config/snmp.yml \ --web.listen-address=:9116 \ --web.telemetry-path=/metrics \ --log.level=info Restart=always RestartSec=10 [Install] WantedBy=multi-user.target启动服务:
# 创建 prometheus 用户(若不存在) sudo useradd --no-create-home --shell /bin/false prometheus # 重载 systemd 配置并启动 sudo systemctl daemon-reload sudo systemctl enable snmp_exporter sudo systemctl start snmp_exporter # 检查状态 sudo systemctl status snmp_exporter验证 exporter 是否正常:curl http://localhost:9116/metrics?module=cisco_ios应返回大量# HELP注释和指标行,而非 404 或空响应。
3.3 Prometheus 侧:添加目标并验证数据拉取
编辑prometheus.yml,在scrape_configs:下新增:
- job_name: 'snmp-cisco' static_configs: - targets: - '192.168.10.100' # 交换机 IP metrics_path: /snmp params: module: [cisco_ios] # 使用 cisco_ios 模块 relabel_configs: - source_labels: [__address__] target_label: __param_target replacement: $1 - source_labels: [__param_target] target_label: instance replacement: $1 - target_label: __address__ replacement: 127.0.0.1:9116 # snmp_exporter 地址关键点解析:
metrics_path: /snmp:snmp_exporter的固定路径,不可改为/metrics。params.module: [cisco_ios]:指定使用cisco_ios模块,该模块已预置 Cisco 设备 OID。relabel_configs:这是 Prometheus 的“地址重写”机制。__address__原本是192.168.10.100,但我们要把它变成snmp_exporter的查询参数?target=192.168.10.100&module=cisco_ios,所以先用__param_target存下,再把__address__改成snmp_exporter的本地地址。
重启 Prometheus:
sudo systemctl restart prometheus访问http://<prometheus-ip>:9090/targets,找到snmp-cisco任务,状态应为UP,Last Scrape 时间在 30 秒内。点击Metrics标签页,输入ifInOctets,应看到类似ifInOctets{instance="192.168.10.100",job="snmp-cisco",ifIndex="1",ifDescr="GigabitEthernet0/0"}的指标。
3.4 Grafana 侧:构建首张端口流量图
在 Grafana 中添加 Prometheus 数据源后,新建 Dashboard,添加 Panel:
- Query:
rate(ifInOctets{instance="192.168.10.100"}[5m]) * 8
(rate()计算每秒字节数,*8转为比特率,单位 bps) - Legend:
{{ifDescr}} (in) - Unit:
bps - Thresholds:设置 Critical 为
1000000000(1Gbps),Warning 为800000000
保存后,你将看到一条实时更新的流量曲线。此时,拔掉交换机GigabitEthernet0/0的网线,曲线应在 30 秒内跌至 0,并触发告警(需配置 Alerting 规则)。
实操心得:首次部署时,90% 的失败源于
relabel_configs配置错误。一个快速验证方法是:在 Prometheus 的Status > Targets页面,点击snmp-cisco任务右侧的Scrape链接,查看原始抓取内容。如果看到snmp_exporter返回no such target,说明__param_target没传过去;如果看到timeout,说明snmp_exporter无法连通交换机。
4. 常见故障排查:从“指标为空”到“OID 不匹配”的全链路诊断
部署顺利是理想状态,现实中更多是“指标为空”、“数据断断续续”、“数值明显异常”。以下是我在 12 个不同客户现场总结的四大高频问题及其诊断链路。
4.1 问题一:Prometheus Targets 页面显示DOWN,Last Error 为context deadline exceeded
这是最表层的症状,但根因分三层:
| 层级 | 检查项 | 验证命令 | 预期结果 | 修复动作 |
|---|---|---|---|---|
| 网络层 | snmp_exporter服务器能否 ping 通交换机 | ping -c 3 192.168.10.100 | 64 bytes from 192.168.10.100 | 检查物理链路、VLAN、防火墙 |
| 协议层 | snmp_exporter能否用 SNMP 协议访问交换机 | snmpget -v2c -c public-read 192.168.10.100 sysUpTime.0 | DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (1234567) 3 days, 11:34:16.70 | 检查交换机 SNMP 配置、团体名、ACL |
| 服务层 | snmp_exporter进程是否在监听 | sudo ss -tuln | grep :9116 | tcp LISTEN 0 4096 *:9116 *:* | 重启snmp_exporter服务 |
关键技巧:snmpget命令比snmpwalk更快,适合快速验证单个 OID。如果snmpget成功但snmpwalk失败,大概率是交换机对bulk请求的支持有问题,此时需在generator.yml中将walk:改为get:,牺牲性能换取稳定性。
4.2 问题二:Targets 显示UP,但ifInOctets等指标在 Prometheus 中查不到
这表明snmp_exporter成功拉到了数据,但没按预期暴露指标。原因集中在snmp.yml配置:
- 模块名不匹配:
prometheus.yml中写的module: [cisco_ios],但snmp.yml里没有cisco_ios模块。检查snmp.yml文件开头是否有modules:,以及其下是否有对应模块名。 - OID 未启用:
cisco_ios模块默认只启用常用 OID。若要监控光模块,需手动添加hwOpticalModuleRxPowerOID 到cisco_ios的walk:列表。 - 正则过滤过严:
regexes:字段可能过滤掉了所有ifIndex。临时注释掉regexes:行,重新加载snmp_exporter,再查指标。
快速定位法:直接访问http://localhost:9116/snmp?target=192.168.10.100&module=cisco_ios,查看返回的原始指标文本。如果里面根本没有ifInOctets,说明是模块或 OID 问题;如果里面有但 Prometheus 查不到,说明是 Prometheus 的relabel_configs或metric_relabel_configs做了二次过滤。
4.3 问题三:指标存在,但数值恒为 0 或突变为极大值(如 2^32)
这是典型的 OID 类型(type)配置错误。snmp_exporter的generator.yml中,type:字段必须与 SNMP 协议定义一致:
Counter32/Counter64→type: counterGauge32/TimeTicks→type: gaugeInteger/Enum→type: gauge
例如sysUpTime是TimeTicks类型,若配成gauge,当计数器溢出(约 49 天后),值会从4294967295突变为0,导致rate()计算出负数。正确做法是配type: counter,rate()会自动处理溢出重置。
验证方法:用snmpget查原始值,对比snmp_exporter输出。若snmpget返回Timeticks: (123456789) 14 days, 6:56:07.89,而snmp_exporter输出sysUpTime 123456789,说明类型正确;若输出sysUpTime 123456789.0(带小数点),说明类型错误,被当成了浮点数。
4.4 问题四:Grafana 图表显示“N/A”,或数据点稀疏(每 5 分钟才一个点)
这指向 Prometheus 的采集间隔(scrape interval)与snmp_exporter的超时设置不匹配。
默认
scrape_interval: 15s,但snmp_exporter对一台设备的bulkwalk可能耗时 800ms。若网络抖动,单次采集超时(默认 10s),Prometheus 就会跳过本次,导致数据点缺失。解决方案:在
prometheus.yml的job_name下增加scrape_timeout:- job_name: 'snmp-cisco' scrape_interval: 30s scrape_timeout: 25s # 必须小于 scrape_interval # ... 其余配置
同时,在snmp_exporter启动参数中增加超时:
ExecStart=/opt/snmp_exporter/snmp_exporter \ --config.file=/opt/snmp_exporter/config/snmp.yml \ --web.listen-address=:9116 \ --timeout=20s \ # snmp_exporter 自身超时 --log.level=info经验数据:对于 48 口交换机,bulkwalk平均耗时 300~600ms;对于 1000+ 端口的核心路由器,可能达 1.5s。务必根据设备规模调整超时,而非盲目设为 10s。
最后一个硬核技巧:当所有常规手段失效,启用
snmp_exporter的 debug 日志。在ExecStart中加入--log.level=debug,然后journalctl -u snmp_exporter -f,你会看到每一行 OID 的查询耗时、返回值、错误堆栈。这是定位“为什么这个 OID 拉不到”的终极武器。
5. 进阶实践:为国产设备定制 OID 模块与自动化生成
当监控华为、H3C、锐捷等国产设备时,官方snmp.yml往往不包含其私有 MIB。此时,generator.yml的定制能力就成为核心竞争力。下面以华为 S5735 的端口光功率为例,展示从 OID 获取到模块上线的全流程。
5.1 第一步:获取设备 MIB 文件与 OID 树
华为官网提供完整的 MIB 包(搜索“华为 MIB 下载”)。下载后解压,找到HUAWEI-IF-EXT-MIB.mib文件。用文本编辑器打开,搜索hwOpticalModuleRxPower,你会看到:
hwOpticalModuleRxPower OBJECT-TYPE SYNTAX INTEGER (-4000..2000) MAX-ACCESS read-only STATUS current DESCRIPTION "The optical module receive power." ::= { hwOpticalModuleEntry 10 }再找它的父节点hwOpticalModuleEntry:
hwOpticalModuleEntry OBJECT-TYPE SYNTAX SEQUENCE { hwOpticalModuleIfIndex INTEGER, hwOpticalModuleRxPower INTEGER, ... } MAX-ACCESS not-accessible STATUS current DESCRIPTION "An entry in the optical module table." INDEX { hwOpticalModuleIfIndex } ::= { hwOpticalModuleTable 1 }继续向上,找到hwOpticalModuleTable的 OID:
hwOpticalModuleTable OBJECT-TYPE SYNTAX SEQUENCE OF HwOpticalModuleEntry MAX-ACCESS not-accessible STATUS current DESCRIPTION "The optical module table." ::= { hwOpticalModule 1 }最终,hwOpticalModuleRxPower的完整 OID 是1.3.6.1.4.1.2011.5.25.31.1.1.1.1.10,索引 OID 是1.3.6.1.4.1.2011.5.25.31.1.1.1.1.1(hwOpticalModuleIfIndex)。
5.2 第二步:编写 generator.yml 片段并生成 snmp.yml
在config/generator.yml的modules:下新增:
huawei_optical: walk: - 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.1 # hwOpticalModuleIfIndex - 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.10 # hwOpticalModuleRxPower - 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.11 # hwOpticalModuleTxPower metrics: - name: hwOpticalModuleRxPower oid: 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.10 type: gauge help: Optical module receive power in 0.01dBm. indexes: - labelname: ifIndex type: gauge oid: 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.1 - name: hwOpticalModuleTxPower oid: 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.11 type: gauge help: Optical module transmit power in 0.01dBm. indexes: - labelname: ifIndex type: gauge oid: 1.3.6.1.4.1.2011.5.25.31.1.1.1.1.1注意help字段中的单位:华为返回的是0.01dBm,即数值1234表示12.34dBm。因此 Grafana 查询时需除以 100:hwOpticalModuleRxPower{instance="192.168.10.100"} / 100。
5.3 第三步:自动化生成与 CI/CD 集成
手动运行generator效率低。我们将其集成到 GitOps 流程中:
- 将
generator.yml托管在 Git 仓库; - 每次提交后,触发 GitHub Actions;
- Action 中安装 Go,运行
make build,生成新snmp_exporter和snmp.yml; - 通过 Ansible 将新二进制和配置推送到所有监控节点。
这样,当网络团队新增一台锐捷设备,只需在generator.yml中添加ruijie_if模块,提交代码,10 分钟后全网监控就自动支持。
我个人的经验是:不要试图维护一个“大而全”的
snmp.yml。按厂商、按设备型号拆分成huawei_s5735.yml、h3c_s5130.yml等小文件,用generator的include:功能合并。这样,修改一个厂商配置,不会影响其他厂商的稳定性。我们在某省级政务云项目中,用此方法管理 17 个品牌、83 种型号的网络设备,三年未因配置变更引发一次监控中断。
6. 生产环境加固:安全、高可用与长期运维要点
当监控从 PoC 进入生产,安全与稳定性成为首要考量。以下是经过 5 个大型项目验证的加固清单。
6.1 安全加固:从明文团体名到 TLS 双向认证
SNMP v2c 的团体名(community string)本质是明文密码,网络抓包即可获取。生产环境必须升级:
SNMP v3:支持用户认证(MD5/SHA)和加密(DES/AES)。在交换机上配置:
# 创建用户 testuser,认证密码 authpass,加密密码 privpass snmp-server user testuser groupname v3 auth md5 authpass priv aes 128 privpass在
generator.yml中,模块需指定version: 3和凭据:modules: huawei_v3: version: 3 auth: username: testuser password: authpass auth_protocol: md5 priv_password: privpass priv_protocol: aes walk: [...]snmp_exporter TLS:为
snmp_exporter的/metrics接口启用 HTTPS,防止指标被窃听。需在启动参数中加入--web.config.file=web-config.yml,