Skip to content

把数据接出去:flowprobe 与 Prometheus

前面几篇讲了该看哪些计数器、怎么读 trace。但那些都是人坐在 CLI 前的操作。 生产环境需要的是把数据持续接到监控系统里。

这一篇讲两条出口,顺便回答第 4 章留下的一个问题: DET44 免掉了会话日志,那确实需要流日志的时候用什么?

flowprobe:IPFIX 流导出

IPFIX 是 NetFlow 的标准化后继,用来把"谁和谁通信了多久多少字节"导出给采集器。

bash
# 1. 先配导出目标
set ipfix exporter collector <采集器IP> src <本机IP> [template-interval <>]

# 2. 配记录哪些层、两个定时器
flowprobe params record [l2] [l3] [l4] [active <>] [passive <>]

# 3. 挂到接口
flowprobe feature add-del <> [l2|ip4|ip6] [rx|tx|both] [disable]

show flowprobe params / feature / table / statistics

不配 exporter 就一条流都不记

这个坑没有任何提示。flowprobe feature add-del 会成功, show flowprobe feature 也显示挂上了,但:

bash
vppctl show flowprobe table
text
Dumping IPFIX table
                          ← 空的

show flowprobe statisticsPool utilisation 一直是 0%。

配上 set ipfix exporter 之后,流记录立刻开始出现。

应用配置

bash
./labctl reset base
./labctl apply base 18
./labctl verify base 18

配好之后:

bash
./labctl vppctl base show flowprobe table
text
Dumping IPFIX table
 rx 1/0 ... 203.0.113.1 -> 203.0.113.11 6 43665 9000
 rx 1/0 ... 203.0.113.1 -> 203.0.113.11 1 0 0

两条流:TCP(协议 6,端口 43665→9000)和 ICMP(协议 1)。

一个必须知道的细节:它记的是 NAT 之后的地址

上面那条记录的源地址是 203.0.113.1 —— NAT 转换后的公网地址, 尽管 flowprobe 挂的是内网口的入向

原因在 feature arc 上:

bash
./labctl vppctl base show interface features host-eth1
text
ip4-unicast:
  ip4-sv-reassembly-feature
  nat-pre-in2out
  flowprobe-input-ip4        ← 排在 NAT 后面

flowprobe-input-ip4 排在 nat-pre-in2out 之后

这对采集侧影响很大

text
  你的 IPFIX 收集器看到的是**公网侧的五元组**,
  而不是"哪台内网主机干的"。

想把流量归因到具体用户,还得把 flowprobe 的记录和 NAT 的会话表 (或者 DET44 的算法)对起来 —— 两份数据在时间上还得对齐。

这正好解释了第 4 章那句话:DET44 免掉的是"会话映射日志",不是"全部日志"。 你仍然需要流日志来知道用户访问了哪里,只是不再需要日志来回答 "这个公网端口是谁"。

对照一下两种方案:

text
  ┌──────────────────┬────────────────────┬──────────────────────┐
  │                  │ 传统 NAT + 流日志    │ DET44 + 流日志        │
  ├──────────────────┼────────────────────┼──────────────────────┤
  │ 端口 → 用户       │ 查会话日志(TB 级)  │ 一条命令算出来         │
  │ 用户访问了哪里     │ 查流日志            │ 查流日志(同样需要)    │
  │ 存储量           │ 会话日志 + 流日志    │ 只有流日志            │
  └──────────────────┴────────────────────┴──────────────────────┘

两个定时器

bash
vppctl show flowprobe params
text
 l3 l4 active: 10 passive: 30
text
  active   长流每隔多久导出一次中间记录
  passive  流静默多久后判定结束并导出最终记录

active 太长,长连接的流量要很久才反映到监控里;太短则导出报文量暴增。 生产上常见 60s / 15s 这个量级。

Prometheus:把全部统计暴露成 HTTP 端点

VPP 的 prom 插件把内部统计以 Prometheus 格式吐出来。

bash
# 1. 启动 HTTP 服务(注意 uri 必须在第一次调用时就给)
http static server www-root /tmp/www uri tcp://0.0.0.0/80 url-handlers

# 2. 打开 prometheus 导出
prom enable

# 端点:http://<VPP接口地址>/stats.prom

两个坑,都会让人卡很久

一、http static server 的 uri 必须在第一次调用时给。

如果先执行了不带 uri 的版本:

bash
vppctl http static server url-handlers          # 少了 uri
vppctl http static server ... uri tcp://0.0.0.0/80 ...
text
http static server: http static server already initialized...

改不了,只能重启 VPP。

二、这个 HTTP 服务跑在 VPP 自己的 host stack 上,不是容器/主机的内核栈。

所以:

bash
docker exec <> ss -lnt | grep :80       # 什么都看不到
docker exec <> curl http://127.0.0.1/stats.prom   # Connection refused

必须从别的节点,用 VPP 的接口地址访问

bash
docker exec clab-natbase-s1 python3 -c "
import urllib.request
print(urllib.request.urlopen('http://203.0.113.1/stats.prom').read().decode()[:200])
"

我在这上面卡了几轮 —— 一直以为服务没起来, 直到从外部访问收到一个 HTTP 404(而不是连接拒绝), 才意识到服务其实在跑,只是路径写错了、而且不能从本机 loopback 访问。

"404 而不是 connection refused"是个很有价值的信号: 它说明网络这一层是通的,问题在应用层。

抓到的内容:

text
# TYPE vpp_sys_heartbeat counter
vpp_sys_heartbeat 5.00
# TYPE vpp_sys_last_stats_clear counter
vpp_sys_last_stats_clear 0.00
# TYPE vpp_sys_boottime counter
vpp_sys_boottime 1788509264.00

标准的 Prometheus 文本格式,可以直接被 scrape。

一次全量抓取 1.8 MB

生产上必须筛选

VPP 把所有统计都吐出来 —— 每个接口每个方向的每个计数器。 本实验环境只有 3 个接口,一次抓取就接近 1.8 MB。

几百个接口的设备一次能到几十 MB,Prometheus 那边的存储和查询都会很难看。

bash
vppctl prom patterns add <>      # 只导出匹配的指标
vppctl prom enable used-only         # 只导出非零的
vppctl prom patterns show            # 看当前筛选规则
vppctl prom enable min-scrape-interval <>   # 限制抓取频率

used-only 是最省事的一刀 —— 大量计数器恒为零,导出它们纯属浪费。

该监控什么

结合第 7 章的故障签名,最值得接进告警的:

text
  ┌────────────────────────────┬────────────────────────────────┐
  │ 指标                        │ 为什么重要                       │
  ├────────────────────────────┼────────────────────────────────┤
  │ NAT 会话数 / 上限            │ 逼近上限时新连接开始失败           │
  │ out of ports 计数           │ 地址池耗尽,已经在影响用户          │
  │ maximum sessions exceeded  │ 会话表满                        │
  │ no translation 计数增速     │ 突然加速通常是会话老化误伤          │
  │ ACL deny 计数               │ 突增可能是策略配错或遭遇扫描        │
  │ 各接口的 drop 计数           │ 任何非零都值得看一眼               │
  │ Vectors/Call               │ 持续为 1 说明收包路径有问题         │
  └────────────────────────────┴────────────────────────────────┘

取差值,不要取绝对值

show errors 和 Prometheus 导出的都是累计值。 告警规则要基于增长速率,不是绝对数字 —— 一台跑了半年的设备累计几百万个 no translation 完全正常 (背景扫描),但每秒新增几百个就是事故。

小结

flowprobeIPFIX 流导出,答"用户访问了哪里"
前置条件必须先 set ipfix exporter,否则一条不记且无提示
位置arc 上排在 NAT 之后 → 记的是转换后的地址
定时器active(长流中间记录)/ passive(流结束判定)
Prometheushttp static server ... uri ... + prom enable,端点 /stats.prom
坑一http static server 的 uri 必须首次调用就给,否则只能重启 VPP
坑二跑在 VPP host stackss 看不到,不能从 127.0.0.1 访问
生产必做prom patterns / used-only 筛选,否则一次抓取几十 MB
告警原则增长速率,不取累计绝对值

实验环境基于 netlab + containerlab + VPP 26.06