下载期间的高延迟

网络工程 潜伏
2021-07-02 20:09:41

我的业务连接 5Mbps 遇到了与本网站上的另一个帖子相同的问题一旦任何计算机开始下载,在通过我们的 ISP (Bell) 提供的 DFG 的第一跳上的延迟就会超出图表。这个第一跳很可能在我们的同一个建筑物中,并且持续 1 毫秒,开始下载,例如 Windows 更新,它跳到 200-1000 毫秒。

我在电话上花了数小时支持,所有人都说您已达到最大可用带宽,延迟飙升是正常的。但是我的阅读告诉我他们正在破坏 TCP 的某些内容。我已经在家庭 Shaw 连接上运行测试,甚至在运行下载并达到我帐户的最大 Mbps 的 Rogers LTE 上运行测试,但延迟并没有超过屋顶。

我的理解是否正确,贝尔正在做一些事情来破坏 TCP 的内置技术,以根据 2 个端点之间的可用带宽来管理其速率?

4个回答

贝尔告诉你真相。当您尝试将 5Mbps(或更多)推入 5Mbps 连接时,所有文件都按整齐排列(阅读:队列)。您的 ping 会立即消失,因为没有积压。然而,答复现在位于队列的末尾。TCP 正在做它应该做的事情——发送者正在填充允许的接收窗口。

您可以在线路中做一些事情(QoS、WRED 等)来帮助减少影响,但是当发送方和接收方带宽之间存在很大差异时,您会看到这种情况。我已经使用它多年(T1、6Mbps DS3,甚至 10Mbps 电缆调制解调器)您可以要求 ISP 减少他们这边的队列大小,但他们不太可能这样做,因为它会导致数据包丢失.

现在大多数形式的“QoS”都不包括 AQM,因为供应商发现很难在不造成伤害的情况下自动配置 RED。这导致您在当今许多常见设备上看到的可怕延迟,尤其是电缆调制解调器和无线设备。所以仅仅推荐“打开 qos”......没有帮助。事实上,至少在 Netgear 的一种产品上,打开“QoS”的速率限制器会导致更糟糕的结果......

最近出现了一种新的公平排队 + AQM 算法,它看起来运行得非常好,而且更好的是,除了设置速率限制器之外几乎不需要任何配置。它被称为 fq_codel,它现在在大多数 Linux 中广泛使用,并且也已移植到 BSD。它是 openwrt 屏障断路器、cerowrt 和 gargoyle 中默认“QoS”的一部分,使用名为 sfqred 的(相当不错的)早期版本以及称为 ACC 的创新自动速率调整方案。

所以你可以在你的行为不端的链接前猛击一个基于此的框,打开他们的 QoS 速率限制器(设置略低于你的提供商入站和出站设置,以便你控制)+ fq_codel,并为每个使用它的人获得更好的性能. 我的意思是惊人的好:请参阅下面的 ietf 演示、向 ietf 的 iccrg 工作组提交的报告等。

有关 bufferbloat 问题及其修复的更多详细信息,请参阅:

http://www.bufferbloat.net/projects/cerowrt/wiki/Bloat-videos

我们(当然)正试图说服各种 ISP CPE 供应商关注,就像 cablelabs 一样,它在几个月前发表了对这种新东西的精彩研究,其中还包含一些关于当前电缆调制解调器不当行为的详细信息。

http://www.cablelabs.com/downloads/pubs/Active_Queue_Management_Algorithms_DOCSIS_3_0.pdf

你所看到的完全是典型的。许多服务提供商会限制速率和/或使用 QoS 机制来降低 ICMP(包括传统 ping 和跟踪路由)的优先级,因为它有时被用于拒绝服务攻击。

虽然链接不拥塞,但降低的优先级不会影响任何事情,因为没有流量排队。在这些期间,您的延迟会保持在较低水平,因为 ICMP 数据包将立即转发而根本不会延迟。

当链路拥塞时,更高优先级的队列会得到更多关注。根据排队机制,它可能会为来自较低优先级队列的每个数据包转发来自较高优先级队列的多个数据包,甚至仅在较高优先级队列中没有任何数据时才转发。在任何情况下,与没有拥塞的链路相比,降级到较低优先级队列的数据包通常会被延迟更长的时间,从而增加延迟。

您可能正在遭受缓冲区膨胀的困扰,并且想要 AQM(主动队列管理)。我已经为 Linux 编写了一个脚本,这使得这很容易:

#!/bin/bash
# Traffic shaping script (AQM, fq_codel+tbf)
# Copyright 2018 Mikko Rantalainen <mikko.rantalainen@gmail.com>
# License: MIT (X11)
# Usage:
#   21/0.8 Mbps connection (ADSL2): DOWNLINK_RATE=21.7Mbit UPLINK_RATE=0.8Mbit TBF_LATENCY=500ms bin/traffic-shaping start
#   100/100 Mbps connection: ./traffic-shaping
#   1/1 GBps connection: DOWNLINK_RATE=1Gbit UPLINK_RATE=1Gbit TBF_LATENCY=10ms bin/traffic-shaping start
# Note that using low TBF_LATENCY will require powerful CPU.
#   

set -e

DEV="${DEV:=$(ip route | grep "^default " | grep -Po "(?<=dev )[^ ]+")}"

# ingress:
DOWNLINK_RATE="${DOWNLINK_RATE:=104000kbit}" # or e.g. "21.5Mbit"
# egress:
UPLINK_RATE="${UPLINK_RATE:=105000kbit}"

CODEL_INTERVAL="${CODEL_INTERVAL:=100ms}" # usually 100ms, high speed links with low latency may need lower values
CODEL_TARGET="${CODEL_TARGET:=5ms}" # unit "us" is also available, usually 5%-10% of CODEL_INTERVAL
CODEL_LIMIT="${CODEL_LIMIT:=1001}" # decrease to reduce latency, too low values will limit throughput
CODEL_FLOWS="${CODEL_FLOWS:=1024}"

# set burst as high as possible without causing dropped packets at the start of the connections
DOWNLINK_BURST="${DOWNLINK_BURST:=6500}"
UPLINK_BURST="${UPLINK_BURST:=6500}"

TBF_LATENCY="${TBF_LATENCY:=14ms}" # set to lower latency to improve control over bandwidth limiting, UPLINK_BURST bytes must be able to be sent in this time

IFB="$DEV.ingress"

INITCWND="${INITCWND:=20}"
INITRWND="${INITRWND:=20}"

configure_shaping()
{
    # EGRESS (outgoing traffic, "uploads"):

    # setup bandwidth limiting:
    tc qdisc add dev "$DEV" root handle 1: tbf rate "$UPLINK_RATE" burst "$UPLINK_BURST" latency "$TBF_LATENCY"

    # setup fq_codel for bandwidth shaping
    tc qdisc add dev "$DEV" parent 1: fq_codel limit "$CODEL_LIMIT" target "$CODEL_TARGET" interval "$CODEL_INTERVAL" flows "$CODEL_FLOWS" noecn


    # INGRESS (incoming traffic, "downloads"):

    # setup bandwidth limiting (ingress limiting needs IFB or Intermediate Functional Block, see https://wiki.linuxfoundation.org/networking/ifb):
    tc qdisc add dev "$DEV" handle ffff: ingress
    ip link add name "$IFB" type ifb
    tc qdisc add dev "$IFB" root handle 1: tbf rate "$DOWNLINK_RATE" burst "$DOWNLINK_BURST" latency "$TBF_LATENCY"

    # setup fq_codel for bandwidth shaping
    tc qdisc add dev "$IFB" parent 1: fq_codel limit "$CODEL_LIMIT" target "$CODEL_TARGET" interval "$CODEL_INTERVAL" flows "$CODEL_FLOWS" ecn
    ip link set dev "$IFB" up

    # connect ingress filtering to actual WAN device
    tc filter add dev "$DEV" parent ffff: protocol all prio 10 u32 match u32 0 0 flowid 1:1 action mirred egress redirect dev "$IFB"

    # configure initcwnd and initrwnd
    ip route change $(ip route | grep ^default) initcwnd "$INITCWND" initrwnd "$INITRWND"
}

remove_shaping()
{
    tc qdisc list | grep -q "ingress" && tc qdisc del dev "$DEV" ingress || true
    tc qdisc list | grep -q "codel" && tc qdisc del dev "$DEV" root || true
    ip link show | grep -q "$IFB" && ip link del "$IFB" || true
}

status()
{
        echo "─── queue discipline configuration: ──────────────────"
        tc qdisc list
        echo "   TIP: use e.g. 'sudo tc qdisc del dev $DEV ingress' to remove ingress filtering"
        echo "   TIP: use e.g. 'sudo tc qdisc del dev $DEV root' to remove egress filtering"
        echo "─── ip link show: ────────────────────────────────────"
        ip link show
        echo "   TIP: use e.g. 'sudo ip link del $IFB' to remove ingress device"
}

color_status()
{
    status | grep --color=auto -E "^|$DEV|$IFB|rate [^ ]+"
}

# handle parameters

ACTION="$1"
shift || true

while [ ! -z "$1" ]
do
    case "$1" in
        -v|--verbose)
            echo "Device: $DEV"
            echo "Downlink rate (ingress): $DOWNLINK_RATE"
            echo "Uplink rate (egress): $UPLINK_RATE"
            set -x
            ;;
        *)
            if [ ! -z "$2" ]; then
                echo "Unknown parameter: '$2'" 1>&2
                exit 1
            fi
            ;;
    esac
    shift
done

case "$ACTION" in
    start)
        remove_shaping
        configure_shaping
        ;;
    stop)
        remove_shaping
        ;;
    status)
        color_status
        ;;
    restart)
        remove_shaping
        configure_shaping
        ;;
    *)
        echo "Unknown action: $1" 1>&2
        echo "Usage: $0 <start|stop|restart|status> [--verbose|-v]" 1>&2
        exit 1
esac

您只需将脚本另存为traffic-shapingchmod a+x以 root 身份运行(显然是在阅读源代码之后)。

对于您的用例,我建议

DOWNLINK_RATE=5.0Mbit UPLINK_RATE=5.0Mbit TBF_LATENCY=500ms ./traffic-shaping start