主题
实验 17:QoS 与限速
OVS 提供两套限速机制,方向不同、原理不同、效果差别很大:
| ingress policing | QoS + Queue | |
|---|---|---|
| 方向 | 入向(进入交换机) | 出向(离开交换机) |
| 原理 | 令牌桶,超了就丢 | 分层令牌桶,超了就排队 |
| 配在哪 | Interface 表 | Port → QoS → Queue |
| 能分级 | 不能 | 能(多个队列) |
| 配置难度 | 一条命令 | 需要三张表 |
| TCP 实测速率 | 明显低于配置值 | 接近配置值 |
最后一行是这一章最值得记住的结论,下面会用实测数据说明。
起环境
bash
cd labs/learn-ovs/14-qos
./start.shtext
h1 ── ovs1 ── h2
.1 br0 .2
iperf3 -sstart.sh 会先测一个基线:
text
[ 5] 0.00-3.00 sec 3.22 GBytes 9224 Mbits/sec receiver9224 Mbit/s —— 这是容器之间 veth 的裸速度,后面所有限速效果都跟它对比。
方案一:ingress policing
最简单的限速,一条命令:
bash
N="docker exec clab-qos-ovs1"
$N ovs-vsctl set Interface eth1 ingress_policing_rate=20000
$N ovs-vsctl set Interface eth1 ingress_policing_burst=2000| 字段 | 单位 | 含义 |
|---|---|---|
ingress_policing_rate | kbit/s | 平均速率上限。20000 = 20 Mbit/s |
ingress_policing_burst | kbit | 允许的突发量。一般设成 rate 的 10% |
ingress_policing_kpkts_rate | kpps | 按包速率限(可选) |
单位是 kbit/s,不是 bit/s
ingress_policing_rate=20000 是 20 Mbit/s。写成 20000000 会变成 20 Gbit/s,等于没限速 —— 这是最常见的配置错误。
注意 Queue 表的 max-rate 单位是 bit/s,两处不一样,很容易搞混。
实测:
bash
docker exec clab-qos-h1 iperf3 -c 192.168.10.2 -t 5 -f mtext
[ 5] 0.00-5.00 sec ... 11.9 Mbits/sec receiver配置 20 Mbit/s,实测只有 11.9 Mbit/s —— 差了四成。
为什么打不满
policing 的做法是超速就丢包。TCP 一遇到丢包就认为网络拥塞,立刻把发送窗口砍半,然后慢慢爬升。爬到接近限速值又开始丢包,再砍半 —— 于是平均吞吐远低于配置值。
text
带宽
│ ╱╲ ╱╲ ╱╲ ← 每次撞到限速就丢包
20 ├─ ─ ─╱─ ╲─ ─ ╱─ ╲─ ─ ╱─ ╲─ ─ ← 配置的 20 Mbit/s
│ ╱ ╲ ╱ ╲ ╱ ╲
12 ├ ─ ╱ ─ ─ ─╲╱ ─ ─ ─ ╲╱ ─ ─ ─╲─ ─ ← 实际平均只有 12
│ ╱
└──────────────────────────────▶ 时间policing 适合限制不守规矩的流量(比如防 UDP 洪泛),不适合给 TCP 业务做带宽保证。
方案二:QoS + Queue
出向限速,用 Linux 的 HTB(分层令牌桶)。它涉及三张 OVSDB 表:
text
Port(eth2)
└─ qos ──▶ QoS (type=linux-htb, max-rate=100M)
├─ queues:0 ──▶ Queue (max-rate=10M)
└─ queues:1 ──▶ Queue (max-rate=50M)配置命令(和实验 12 的 Mirror 一样要用 @ 符号):
bash
$N ovs-vsctl \
-- set Port eth2 qos=@newqos \
-- --id=@q0 create Queue other-config:max-rate=10000000 \
-- --id=@q1 create Queue other-config:max-rate=50000000 \
-- --id=@newqos create QoS type=linux-htb \
other-config:max-rate=100000000 \
queues:0=@q0 queues:1=@q1Queue 的单位是 bit/s
max-rate=10000000 是 10 Mbit/s(10 的 7 次方 bit/s)。
和 ingress_policing_rate 的 kbit/s 不一样。配之前先确认单位。
常用的 Queue 参数:
| 参数 | 含义 |
|---|---|
max-rate | 速率上限(bit/s) |
min-rate | 保证的最低速率。总和不能超过 QoS 的 max-rate |
priority | 优先级,数字小的先发 |
burst | 突发量 |
用流表选队列
配好队列还不够 —— 得告诉 OVS 哪些流量走哪个队列:
bash
$N ovs-ofctl add-flow br0 \
"priority=100,ip,nw_src=192.168.10.1,actions=set_queue:1,NORMAL"set_queue:N 决定这个包用几号队列。不设的话走 0 号队列(也叫 Default 队列)。
这是 QoS 真正强大的地方:队列的选择可以基于任意流表匹配条件 —— 源 IP、目的端口、VLAN、DSCP,什么都行。
实测
先把 ingress policing 关掉,只留 HTB:
bash
$N ovs-vsctl set Interface eth1 ingress_policing_rate=0 ingress_policing_burst=0走 queue 1(上限 50 Mbit/s):
text
[ 5] 0.00-5.02 sec 29.8 MBytes 49.7 Mbits/sec receiver改成走 queue 0(上限 10 Mbit/s):
bash
$N ovs-ofctl mod-flows br0 \
"priority=100,ip,nw_src=192.168.10.1,actions=set_queue:0,NORMAL"text
[ 5] 0.00-5.13 sec 6.00 MBytes 9.81 Mbits/sec receiver对比一下三组数据:
| 机制 | 配置值 | 实测 | 达成率 |
|---|---|---|---|
| ingress policing | 20 Mbit/s | 11.9 | 60% |
| HTB queue 1 | 50 Mbit/s | 49.7 | 99% |
| HTB queue 0 | 10 Mbit/s | 9.81 | 98% |
shaping(排队)几乎精准命中,policing(丢包)大幅低于配置值。
因为 HTB 超速时是把包排进队列慢慢发,不丢包。TCP 感知到的是延迟增加而不是丢包,不会触发拥塞退避,所以能稳定跑在限速值附近。
结论
- 要给业务做带宽保证 → 用 QoS + Queue(shaping)
- 要压制滥用流量 → 用 ingress policing(policing)
给 TCP 业务配 policing 然后抱怨"限速 100M 只跑到 60M",是很常见的误用。
看队列统计
bash
$N ovs-appctl qos/show eth2text
QoS: eth2 linux-htb
max-rate: 100000000
Default:
burst: 76512
min-rate: 76000
max-rate: 10000000
tx_packets: 3
tx_bytes: 210
Queue 1:
burst: 76512
min-rate: 76000
max-rate: 50000000
tx_packets: 825
tx_bytes: 7622925tx_packets 直接证明 set_queue 生效了:825 个包走了 Queue 1,Default 只有 3 个(那是没被流表规则匹配到的零散流量)。
排查"限速没生效"时,先看这里 —— 如果流量都进了 Default 队列,说明 set_queue 的流表规则没命中。
min-rate:带宽保证
max-rate 是上限,min-rate 是保证值:
bash
-- --id=@q0 create Queue other-config:min-rate=30000000 \
other-config:max-rate=100000000
-- --id=@q1 create Queue other-config:min-rate=70000000 \
other-config:max-rate=100000000含义是:
- 链路空闲时,任一队列都能跑到 100 Mbit/s
- 链路拥塞时,queue 0 至少能拿到 30 Mbit/s,queue 1 至少 70 Mbit/s
所有队列的 min-rate 之和不能超过 QoS 的 max-rate,否则保证无法兑现,OVS 会按比例缩减。
这是"共享带宽但保底"的标准做法,比单纯设上限灵活得多。
Meter:OpenFlow 标准的限速
除了上面两种 OVS 特有的机制,OpenFlow 1.3 还定义了 Meter:
bash
# 建一个 meter:超过 10000 kbit/s 就丢
$N ovs-ofctl -O OpenFlow13 add-meter br0 \
"meter=1,kbps,band=type=drop,rate=10000"
# 流表里引用它
$N ovs-ofctl -O OpenFlow13 add-flow br0 \
"priority=100,ip,actions=meter:1,NORMAL"
# 看统计
$N ovs-ofctl -O OpenFlow13 meter-stats br0Meter 的优势是标准化,控制器可以跨厂商下发。但它的 band 类型只有 drop 和 dscp_remark,本质上还是 policing,同样有 TCP 打不满的问题。
需要 shaping 就用 QoS + Queue。
清理
bash
$N ovs-vsctl clear Port eth2 qos
$N ovs-vsctl set Interface eth1 ingress_policing_rate=0 ingress_policing_burst=0QoS 和 Queue 记录不会自动删干净
clear Port eth2 qos 只解除引用。QoS 和 Queue 是强引用表,记录会留下来变成孤儿:
bash
$N ovs-vsctl list QoS # 还在
$N ovs-vsctl list Queue # 还在彻底清理要用:
bash
$N ovs-vsctl -- --all destroy QoS -- --all destroy Queue长期反复配 QoS 的机器上,孤儿记录会越积越多。
自动检查
bash
./verify.shtext
[通过] eth1 配了 ingress policing
[通过] eth2 挂了 QoS
[通过] 存在 set_queue 的流表规则
[通过] 限速后仍然连通
== 实测限速效果(h1 → h2,入向限 20 Mbit/s)==
实测接收速率: 12.2 Mbit/s
[通过] 速率被限制在 30 Mbit/s 以下自测清单
- ingress policing 和 QoS+Queue 分别作用在哪个方向?
ingress_policing_rate和Queue.max-rate的单位分别是什么?- 为什么 policing 下 TCP 跑不满配置的速率?
- 配好队列之后还需要做什么,流量才会进指定队列?
- 不设
set_queue的流量走哪个队列? max-rate和min-rate有什么区别?- 排查"限速没生效"该先看什么?
常见问题
限速完全没效果
按顺序查:
bash
# 1. 单位对吗(kbit/s vs bit/s)
ovs-vsctl get Interface eth1 ingress_policing_rate
# 2. QoS 挂到 Port 上了吗
ovs-vsctl get Port eth2 qos
# 3. 流量进了哪个队列
ovs-appctl qos/show eth2第 3 步最有用:如果 tx_packets 全在 Default 队列,说明 set_queue 的流表规则没命中。
限速生效了但达不到配置值
用的是 policing。TCP 场景下这是预期行为,换成 QoS + Queue。
限速方向搞反了
ingress_policing_* 限的是进入交换机的流量,配在流量源头那个接口上。 QoS 限的是离开交换机的流量,配在流量出口那个接口上。
想限制 h1 的上传:配 eth1 的 ingress policing,或者配 eth2 的 QoS。
报错 constraint violation
min-rate 之和超过了 QoS 的 max-rate。调小 min-rate 或调大总的 max-rate。
list QoS 里有一堆用不到的记录
孤儿记录。清理:
bash
ovs-vsctl -- --all destroy QoS -- --all destroy Queue注意这会删掉所有 QoS 配置,生产环境上先确认没有正在用的。
小结
- 两套机制方向相反:
ingress_policing管入向,QoS + Queue管出向 - 单位不同:policing 是 kbit/s,Queue 的
max-rate是 bit/s - policing 靠丢包,TCP 会退避,实测明显低于配置值(实测 20M 只跑到 12M)
- shaping 靠排队,实测接近配置值(50M 跑到 49.7M,10M 跑到 9.81M)
- 给业务做带宽保证用 shaping,压制滥用流量用 policing
- QoS 涉及
Port → QoS → Queue三张表,用@符号一个事务建好 - 配好队列后还要用
set_queue:N把流量指过去,否则全走 Default ovs-appctl qos/show的tx_packets是排查的第一站min-rate是保证值,总和不能超过 QoS 的max-rateclear Port qos会留下孤儿记录,用--all destroy彻底清理
下一章:实验 18:外部控制器。