是的,可以非常明确地说:这个“metric 决定同表路由优先级”的机制在 Linux 内核里是🟢极其成熟、稳定、不会出幺蛾子的。你完全不需要担心它本身的稳定性。
下面我从**内核实现历史、稳定性边界、什么时候会“失效”**三个层面给你一个工程级结论。
一、这是 Linux 路由里「最老、最稳」的一条规则之一
1️⃣ metric 的历史地位
-
metric机制 从 Linux 2.x 时代就存在 -
早于:
- policy routing(
ip rule) - netfilter/iptables
- Kubernetes / CNI
- policy routing(
可以说:
metric 是 Linux FIB(转发表)最基础的排序字段之一
几十年内核版本里:
- 行为 几乎没有语义变化
- 只是在内部数据结构上优化过(hash / trie / fib_info)
二、内核里是“硬编码语义”,不是“策略插件”
内核的选路逻辑(简化)
在 同一个 routing table 内:
- 最长前缀
- metric(数值小者胜)
- ECMP(metric 相同)
这是写在内核路由查找路径里的 固定顺序:
- 不依赖模块
- 不依赖 sysctl
- 不依赖用户态守护进程
👉 只要路由存在,行为必定如此
三、你这种用法是「教科书级别」
你现在做的是:
main 表:
default via net1 metric 100 ← 主
default via net2 metric 200 ← 备
这是:
- 多出口服务器
- 云主机
- NAT 网关
- 防火墙
- 路由器
每天在全球无数 Linux 设备上运行的模式
四、什么情况下“会出问题”?(和 metric 本身无关)
❌ 不是 metric 不稳定,而是「路由条目没变」
内核只关心:
“这条 route 在不在?”
它不会主动判断:
- 网关是否能 ping
- 上游是否黑洞
- NAT 是否成功
所以:
| 场景 | 结果 |
|---|---|
| net1 default 存在,但网关不通 | ❌ 不会自动切到 net2 |
| net1 interface up,但上游断 | ❌ 仍选 net1 |
| net1 route 被删除 / iface down | ✅ 自动走 net2 |
👉 这是设计如此,不是 bug
五、工程上“真正需要注意”的三点(非常现实)
1️⃣ 谁在改你的路由?
在你的环境里:
global-snat-gw- kube-ovn
- CNI / controller
都可能会重写 main 表
🔎 你已经注意到 metric 0 默认出现,这很可能就是 controller 行为。
解决方案不是担心 metric,而是确认“写路由的权威是谁”
2️⃣ 已建立连接(conntrack)
metric 只影响 新建连接:
- 已有 NAT / conntrack 流
- 不会被“平滑迁移”
这在 SNAT 网关上是常态,不是问题。
3️⃣ 持久化问题(比稳定性更现实)
ip route是运行时状态- 容器 / Pod 重启就没
工程上要做的是:
- entrypoint 脚本
- initContainer
- systemd-networkd / netplan
- 或 CNI 配置层
六、可以给你一个「非常硬核的稳定性背书」
metric 优先级是 Linux 路由系统里,
比 iptables 还稳定、
比 policy routing 更“底层”、
比任何 CNI 更“不可替代”的机制。
你担心它,反而说明你是在用它做关键路径 ——这是对的。
七、给你一个“是否可放心使用”的判断标准
你可以放心使用 metric,只要满足这三点:
- ✅ 所有 default 路由在 同一个 routing table
- ✅ metric 明确指定(不用 0)
- ⚠️ 确认 kube-ovn 不会反复覆盖
在你当前的描述下,完全满足。
八、下一步我建议你做的不是“再验证 metric”,而是这个
如果你愿意,我更建议下一步做:
- 🔍 确认 kube-ovn 是否周期性重写 default
- 🧪 用
ip monitor route跑 5 分钟看有没有变动 - 🛡️ 必要时做一个“路由守护脚本”
我可以直接给你一个 10 行以内的 route-guard 脚本,专门保证:
“net1 metric 100 + net2 metric 200 永远存在”
你要的话我就直接贴。