这是本节的多页打印视图。 点击此处打印.

返回本页常规视图.

技术研究

详细了解 Cloudnet 的技术原理及其网络技术的研究成果

此文档汇集了 Cloudnet 的技术原理及其网络技术的研究成果, 以供用户参考.

1 - NAT穿透打洞技术介绍及常见问题解答

本文将详细介绍: NAT穿透打洞技术介绍及常见问题解答,以及其带来的效果和价值。

nat-traversal

NAT 分类以及哪些 NAT 可以打洞成功?

NAT(网络地址转换)主要有以下几种分类:

  1. 全锥形 NAT (Full Cone NAT)

    • 一旦一个内部地址 (iAddr:iPort) 被映射到一个外部地址 (eAddr:ePort),任何发往 eAddr:ePort 的数据都会被转发到 iAddr:iPort。
    • 打洞成功率:高
  2. 受限锥形 NAT (Restricted Cone NAT)

    • 只有当 iAddr:iPort 先发送数据给某个外部地址 (eAddr:ePort) 后,来自该外部地址的数据才能被转发回 iAddr:iPort。
    • 打洞成功率:中
  3. 端口受限锥形 NAT (Port Restricted Cone NAT)

    • 类似于受限锥形 NAT,但是通信受限于特定的端口。只有当 iAddr:iPort 先发送数据给 eAddr:ePort 后,来自 eAddr 和指定端口的数据才会被转发。
    • 打洞成功率:中
  4. 对称型 NAT (Symmetric NAT)

    • 每次从相同的内部地址和端口发送到一个特定的外部地址和端口时,都会使用一个新的随机外部端口。
    • 打洞成功率:低
    • 该类型的 NAT 常见于国内教育网系统中, 例如: 校园网, 教育网等.

在进行 NAT 穿透时,全锥形 NAT 是最容易打洞成功的,因为它对于入站数据没有严格的限制。而对称型 NAT 是最难打洞的,因为它对于每个不同的外部目标使用不同的映射,这使得建立直接的点对点连接变得复杂。

在实际应用中,例如 P2P 通信或 VoIP,通常需要使用 STUN(Session Traversal Utilities for NAT)、TURN(Traversal Using Relays around NAT)或 ICE(Interactive Connectivity Establishment)等技术来辅助完成 NAT 穿透。

为什么我们专注研究 NAT 打洞?

NAT 打洞(NAT Traversal)是一种技术,它允许位于私有网络中的设备与外部世界建立直接的通信连接。我们专注研究 NAT 打洞的原因包括:

  1. P2P 网络优化

    • 在点对点 (P2P) 网络中,NAT 打洞可以提高数据传输效率,减少延迟,并降低中继服务器的负载。
  2. 成本节约

    • 通过直接通信,可以避免使用昂贵的中继服务,从而降低运营成本。
  3. 隐私和安全性

    • 直接的端到端连接可以增强数据传输的隐私性和安全性,因为数据不需要经过可能不受信任的第三方服务器。
  4. 应用兼容性

    • 许多现代的互联网应用,如视频会议、在线游戏和 VoIP 服务,都需要能够穿透 NAT 来实现最佳性能。
  5. 广泛的适用性

    • 随着 IPv4 地址的枯竭,越来越多的网络采用 NAT。因此,NAT 打洞技术变得越发重要,以确保网络的连通性。
  6. 互联网规模扩展

    • NAT 打洞技术使得在没有公网 IP 地址的情况下也能进行大规模的网络连接,这对于互联网的扩展至关重要。

由于以上原因,NAT 打洞技术在网络通信领域中占据了重要地位,特别是在那些需要绕过 NAT 设备以建立直接通信的场景中。

cloudnet 如何实现 NAT 穿透? 使用了哪些技术

在 NAT 1-3 中基本上 Cloudnet 都是可以打洞成功的. Cloudnet 使用了 STUN/TURN/ICE 等技术来辅助完成 NAT 穿透.

对于 NAT4 类型的 NAT, Cloudnet 使用了客户端随机端口技术, 但是这不能保证 100% 的成功率, 所以我们引入了中继服务, 以保证 NAT4 类型的设备也能够快速使用高速网络连通.

我应该如何做来增加 NAT 打洞成功率?

目前很多城市的运营商都已经回收公网 IP 地址, 并分配 100.64 段的 IP 地址, 近年来运营商新装的宽带基本上都是光猫+路由器一体机, 如果你的路由器没有配置上网帐户,直接就是插上就能用的话, 那你的光猫就带有路由器功能, 那么您的 NAT 至少是 2-3 层, 如果您有设备的控制权, 我们建议您开启 upnp/pcp/pmp 这些作为辅助, 那么 NAT 打洞成功率就会很高. 如果你是网络管理员, 可以开放 udp 端口 41641, 那么 NAT 打洞成功率 100%.

NAT 穿透/打洞的常见问题解答

为什么在同一个内网中有的设备可以打洞成功,有的却无法打洞成功?

在同一个内网中,不同设备之间在进行 NAT 打洞时可能会遇到成功或失败的情况,这可能由以下几个因素导致:

  1. NAT 类型差异

    • 即使设备位于同一内网,它们也可能连接到不同类型的 NAT。例如,一些设备可能处于完全锥形 NAT 后面,而其他设备可能处于对称型 NAT 后面。对称型 NAT 更难穿透。
  2. 端口预测不一致

    • NAT 设备在分配外部端口时可能采用不同的策略。如果 NAT 设备不允许端口预测,那么打洞过程可能会失败。
  3. 设备配置

    • 设备的防火墙设置或私有网络配置可能阻止了打洞尝试。确保相关的端口和协议没有被阻塞是成功打洞的关键。
  4. 超时设置

    • 不同的 NAT 设备可能有不同的超时设置。如果一个设备的 NAT 映射很快就超时了,那么打洞尝试可能会因为映射失效而失败。
  5. 并发连接限制

    • 某些 NAT 设备可能对并发连接数有限制。如果达到上限,新的打洞尝试可能无法建立。
  6. IP 地址变化

    • 在动态 IP 地址分配的环境中,设备的公网 IP 地址可能会变化,这会影响到打洞的成功率。
  7. 路由器/防火墙固件差异

    • 不同的路由器或防火墙固件可能实现 NAT 的方式不同,这可能会影响到 NAT 打洞的成功率。
  8. 多层 NAT

    • 如果内网中存在多层 NAT,打洞过程将变得更加复杂,成功率可能会降低。
  9. 端口容量

    • 因为需要占用最上层的公网 IP 的端口, 而最上层公网 IP 往往可能是整个小区的人都在共用, 端口也会很紧张, 如果 NAT 打洞时协商不到端口那就会持续协商,直到成功协商到端口并打洞成功, 所以这也会导致为什么同一个内网的设备有的打洞成功而有的却无法成功的原因.

理解和诊断这些因素有助于改善 NAT 穿透/打洞的成功率,并且可能需要针对特定的网络环境调整策略。

如何解决这个问题呢?

Cloudnet 在 1.58 版本开发了一种叫做 NAT 动态路由的技术. 该技术的原理是将打洞成功的设备作为 NAT 路由节点, 而同处于一个内网的其他设备则通过这个 NAT 路由节点来进行转发特定的网段流量, 当设备打洞成功则自动切换回本机路由,不再走 NAT 动态路由.

使用该功能的前提是内网中至少有一个设备是可以打洞成功的, 且该设备必须是一直在线的, 且不会被关机, 以保证 NAT 动态路由的可用性.

Cloudnet 进行 NAT 打洞时, 为什么会有延时?

  • 对于 NAT1-3 类型的 NAT, Cloudnet 基本上可以做到只需几秒即可打洞成功.

  • 对于 NAT4 可能不会立刻打洞成功, 针对此场景我们会先使用中继服务来保证你的网络是通的, 并同时进行打洞, 一旦打洞成功就会切换到直连模式, 这个过程有时会持续几分钟甚至更久.

什么是 idle 状态?

如果穿透成功后长时间没有使用(没有任何流量进出),那么客户端与对端的设备就会变为空闲状态(idle).

什么情况下会重新打洞?

  • 穿透成功就会持续占用运营商公网 IP 网关分配的端口, 如果运营商的网关设备重置连接或强制释放端口那就需要重新进行打洞

  • 如果穿透成功后长时间没有使用(没有任何流量进出),那么客户端也会自动释放端口,再次使用时就会重新进行打洞.

2 - 如何在 Cloudnet 上提升 QUIC 和 UDP 的传输效率

本文将详细介绍如何在 Cloudnet 上提升 QUIC 和 UDP 的传输效率,以及其带来的效果和价值。

大家好,我们来聊聊性能优化了。记得之前我们如何提升了 TCP 传输效率吗?现在,我们有了新动作——我们显著提高了 Linux 系统上 UDP 传输的速度。就像以前一样,我们计划将这些改进贡献给 WireGuard 社区。

UDP 协议是一种相对简单的传输方式,它不像 TCP 那样会确认数据包是否成功送达。因此,UDP 特别适合那些对即时响应有严格要求的应用,比如在线游戏或视频会议。而最近,随着新兴协议 HTTP/3 和 QUIC 的崛起,UDP 的使用率激增。

我们通过使用一种技术叫做分段卸载,提高了基于 HTTP/3、QUIC 等 UDP 协议的应用的传输效率。在标准的 Linux 系统上,我们使得 Cloudnet 的 UDP 传输速度提高了四倍,甚至超过了同一硬件上的内核级 WireGuard 实现。

想要体验这些?你可以在 Cloudnet v1.54 中尝试。继续阅读,我们将分享更多细节;如果你只对结果感兴趣,也可以直接跳到成果部分。

背景

接下来,我们会探讨 wireguard-go——Cloudnet 数据传输的核心。它通过 TUN 设备接收操作系统的数据包,对它们进行加密,然后通过 UDP 协议发送到另一端。返回的数据包也通过相同的路径解密后返回到操作系统。

Cloudnet

我们先前的改进主要集中在提升每次 I/O 操作中传输的数据包数量。不管是 TCP 还是 UDP,我们都采用了一些技术来提高数据包处理的效率。但这些技术对于 TCP 更加有效,因为 UDP 流量在我们的 wireguard-go 实现中几乎没有得到改善。考虑到越来越多的应用开始采用 HTTP/3 和 QUIC,我们现在把重点放在了提升 UDP 的性能上。

我们在 Cloudnet v1.36 和 v1.40 中做的改变更新了这个数据包管道,大大增加了 wireguard-go 上的 TCP 吞吐量。在这两种情况下,我们都专注于增加每个 I/O 操作端到端传输的数据包数量。在 TUN 驱动端,这涉及到 TCP 分段卸载(TSO)和通用接收卸载(GRO)。在 UDP 套接字端,我们利用了 UDP 通用分段卸载(UDP GSO)和 UDP 通用接收卸载(UDP GRO)。分段和接收卸载都使多个数据包能够作为一个单一元素通过堆栈传递。分段卸载涉及在最接近传输边界的地方将单个“怪兽”数据包分段,这是要写入自然大小的数据包的地方。接收卸载涉及将多个数据包合并成一个“怪兽”数据包,这是最接近接收边界的地方,预期在这里读取自然大小的数据包。

Cloudnet

Cloudnet

在这些卸载被用于 UDP 的地方,UDP 是作为底层协议的。我们在 TUN 端实现的卸载是针对 TCP 的,并不适用于 UDP 覆盖流量。这导致 UDP 流在 wireguard-go 上几乎没有什么好处。TCP 一直是高吞吐量应用的传输协议的首选,所以最初专注于 TCP 吞吐量是有道理的。然而,随着 HTTP/3 和 QUIC 的出现,这种情况正在开始改变。

HTTP/3 和 QUIC

HTTP/3 是 HTTP/2 的继任者,它使用 QUIC,这是一个相对较新的基于 UDP 的多路复用传输协议。

Cloudnet

QUIC 有许多优于 TCP 的优点,包括但不限于:

  • 紧密集成 TLS,使其不易受到中间盒子干扰或依赖传输层元数据的影响
  • 更快的连接握手(假设不需要 HTTP/2 over TCP 来引导)
  • 对头阻塞的抵抗力更强;流感知从传输协议延伸到 HTTP/3
  • 使拥塞控制快速演化成为可能,因为它存在于用户空间
  • 全球约有 27% 的网络和服务器已经支持 HTTP/3。

所以,HTTP/3 和 QUIC 的采用正在增加,我们需要扩展我们的性能工作以使其受益。

基线

关于基准测试的免责声明:这篇文章包含基准测试!这些基准测试在写作时是可重现的,我们提供了我们运行它们的环境的详细信息。但是基准测试结果在不同的环境中会有所不同,而且随着时间的推移,它们也往往会过时。你的里程可能会有所不同。

我们需要设置一个 UDP 吞吐量基线以供后续比较。在我们之前的文章中,我们使用 iperf3 进行了 TCP 基准测试,但在写作时,iperf3 不支持 UDP GSO/GRO。没有这个支持,它不会反映出与广泛使用的 QUIC 实现相比的实际性能。所以,我们将使用 secnetperf,这是 msquic 的一个实用程序,来代替。引用 msquic 的 README:

MsQuic 是微软对 IETF QUIC 协议的实现。它是跨平台的,用 C 写的,设计成一个通用的 QUIC 库。MsQuic 还有 C++ API 包装类,并为 Rust 和 C# 暴露了互操作层。

msquic 的一位维护者,Nick Banks,在 IETF 内部工作,并提出了一个 QUIC 性能协议,用于测试 QUIC 实现的性能特性。secnetperf 实现了这个协议。

使用 secnetperf,我们为 wireguard-go@2e0774f 和内核 WireGuard 在两对主机之间的 QUIC 吞吐量进行了基线测试,这两对主机都运行着 Ubuntu 22.04,使用的是写作时可用的 LTS 硬件启用内核:

2 x AWS c6i.8xlarge 实例类型 2 x “裸机”服务器,由 i5-12400 CPU 和 Mellanox MCX512A-ACAT NICs 提供动力 AWS 实例位于同一区域和可用区:

在我们之前的文章中,我们分析了火焰图(),这些图突出显示了通过内核网络堆栈和 wireguard-go 可以提高 CPU 周期/字节效率的地方。这个分析的结果导致我们在 wireguard-go 的两端实现了传输层卸载,这提高了覆盖网络上的 TCP 流量的吞吐量。现在,我们需要在这项工作的基础上,同样使 UDP 流量在 wireguard-go 上受益。进入 tx-udp-segmentation。

Cloudnet

NETIF_F_GSO_UDP_L4 是 Linux 内核中用于在代码中定义它的符号。引用内核文档 NETIF_F_GSO_UDP_L4 接受一个超过 gso_size 的 UDP 头和负载。在分段时,它在 gso_size 边界上分段负载,并复制网络和 UDP 头(如果小于 gso_size,则修复最后一个)。

Cloudnet

这个 netdev 特性在 Linux v4.18 中被添加,最近在 Linux v6.2 中被添加为一个可以在 TUN 驱动中切换的特性。TUN 驱动在 v6.2 中的支持是提高 UDP 吞吐量所需的缺失的部分。开启它后,wireguard-go 可以从内核接收“怪兽” UDP 数据报:

反向方向的工作方式类似。它不需要一个显式的 netdev 特性来支持 UDP GRO,而是简单地依赖于相同的 virtio 网络基础设施来支持合并。

现在,来看看总体结果。

应用 TUN UDP GSO/GRO 导致 wireguard-go 的吞吐量大幅提高,因此也在 Cloudnet 客户端中提高。

有了这一新的改变集,Cloudnet 上的 UDP 吞吐量在裸机 Linux 上增加了 4 倍,并超过了该硬件上的内核 WireGuard 实现。

AWS c6i.8xlarge 实例在约 7Gb/s 的地方遇到了一个墙,这似乎是底层网络的人为限制。

rx-udp-gro-forwarding 和 rx-gro-list

关于 UDP 吞吐量在转发拓扑中的两个 Linux 内核网络设备特性很重要,即数据包从一个接口进入并从另一个接口离开。

第一个是 rx-udp-gro-forwarding,引用其来自 Linux 内核的注释:

Cloudnet

如果在接收接口上没有启用 rx-udp-gro-forwarding,那么被转发的 UDP 数据包,即不是目标为本地套接字的数据包,将不会是合并的候选者。这限制了 GRO 在堆栈的其余部分的效果,降低了吞吐量。最初,对于转发的数据包,默认启用了 UDP GRO,这是在这个特性存在之前。这是无意的,如引入该特性的内核提交所提到的。

Cloudnet

我们建议在你的默认路由接口上启用 rx-udp-gro-forwarding,如果你正在运行 Cloudnet 版本 1.54 或更高版本作为子网路由器或出口节点,并且使用的是 Linux 6.2 或更新的版本.

最后

我们还介绍了一些技术细节,包括如何在 Linux 系统上启用特定的网络设备特性来进一步提升 UDP 性能。我们的工作使得 Cloudnet 上的 UDP 传输速度得到了大幅提高,尤其是在不使用虚拟化环境的 Linux 系统上。

希望以上内容能帮助你了解我们是如何优化 Cloudnet 上的 UDP 传输效率的。如果你想要了解更多的技术细节或参与到我们的性能提升工作中,请继续关注我们的更新。