
vc5 v0.3.4
一个可水平扩展的 Direct Server Return 第4层负载均衡器,适用于 Linux,使用 XDP/eBPF
VC5
本 README 正在更新以反映近期变更——部分信息可能与当前代码库不符。此迭代代码尚未达到实战就绪状态——生产环境中请使用 v0.2 版本。
一种基于 Linux XDP/eBPF 的、支持水平扩展的直连服务器返回(DSR)四层负载均衡器(L4LB)。
如果您认为这可能有帮助,或有任何疑问/建议,欢迎通过 [email protected] 与我联系,或在 GitHub 上提 Issue。
现已支持 IPv6 以及三层分发(即隧道模式)!XVS 库已更新包含这些功能,同时不再需要从网络命名空间运行健康检查,大幅简化了代码。这将结束所有后端服务器必须与负载均衡器共享同一 VLAN 的要求。
当前代码限制导致无法按服务启用隧道模式。使用 -tunnel 选项可通过单一方案(IP-in-IP、GRE、FOU 或 GUE)全局启用三层隧道。未来代码将更新以支持在服务级别配置隧道。
二层负载均衡将继续受支持——启动该项目的主要原因是因为 Facebook 的 Katran 负载均衡器缺乏二层支持。
附带了 示例 IPv6/L3 配置文件——更完善的文档后续提供。
关于
VC5 是一款网络负载均衡器,旨在替代传统硬件设备。它允许将具有虚拟 IP 地址(VIP)的服务分发到后端(“真实”)服务器组。真实服务器可以直接运行服务本身,或作为另一层服务器的代理(例如,当需要应用层决策时,HAProxy 充当七层 HTTP 路由器/SSL 卸载)。唯一的要求是 VIP 需要配置在每个真实服务器的环回设备上,例如:ip addr add 192.168.101.1/32 dev lo
服务和真实服务器在配置文件中指定,同时包含健康检查定义。当后端服务器通过检查且足够数量可用时,虚拟 IP 地址会通过 BGP 通告给路由器。
现已支持二层和三层流量分发。二层分发要求真实服务器与负载均衡器共享同一个 VLAN;当接收到需要分发的数据包时,负载均衡器会更新数据包中的以太网硬件地址,将目的地址改为真实服务器的 MAC 地址,源地址改为自身的 MAC 地址,然后通过适当接口转发数据包,如果数据包带有 VLAN 标签,还需更新 802.1Q VLAN ID。
三层分发要求数据包封装在隧道协议中,发往真实服务器 IP,并通过路由器转发(除非服务器和负载均衡器共享 VLAN)。如果封装后的数据包超过网络最大传输单元,则会向源端发送 ICMP 消息,建议使用合适的 MTU。后端服务器只需解封装数据包——无需与负载均衡器建立双向隧道。
一台配备 10Gbit/s 网络接口的服务器应能够支持超过 100Gbit/s 出口带宽的 HTTP 服务,这是因为大多数互联网流量的不对称性。对于较小的服务,一两台普通的虚拟机很可能就能处理每秒数吉比特出口流量的服务。
如果一个实例不足,可以使用路由器的 ECMP 功能添加更多服务器以水平扩展容量(并提供冗余)。支持 802.3ad 链路聚合接口和 802.1Q VLAN 中继(参见 examples/ 目录)。
无需内核模块或复杂设置,但为了获得最佳性能,建议使用支持 XDP 原生模式驱动的网卡(例如:mlx4、mlx5、i40e、ixgbe、ixgbevf、nfp、bnxt、thunder、dpaa2、qede)。完整列表见 XDP 项目驱动支持页面。
目标/状态
- ✅ 单一二进制文件,部署简单
- ✅ 使用 Maglev 哈希算法实现稳定的后端选择
- ✅ 路由健康注入自动处理;无需运行 ExaBGP 等其他软件
- ✅ 侵入性最小;无需修改均衡器上的 iptables 规则
- ✅ 后端服务器除了将 VIP 添加到环回设备/使用三层分发时终止隧道外,无需任何修改
- ✅ 健康检查是针对后端服务器上的 VIP 进行,而非其真实地址
- ✅ 内置 HTTP/HTTPS、半开 SYN 探测以及 UDP/TCP DNS 健康检查
- ✅ 使用 eBPF/XDP 在内核中完成数据包交换;原生模式驱动避免 sk_buff 分配
- ✅ 支持多 VLAN
- ✅ 支持低带宽/开发用途的多网卡
- ✅ 支持带标签/绑定的网络设备,可实现高可用/高带宽
- ✅ 通过 Web 控制台、Elasticsearch 日志记录(开发中)和 Prometheus 指标实现可观测性
- ✅ 支持 IPv6,且能够混合使用 IPv4 和 IPv6 后端配合任意类型的 VIP
- ✅ 支持三层流量分发,包括 IP-in-IP、GRE、FOU 和 GUE。
快速开始
为获得最佳效果,应禁用/卸载 irqbalance。
您需要选择一个主 IP 传递给均衡器。该 IP 用于 BGP 路由器 ID。
一个简单的示例,服务器使用单个无标签以太网接口:
apt-get install git make libelf-dev golang-1.20 libyaml-perl libjson-perl ethtool(或您的发行版等价包)ln -s /usr/lib/go-1.20/bin/go /usr/local/bin/go(确保 Go 二进制文件在 PATH 中)git clone https://github.com/davidcoles/vc5.gitcd vc5/cmdcp config.sample.yaml config.yaml(编辑 config.yaml 以满足您的需求)make(下载 libbpf 库,构建二进制文件和 JSON 配置文件)./vc5 10.1.10.100 config.json eth0(根据您的服务器 IP 和以太网接口进行调整)- Web 控制台默认位于负载均衡器服务器的 80 端口
- 将您的 VIP 添加到后端服务器的环回设备(例如:
ip addr add 192.168.101.1/32 dev lo) - 配置网络/客户端,将 VIP 流量发送至负载均衡器,可通过 BGP(参见配置文件)或静态路由实现
使用最新 Github 版本(为 x86-64 编译)的二进制文件几乎肯定更简单。该版本已在生产环境中测试,应可靠。请使用标签发布中的 config.pl 脚本确保您的配置与此版本兼容(当然,您也可以按自己偏好生成 JSON 配置)。
如果更新了 YAML 配置文件并重新生成 JSON(make config.json),可以通过向进程发送 SIGINT(Ctrl-C)或 SIGUSR2 来重新加载新配置。SIGQUIT(Ctrl-\)或 SIGTERM 会使进程优雅地关闭 BGP 连接并退出。
一个更复杂的示例,使用包含两个接口(我的测试服务器上是 Intel X520 10Gbps)的 LACP 绑定以太网设备,启用原生 XDP 驱动模式并带有标签 VLAN:
config.yaml 中 vlans 条目:
vlans:
10: 10.1.10.0/24
20: 10.1.20.0/24
30: 10.1.30.0/24
命令行:
./vc5 -n 10.1.10.100 config.json enp130s0f0 enp130s0f1
二进制文件会通过查找具有 IP 地址且地址包含在配置文件 VLAN 前缀中的设备来检测您的 VLAN 接口。如果使用单独的无标签物理接口,现在应能透明工作,无需额外配置,只需在命令行中列出所有接口,以便 eBPF 代码加载到每个接口中。
由于连接状态按核心跟踪(BPF_MAP_TYPE_LRU_PERCPU_HASH),您应确保 RSS(接收端缩放)能够在 LACP 拓扑变化时,始终将流的包路由到同一 CPU 核心。禁用 irqbalance,确保每个接口的通道设置相同(ethtool -l/-L),并且 RSS 流哈希重定向一致(ethtool -x/-X)。
可以通过启动一个到一组后端服务器的长连接(例如使用 iperf 配合 -t 选项)来测试设置,然后在配置文件中用星号禁用所选后端(参见 doc/servers.md),确定负载均衡器上接收该流的接口(例如 watch -d 'cat /proc/interrupts | grep enp130s0f' 并查找快速增长的 IRQ 计数器),然后将该接口从 LACP 中移除(ifenslave -d bond0 enp130s0f0)。您应看到该流移动到另一个网络接口,但仍命中同一核心。
当后端位于多个子网时,为获得最佳性能,应确保所有 VLAN 都在单个中继接口上带标签(如果有多个物理接口则使用 LACP 绑定),并在配置文件的 vlans 部分指定子网/VLAN ID 映射。
如果无法做到(例如在 vSphere 上创建中继接口不太容易),则可以将每个子网分配给不同的无标签接口:
./vc5 10.1.10.100 config.json eth0 eth1 eth2
背景/更多信息
Patrick Shuff 的 "Building a Billion User Load Balancer" 演讲 和 Nitika Shirokov 的 Katran 演讲 中讨论了所用概念的良好总结。
包含基本 Web 控制台和 Prometheus 指标服务器:
现已加入实验性的 Elasticsearch 日志记录支持(直接写入集群,无需抓取系统日志)。每次对后端服务器的探测都会被记录,因此如果某个后端宕机,您可以精确看到返回的错误,以及各种其他情况。这需要大量改进和更合理的日志参数命名等(如果您有任何见解,请随时联系),但应该能够深入了解系统运行状况——这是我第一次尝试创建 Kibana 仪表盘,非常笨拙:
性能
主要使用 Icecast 后端服务器进行测试,客户端拉取混合低比特率和高速比特率流(48kbps - 192kbps)。
一台使用 XDP 通用驱动的 VMWare 虚拟机(4 核,8GB)似乎能够支持 10 万并发客户端,通过负载均衡器的流量为 380Mbps/70 万 pps,后端直接到客户端的流量为 8Gbps。
在一台(非虚拟化)Intel Xeon Gold 6314U CPU(2.30GHz,32 物理核心,开启超线程后 64 逻辑核心)和 Intel 10G 4P X710-T4L-t 以太网卡上,我能够运行 70 万个流,入站流量 2Gbps/380 万 pps,出站流量 46.5Gbps。服务器空闲率超过 90%。不幸的是,我没有更多资源来创建更多客户端/服务器。
操作
有三种操作模式:简单模式、VLAN 模式和多网卡模式。在简单模式下,所有主机必须与负载均衡器的主 IP 处于同一子网。在 VLAN 模式下(通过在 YAML/JSON 配置文件的 "vlans" 部分声明条目启用),服务器条目必须匹配 VLAN/CIDR 子网条目。需要在操作系统中创建带 VLAN 标签的接口,并分配子网内的 IP 地址。在多网卡模式下,子网以与 VLAN 相同的方式分配 ID,但使用 bpf_redirect() 将流量从适当配置的接口发送出去(而不是更改 VLAN ID 并使用 XDP_TX)。
在 VLAN 模式下,所有发往负载均衡器的流量都需要在带标签的 VLAN 上(尚不支持 802.1Q 的推送或弹出)。