「智能队列」如何改善你的家庭网络质量

在无线路由器的设置页面上,我们可能会看到一个名为「智能队列」的功能(根据品牌或操作系统的不同,也可能会被称做「智能 QoS」、「SQM」等)。

这一功能是如何工作的?是否能让网速变快?是否需要打开?本文将尝试解答这些问题。

从「网络如何连接」说起

本章节主要介绍计算机网络的基础知识。如果读者已经熟悉相关知识,可跳过这部分内容。

在介绍「智能队列」之前,先来了解一下基础的网络知识。

两台电脑间进行数据传输,存在两种方式,分别是电路交换分组交换

对于电路交换,两台电脑独占一条线路进行数据传输。过去的固定电话,大多使用的就是电路交换。

由于独占一条线路,两台设备之间的通信较为稳定,很难出现数据丢失、数据传输顺序错乱等情况。但一条线路只能供一组电脑使用,另外一组电脑想要通信,就不能复用原来的线路了。

对于分组交换,传输的数据被拆分为小段,每一小段叫做一个数据包(报文)。数据以报文的形式进行转发,从而实现了多组电脑复用一条线路进行通信。

分组交换示意图

电路交换虽然能保证数据传输的稳定性,但由于独占线路浪费太多资源,所以在 Internet 中,使用的是分组交换

分组交换将数据拆分成一个一个的小片段来转发,没有独占线路。如果网络条件不好(例如同时有大量报文经过路由器,超出了路由器的处理能力),很有可能遇到数据顺序错乱、甚至数据丢失等情况。那么,这些情况应该如何避免?

  • 在微信视频通话电视直播等应用中,报文的丢失或乱序,只会造成视频图像卡顿,不会造成太严重的影响。所以这些应用会使用简单的 UDP 协议,不考虑丢包、乱序
  • 网页浏览文件下载等应用中,一般使用基于 TCPHTTP 协议。TCP 在报文中携带序号,避免乱序;同时提供了报文的丢失重传机制,避免了丢包。所以,也可以认为 TCP 为两台电脑的应用程序建立了一个虚拟的「连接」。(最新版本的 HTTP/3 协议,使用的则是 QUIC。QUIC 虽然基于 UDP,但引入了与 TCP 类似的报文丢失重传机制)

如果想要了解更多网络基础知识,推荐阅读「入网指南」系列文章:

网络延迟:影响上网体验的重要因素

带宽延迟,是影响上网体验的两大因素。

带宽指的是在单位时间内,网络最多能传输多少数据。

网络的带宽水管的粗细有着很多相似之处,水管越粗,相同时间流出的水越多;同样地,网络带宽越大,相同时间能够传输的数据越多。

在日常上网过程中,大的带宽能带来这些好处:

  • 上传、下载文件的速度更快
  • 在线看视频时,缓冲的时间更短
  • 如果家中有多个人同时上网,大的带宽能够保证每个人都能流畅上网,相互的影响更小

对于家庭宽带,我们常常听到的 10 兆、50 兆、100 兆、千兆,就是指的带宽的大小。

带宽 示意图

延迟指的是数据从网络的一端到达另一端,所需要的时间。

过大的延迟也会对上网体验带来不好的影响,例如:

  • 在浏览器中输入网址敲回车后,需要等更长的时间,网页才能加载
  • 视频聊天、语音通话质量变差,甚至能直接感受到声音、画面的滞后
  • 玩在线游戏时,发现游戏变慢

在很多时候,延迟相比带宽更容易被人感知,对网络体验的影响更大。

是什么导致了网络延迟?

上文中介绍过,Internet 使用的是分组交换。如果大家阅读过计算机网络相关的书籍,应该对分组交换的「存储-转发」机制有一定的印象。

简单说,「存储-转发」是指网络设备将收到的报文存储在缓冲区,然后再发送。

这是由于网络设备的性能有限,转发报文有速率限制。如果设备短时间内收到大量报文,一时半会儿处理不过来,就可以先报文存起来,空闲时慢慢发送。通过「存储-转发」,能够提高网络设备的吞吐量,更充分地利用带宽

其中,存储报文缓冲区,是一个先进先出队列那么,队列的长度应该如何确定?是不是队列越长,能够存储的报文越多,网络的性能就越好?大家可以先思考下这个问题。

其实在过去,内存价格比较昂贵,考虑到成本,网络设备的队列不会太大。现在,随着内存价格的下降,网络设备拥有了更大的队列。

但是,网络的带宽是有限的。实际的可用带宽,取决于数据传输路径上的最小带宽。这个最小带宽也被称做带宽上的「瓶颈」(bottleneck)。

bottleneck 示意图

由于瓶颈的存在,如果流量长时间以较大速率发送,大的队列并不能显著提升吞吐量。相反,大量报文滞留在队列中,会带来延迟的增大

这种队列中缓存有大量报文,来不及发送,导致数据传输延迟增大的现象,被称做 bufferbloat(缓冲区膨胀)。

bufferbloat 示意图

DSLReport 提供的测速服务,能够检测网络的 bufferbloat 程度。不过由于没有中国大陆服务器,测试结果不够准确。国外的读者可以尝试一下:

家用无线路由器中的 QoS 功能

在「智能队列」出现之前,很多家用路由器已经提供了 QoS 功能。那么,传统的 QoS 如何解决网络延迟、网络拥堵?存在哪些不足之处?

在了解这个问题之前,先来熟悉一下网络中的报文,是什么样子的:

在网络中传输的报文,一般包括了链路层、网络层、传输层、应用层这四层信息。其中,网络层的源 IP 地址目的 IP 地址协议号,和传输层的源端口号目的端口号,是 QoS 算法中常常会关注的五个信息。这些信息合称「五元组」。

同一个应用在同一时间段内,传输的报文中,这些信息一般是不会发生变化的。例如观看在线视频时,同一个视频的所有报文 ,一般拥有相同的五元组信息。所以,通过五元组,我们能够区分不同应用的流量。

五元组 示意图

特别地,一些常见的应用,会使用固定的端口号。例如网页浏览一般使用 80、443 端口;英雄联盟游戏,使用的是 5000-5500 端口……

所以,当我们想要提升英雄联盟游戏的体验时,在路由器上设置让 5000-5500 端口的报文优先通过即可:


家用路由器中常见的 QoS 功能,就是通过手动设置 IP 地址、协议号、端口号等报文特征来实现的。这种方式需要用户了解一定的网络知识,且操作复杂。(虽然部分无线路由器内置了常用应用的 QoS 规则,但仍需要一定的手动设置,且无法及时适配新的、小众的应用)

当然,除了上文中介绍的内容,QoS 还有多种不同的实现方式。例如:

  • 对特定应用(例如 BitTorrent)进行限速
  • 按照 MAC 地址指定某台设备的优先级(例如提高 Nintendo Switch 的优先级,使游戏更加流畅)
  • 通过 WMMDSCP 等机制来决定报文优先级

这些机制各有各的特色和不足。例如对应用程序限速的方式,虽然效果明显,但无法在网络空闲时,动态利用剩余带宽来提升传输速度,也难以适应带宽频繁变化的无线网络。关于上述 QoS 机制的技术细节,本文不再详细介绍。如果感兴趣,可以搜索相关关键词,进一步了解。

智能队列:通过「全自动」的方式优化网络、降低延迟

什么是「智能队列」

目前,一部分新的无线路由器,开始有了名为「智能队列」的功能。这一功能一般指的是 fq_codel。

fq_codel 包含两种队列管理机制,分别是 Flow Queue 和 CoDel。在下文中,我将简要介绍这两种机制的作用。

Flow Queue

前文中介绍过,网络中的报文一般都有自己的五元组信息;同一应用发送的报文,在一定的时间段内,五元组信息是相同的。这些信息相同的一系列报文,被称做一条流(flow)

Flow Queue 为每条流单独维护一个队列。例如,如果我们一边在线观看视频,一边进行语音通话,一边玩游戏,Flow Queue 就会为视频播放的流量、语音通话的流量、在线游戏的流量各维护一条队列:

Flow Queue 示意图

正常情况下,在线观看视频需要占用较大的带宽,但对延迟不敏感,用户可以容忍几秒甚至几十秒的缓冲时间。

而语音通话和在线游戏占用带宽小,但对延迟敏感。例如语音通话时,如果一个人说了一句话,对方在几秒后才能听到,用户就能明显感知到延迟。

如果三种应用共用一个队列,队列中会充满大量视频播放应用的报文,导致语音通话、在线游戏的报文迟迟无法发送,增大了这两种应用的延迟。

Flow Queue 为视频播放、语音通话、在线游戏各维护一条队列,并公平地调度三个队列,避免视频播放的报文占用太多时间,从而让在线游戏、语音通话的报文得到及时处理。由于 Flow Queue 确保了应用程序之间的「公平」(fair),所以又被称做 Fair Queue。

CoDel

我们已经知道,适当长度的队列,能够充分利用带宽、提高吞吐量。但过长的队列,又会导致过大的延迟。也就是说,队列既不能过长、也不能过短。

CoDel 所做的,就是让队列维持在合适长度,最大限度地提升网络性能。

CoDel 通过计算报文在队列中的停留时间,来判断队列是否过长。具体做法如下:

  1. 报文进入队列时,在报文上记录当前时间(也就是报文入队时间
  2. 报文出队列时,再次获取当前时间(报文出队时间
  3. 计算报文入队时间与出队时间的差值,即可得到报文在队列中停留的时间
  4. 当报文在队列中的停留时间超过阈值,说明队列过长,需要缩小队列长度

当队列过长时,CoDel 会直接丢弃出队列的报文,从而减少队列中报文的数量,达到控制队列长度的效果。(这种对报文的丢弃,并不会对网络带来负面影响,具体请见后续章节)

CoDel 示意图

可以看出,CoDel 根据队列中报文的停留时间,来决定是否丢弃报文。而不是「一刀切」地将队列限制在一个固定的、较小的长度。这样既能降低延迟,又保留了队列最大的优点:吸收短暂的大流量报文、提升吞吐量。

另外,我们的设备,尤其是手机等移动设备,所处的网络环境是复杂多变的。例如手机靠近或远离无线路由器,就有可能导致网络带宽的变化。CoDel 通过计算报文停留时间的方式控制队列,能够更加灵活地适应网络带宽、网络质量的变化。

fq_codel

Flow Queue 确保了不同应用程序的流量能够公平传输。CoDel 控制队列长度,实现了整体延迟的降低。fq_codel 就是将 Flow Queue 和 CoDel 结合在一起使用的机制。

其中,Flow Queue 先将不同的流划分为不同的队列,再为每一个队列使用 CoDel,控制报文的延迟。两者结合使用,共同提升网络体验。

fq_codel 具有免配置、天然适应不同的网络环境、实现简单、消耗资源少等特色,越来越多的无线路由器(以及开源的路由器操作系统),开始内置这一机制。

参考 KoolShare 上的这篇帖子,作者经过测试,发现打开 fq_codel 之后,在 BT 下载占满上行带宽时,在线游戏依旧保持较低的延迟:

是否需要打开「智能队列」?

前面介绍了 fq_codel 的一系列优点。那么,fq_codel 有没有缺点?是否需要我们打开?

我的设备 CPU 性能不强,是否可以打开「智能队列」?

根据这篇帖子,ER-X 路由器在打开 fq_codel 时,最大支持 200M 左右的带宽。

ER-X 使用的是 MT7621 CPU。从这个页面可以看到,我们熟悉的小米路由器 Pro、斐讯 K2P 等,都采用了这一系列的 CPU。也就是说,如果宽带带宽小于 200M,使用这些路由器,「智能队列」对网速基本不会有太大影响。

当然,在家用路由器上,不同人有着不同的方案:从百元以下、到千元以上的无线路由器,都有不少人在使用;还有一些人使用有线路由器、软路由,甚至企业级网络设备。

不同的设备,在 CPU 性能上存在很大的差异。还有一些设备,虽然 CPU 性能较弱,但使用了专门的硬件来处理报文。对于 CPU 性能不足的设备,一旦打开了「智能队列」,CPU 就需要参与更多的运算来处理报文,影响报文转发速度。

虽说 fq_codel 是一个简单的算法,占用 CPU 资源相对较少。但考虑到家用网络设备的多样性,还是需要经过实测,才能决定是否要打开该功能。

我家的宽带速度较快(100M 以上),是否还有必要开启「智能队列」?

很多人已经用上了 200M、500M 甚至 1000M 的宽带。而大部分应用跑不满这么大的带宽,即使家里的多个人一起用宽带,也很难把带宽占满。对于这样的宽带,是否有必要开启「智能队列」呢?

大部分家庭宽带,上传和下载带宽是不对等的。例如一个 200M 的宽带,上传带宽可能只有 20M。而很多协议需要客户端和服务端的双向交互(例如 TCP,接收端要向发送端发送确认报文),如果上传速度受到限制,也会影响到下载速度

所以对于下载带宽大,但上传带宽小的环境,使用「智能队列」也有利于提升上网体验。

但是,流量速率越快,fq_codel 处理报文消耗的 CPU 资源也就越多。如果带宽较大,CPU 可能处理不过来大速率的报文。所以,最终还是要综合考虑宽带带宽,和网络设备的 CPU 性能,来决定是否要打开「智能队列」。

「智能队列」会主动丢弃报文,会不会对网络造成负面影响?

fq_codel 控制队列长度,是通过主动丢弃报文来实现的。或许读者们会有疑问,主动丢包是否会对网络有负面影响?是否会导致传输数据的缺失?

其实,Internet 被设计成分组交换的方式,丢包是很常见的现象。对于视频通话等使用的 UDP 协议的应用,少量丢包不会有太大的影响;对于网页浏览等应用使用的 TCP 协议,其本身的重传机制,也能确保数据全部正确传输。

另外,TCP 协议还拥有拥塞控制机制,能够自动调整数据发送速率。大部分拥塞控制算法在检测到丢包时,能够自动降低发送速率。所以,fq_codel 的丢包,还可以反馈到 TCP,让 TCP 协议主动降低数据发送速率,进一步缓解 bufferbloat。

总之,fq_codel 的丢包并不会对网络带来太多负面影响。

结论

在网络设备的 CPU 性能足够的情况下,打开「智能队列」,能够在一定程度上提升上网体验。推荐有条件的用户打开该功能。

但是,如果家庭网络环境特殊,例如路由器性能差、上下行带宽都非常充足等情况,fq_codel 的作用就没有那么大了。如果不确定是否需要打开,还是建议亲自测试一下,观察该功能对上网体验的影响。

参考资料与延伸阅读

在常用的无线路由器操作系统上设置 fq_codel:

CAKE 是一种新的队列管理机制。它吸收了 fq_codel 的优点,并在 fq_codel 的基础上增加了更多新特性。如果自己的路由器支持 CAKE,建议直接用 CAKE 代替 fq_codel:

如何进一步优化家庭网络、降低网络延迟:

fq_codel 基础知识:

关于 Bufferbloat 的更多介绍:

本文介绍了 Linux 网络协议栈中的「队列」。通过阅读本文,可以更清晰地了解报文在网络设备内部是如何处理的:

传统的 TCP 拥塞控制算法倾向于填满队列,可能会加剧 bufferbloat。所以除了 fq_codel,还可以通过优化 TCP 拥塞控制算法,来缓解 bufferbloat。最近几年流行的 TCP BBR,就是一种新的拥塞控制算法:

本文中的图片素材来自 www.flaticon.com,作者分别是 FreepiksripsurangxnimrodxVitaly Gorbachevphoto3idea_studio。题图来自 Unsplash,作者是 Jonathan

笔者对 fq_codel 的了解还不够深入。如果发现文章中有错误,请在评论区留言指正。

对于家庭网络的更多内容,可关注我在 GitHub 上创建的 Awesome List。欢迎提交 issue 和 pull request:

本文首发于少数派,原文链接:https://sspai.com/post/64870

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据