跳转至

博客 & 网络

L3 负载均衡实现网速叠加

  • 公司有 wifi 和 网线接入。但是每条链路都严格限制成了 8 Mbps 的速度。
  • 同时连接 wifi 和 网线,修改路由表,让不同目的地址走不同链路,再结合 aria2c 的多源地址下载,可以实现网速叠加。示例命令:
    aria2c -c -x 1 -s 2 https://alist.yfycloud.site:4433/d/Guest/Aria2/grpc.tar.xz\?sign\=JzEpqFm02IlJUuYfCQY3RZdU-NxYVyMElvQShef8Wy0\=:0  http://192.168.36.254:
    8000/grpc.tar.xz
    
    • -s 2 表示文件被分成 2 份并行下载,-x 1 表示每个 host 最大创建 1 个连接。这里指定了 2 个源 url,因此意思就是从每个源各创建 1 个连接。
    • 其中源 alist.yfycloud.site 为公网地址,走以太网。源 192.168.36.254 走 wg(底层基于 wifi)

但是上面使用了两台服务器提供相同的文件,由于有两个公网地址(使用 LAN 地址的链接底层 wg 仍然需要一个公网地址),因此分流比较简单。如果要缩减为 1 台服务器,就得有让即使是只有一个公网地址,也可以走不同路由的方法(即分别从以太网和 wifi 出去)

我开始的想法是本地使用一个 nginx 反向代理远程的链接,使得请求不同本地地址 127.0.0.x bind 到不同出口出去。nginx 支持 proxy_bind 参数,支持绑定到不同源 ip 地址。但是没想到 Windows 的路由非常不灵活,无法实现源地址的路由1

后面我利用一个简单的千兆路由器(xiaomi 4A gigabit version)将多台设备连接起来,并在每台设备上开启 nginx 反代,实现了只有一个公网地址的情况下,对同一个服务器的网速叠加效果。

nginx 的方法虽然有效,但是整个 setup 有点复杂(windows 需要配置 nginx,设置路由表),并且只能针对一个目的地址叠加网速。访问网页其它内容就无法加速了。

之后又去了解了 ECMP 技术,其中 per flow 和 per packet 分流的想法看上去确实很美好。如果可以实现的话,可以真正实现针对任意协议的网速叠加。(单连接在 per flow 情况下还无法提升速度,但是能够对不同单连接负载均衡也足够了)

各方案总结

  • 单机器 wifi 有线叠加
    • 方法:aria2c 指定多个源地址,不同地址使用不同路由。
    • 优点:简单,只需要使用 aria2c
    • 缺点:
      • 需要有多个公网 ip,否则无法根据目的地址路由
      • 几个链路就需要几个公网 ip (windows 不支持源地址路由导致的)
  • 多机器使用 nginx 反代
    • 方法:对上面方法的扩展,每台机器使用 nginx 反代,类似于 CDN 节点。叠加所有机器的链路
    • 优点
      • 提升了扩展性,不同机器可以使用相同的公网 ip 反代
    • 缺点
      • 设置相对复杂
      • 只能代理 HTTP(S)
      • 只能对设置的单个公网 ip 叠加链路,没设置的 ip 仍然只能使用一个链路
  • ECMP 负载均衡
    • 方法:利用 linux 的等效多径路由,在路由器上就流量负载均衡到各节点出去
    • 优点
      • 设置好后,对所有流量都可以负载均衡到不同链路。多线程下载就可以叠加网速。
    • 缺点
      • windows 垃圾的网络能力,无法 masqerade 导致方案一度不可行(因为只有一个网段,最后回来的流量必然还是得走一个链路)
      • 利用 wg 在 openwrt 路由器和 windows 间创建额外的局域网段,将 SRC NAT 转移到 openwrt 上,规避了 windows 的限制。
      • ECMP 的不足
        • 第一个问题是不知道怎么配置 ECMP 检测失效的链路。 wg 断开连接后,ECMP 并不会删除掉坏掉的 nexthop。在这种情况下,总是导致网络不可用(虽然其它 nexthop 是可用的)
        • 第二个问题是链路利用率低,因为是 per-flow 进行负载均衡。计算 L4 hash 后,每个连接等可能分配到每个链路,并不保证不使用相同链路。而简单的数学计算我们可以得到 3 个链路,3 个连接时,使用全部链路的概率仅为 2/9,4 个连接时仅为 9/16。这也是为什么 iperf3 -P 3 每次结果可能不一样。n 个 链路 n 个连接情况下,利用率随着 n 增大,下降到极限值 \(1 - 1/e \approx 0.63\)
      • ECMP 节点作为下载机器时,只能使用本地链路。
        • 如果路由器可以作为一个反代节点就可以解决,可惜我的 mi4a 只有 16M 的 flash,应该装不下(TODO:可以试试自己编译镜像)

下载 windows11 镜像,从一小时二十分钟,下降到二十分钟 image.png image.png

利用 mi4a + 两台 windows 共 3 个路径进行 ECMP,手机播放 B 站 4K 视频时的效果,CPU 有 %30-40 的占用。 image.png

linux 创建代理

我自己的机器配置了透明代理,因此配置开发环境等非常方便。但是实验室服务器等其它机器则通常没有自由的网络环境。因此如果能够让其它机器通过我内网的一台 linux 机器(通常是 VM)上网就很方便了。

由于并不需要绕过 GFW,传统的代理协议如 HTTP 代理和 Socks 即可,并且许多软件都对这两种协议有支持。比如 linux 命令行下的软件大部分支持通过环境变量启用代理,如 curl, wget, git。浏览器甚至 windows 操作系统自身通常也支持设置系统代理(也是对浏览器生效)。因此本片文章主要总结了搭建这两种代理服务器的常见软件。

总结:调研下来,虽然这两种协议历史悠久,有成熟的软件工具。但是目前大部分软件功能都太多了,这导致配置很复杂(比如 squid 9000 行的配置文件)这对简单使用代理功能有点 overkill 了。不过虽然配置复杂,学习后至少能用,因此就先不纠结了。**要我说感觉可以使用 python 简单糊一个单文件脚本,支持 1)密码认证 2)基于 ip 的访问控制 3)并且端口复用,同时支持 http 和 socks。可以放在 TODO list 里。

便携路由器

背景

很多时候,我们想要出门在外也能方便地连入我们的内网。我最近就遇到了到朋友那玩 VR 结果串流不成功的问题。虽然理论上我可以在那慢慢配置 wireguard 啥的,但是通常一下午并没有这么多时间让我折腾。所以就在想是否可以随身携带一个便携路由器,只需要插上网线,连上 wifi 就能快速接入我的内网呢?这便对路由器提出了一些需求:

  1. 最重要的,需要便携性,能放入书包里
  2. 能刷 openwrt 跑 wireguard
  3. wifi 6
  4. 最好是主线 openwrt
  5. 性能联发科 mt7981 以上

2)和4)主要是我设想的组网方案会用到 wireguard,而一些硬件主线还没有支持(比如 360t7 和 wr30u 都是 23 下半年才支持的,我买的时候还没有)。虽然有一些第三方的 openwrt 魔改版固件,比如 QWRT,XWRT 等等。但这些系统有一些我无法接受的点,比如使用闭源 wifi 驱动,这导致无法和主线的 openwrt 组 mesh 和 fast roaming 等。另外 wireguard 需要内核模块,如果第三方固件没有的话,也没法自己安装。

3)和 5)主要是因为 VR 串流对于带宽要求是比较高的,在一些高端硬件情况下,码率设置成 500 mbps 都是可行的。我的硬件一般 60 - 100 Mbps 就够了。由于 wg 需要加解密是需要吃较多 CPU 资源的,mt7981 能够跑到 350-400 Mbps 左右(见cyyself/wg-bench: WireGuard Benchmark using netns and iperf3 (github.com))。而经典的 mt7261 MIPS SoC 则只能跑到 100 Mbps 左右就明显不够用了。因此为了保障有较好体验,wifi 6 和 mt7981 我觉得是个基准线了。

最终实现的效果

  • 设备通过 wg0 接口连接入我的内网
  • (三层接入)连接 5G wifi SSID1,被分配一个本地局域网地址 192.168.1.x,然后通过 wg0 NAT 后上网
  • (二层接入)连接 5G wifi SSID2,通过 vxlan 二层接入我的 op1 内网,获得 op1 的内网地址

测速

  • 有线 wg:420/430 (up/down,下同)
  • 无线(-60dBm signal/-90dBm noise)
    • L2: 257/320
    • L3:300/340

最后的接口示例:

MTU 的那些坑(二层隧道组网)

背景

背景:串流软件不支持手动添加 ip,导致需要二层隧道连接两个路由器。

通过 mDNS proxy 实现本地发现

之前还研究过这类软件一般是怎么发现server的。发现确实有一些方法可以实现跨网络的发现。比如常见的“发现”协议(不知道术语是什么)有mDNS和upnp。是通过ipv4 multicast实现的,所以只要能proxy多播包,就可以实现在两个网络互相发现。

2024/4/17 update: 今天在搜索 vxlan 时发现了一篇博客也遇到了这个问题。他的解决方案是通过设置 bridge-nf-call-iptables 使得桥接的数据包也通过 iptable,然后再通过 iptable 修正 MSS。因此其方案对于 UDP 仍然存在问题。不过将 bridge 的包进行三层的处理的思路是一样的。在 OpenWrt 设备间使用 VXLAN 创建隧道 – t123yh's Blog 看来这个问题并不是 gre 才会有的。那有没有更加现代的二层隧道协议,能够自动解决这个问题呢?

二层隧道方案

隧道方案如下图所示:

二层隧道拓扑图

  • 两个路由器间通过 WAN 口 IPv4 建立 GRE Tap 隧道
  • op1 上将直接将 tap 接口桥接到到原有 br-lan 上
  • op2 保留了原本自己的 lan,然后创建了一个新的 br-lan2,连接了 gre tap 接口和 eth2 接口。

op2 是 PVE Host 上一个容器

op2是PVE上的一个LXC容器,分配了eth0, eth1, eth2分别对应wan, lan1, lan2

  • op2 侧将一个无线路由器连接到 PVE host(软路由)一个网口,该网口位于 PVE vmbr2 下。op2 eth2 也连接到了 vmbr2。
  • 通过切换无线路由器连接到 PVE host 不同网口(对应 vmbr1 和 vmbr2),可以控制无线路由器位于 lan1 还是 lan2。

VLAN 切换 SSID 方案

刚开始想了一个更复杂不用改动AP网线的方案。将AP通过一根线和软路由连接,然后创建2个vlan。AP上,创建两个不同SSID绑定到不同VLAN接口上。这样就可以通过更改连接的WiFi来切换lan1和lan2了。不过PVE上vlan貌似配置有点复杂:可能需要创建一个vlan awareness的vmbr1,然后op2连接到vmbr1的eth1和eth2指定不同vlan id。但是我没想清楚vmbr1下untagged的接口怎么办?vmbr1设置了awareness后还能连接untagged的端口吗?因为不太了解PVE VLAN awareness bridge的更详细内容,加上路由器就在手边,换条线也很快,因此就没有使用该方案。

遇到的问题

实现上述方案后,确实让一开始的 VR 串流软件可以工作了,但是确遇到了一些意外的问题。

我发现我的手机平板都无法使用 moonlight 串流我位于 op1 下的台式机 KVM-win10 了。

  • moonlight 显示在线(这个需要开启 MSS clamping),但是一连接就报错。报错让检查 UDP 端口 478000 是否开放。
  • 笔记本同样连接的 WiFi,却确能够正常串流

以前也遇到这样能 ping 通,但是一发送数据就出问题的现象。问题一般是哪里的接口 MTU 设置不正确导致的,因此这次也是往 MTU 这方面排查问题。 加上之前遇到的 MSS 问题,于是这次相当于把我知道的都结合起来,看能否解决这个问题。

为设备分配静态 v6 基于 ndppd

背景

学校提供了 ipv6,我的许多服务都可以使用 v6 访问。但是学校提供的 PD 可能会变,虽然使用 ddns 可以将 v6 地址映射到固定的域名,但是 ddns 有延迟性。因此最好的解决办法仍然是给机器设置静态 ip。

p.s. 短期重启网卡 PD 不会变,但是如果长期离线再上线就可能变,类似于 dhcp。

宿舍的 v6 wan 口无法设置静态 ip,因为学校路由器要求设备必须发了 RS 才会路由该包。

信智楼则可以静态设置。当访问外网时,学校路由器不会检查源地址,会直接路由出去。等接收到回包时,学校路由器看到目的地址为设置的静态地址,会在广播域上发送 NS,我自己路由的 wan 口接收到 NS 后响应 NA(v6 版的 ARP 过程)。学校路由器便知道了我路由器 wan 口的 mac 地址,于是将包发送给我的路由器 wan 口。

虽然信智楼可以静态设置 v6,但是仅限于 wan 口。lan 下面的设备如果手动设置了静态 v6,是无法正常上网的。重复上过程会发现学校仍然会正常把包路由出去,但是收到回包后,会像之前一样发送 NS。而我们路由器的 wan 口接收到 NS 后,根本不会响应 NA(因为不是自己的 v6 地址)。LAN 和 WAN 又不是一个广播域,因此收不到 NS。从而导致学校路由器并不会把回包交给我们。

但其实上面的需求是可以实现的,我们需要一个叫做 NDP proxy 的软件。

NAS 无法扫描到涉及的网络知识

背景

tsj 的 NAS 插墙上网口,笔记本同样插墙上网口,然后使用 NAS 官方工具扫描不到设备。由于扫描不到设备所以不知道设备 ip,也就无法进一步配置。

那么是什么原因导致扫描不到呢,照理来说,NAS 和笔记本应该接在同一个交换机下,理应是互通的。在研究该问题过程中,查缺补漏了很多网络知识,特记录。

疑问一:学校为何插在相邻墙上的网口的机器分配到不同网段的 ip?比如 114.xxx 和 210.xxx 疑问二:宿舍路由器查看 wan 口邻居表,为何不同 ip 的 mac 地址是相同的?