前言
tc(traffic control)是Linux内核中的一个网络流量控制工具,它可以用来控制网络流量的带宽、延迟、丢包等参数,从而实现网络流量的优化和管理。详细介绍可以参考Linux TC工具的官方文档和man手册。而qdisc (queueing disciplines), 是tc工具中的一部分,叫做队列规则,是一种可以定义Linux网络流量队列规则的一种机制,可以进行流量排队、调度以及限速等操作,达到对网络流量的精细控制和管理。如下是几个qdisc的例子:
限制网络带宽:限制某个IP地址或端口号的带宽,防止其占用过多的网络资源。
提高响应速度:对某个端口号的网络流量进行优先处理,提高其响应速度。
减少网络拥塞:对某个协议的网络流量进行延迟处理,减少网络拥塞。
防止网络攻击:对某个IP地址的网络流量进行丢包处理,防止其对网络安全造成威胁。
流量分类限速:对不同的网络流量进行分类和限速,实现网络质量保障。
概述
qdisc (queue disciplines) 其实是 egress traffic control 和 qos 相关的问题而不是 TCP 的拥塞控制问题,下图是一个简化版的 egress 架构,
网络设备或多或少都有 buffer,初衷是以增大少许延迟来避免丢包,然而 buffer 的存在所导致的延迟可能干扰 TCP 对链接质量的判断,buffer 最终被塞满,丢包不可避免,反而新引入了延迟波动问题,这一现象被称为 bufferbloat,网络开发者们一直致力于研究更好的 qdisc 算法,避免 buffer bloat 带来的影响,这些有基于分类的算法也有无分类算法,其中分类算法最简单的实现有 prio HTB CBQ 等,无分类有 pfifo pfifo_fast tbf 等,针对 bufferbloat 的改进算法有 tail-drop red blue codel 等,其中:
• pfifo_fast 是众多发行版的默认参数,它实现简单,很多网卡可以 offload 而减少 CPU 开销,但它默认队列过长很容易引起 bufferbloat,不能识别网络流可能导致部分流被饿死
• fq (fair queue) 针对了 pfifo 及其衍生算法的缺点,它将每个 socket 的数据称为一个流,以流为单位进行隔离,分别进行 pacing 以期望得到公平发送的效果
• codel 是一种针对 bufferbloat 设计的算法,使用 BQL 动态控制 buffer 大小,自动区分“好流”和“坏流”,fq_codel 对非常小的流进行了优化避免饿死问题
• cake 是 codel / fq_codel 的后继者,内建 HTB 算法进行流量整形而克服了原版 HTB 难以配置的问题,号称能做 fq_codel 能做的一切且比 fq_codel 做得更好,在 4.19 中被引入内核
一个比较笼统但通俗的解释是:终端设备(内容的生产者或最终接收者,而不是转发设备)的 qdisc 更适合 fq,转发设备更适合 codel 及其衍生算法,根据一些不完全的实践,bbr 配合 fq_codel 工作的很好,cake 理论上可作为 fq_codel 的替代,但是目前没有太多实践资料可供参考。
pfifo_fast
pfifo_fast有3个队列(0,1,2)。这三个队列有一定规则约束:
每个队列都执行FIFO策略
优先级: 队列0>队列1>队列2,即如果队列0有数据包未处理,不会去处理队列1中的数据,同理,如果队列1中有数据包未处理,队列2中的数据包就不会被处理。(从这里可以看出,严格按定义来说,pfifo_fast 属于有类别排队规则(classful),因为它内部包 含了三个 队列,而这些 队列 实际上是有区别的。但从用户配置的视角来说,它是 classless 的,因为这三个内部 class 用户是无法通过 tc 命令配置的。)
内核程序会检测每个数据包的TOS字段,将最小延迟的包放到队列1中
用法
pfifo_fast qdisc是在代码里写死的,没办法更改它的配置。
priomap
priomap决定了如何将内核设置的packet priority数据包放到哪个队列。这个priority位于TOS字段
txqueuelen
发送队列长度,是一个网络接口(interface)参数,可以用 ifconfig 命令设置。例如,ifconfig eth0 txqueuelen 10。tc命令无法修改该参数值