Katran:构建高性能第4层负载均衡转发平面
ccwgpt 2025-07-23 13:18 4 浏览 0 评论
Katran是一个C++库和BPF程序,用于构建高性能第4层负载均衡转发平面。Katran 利用XDP infrastructure 内核提供内核内设施以实现快速数据包处理。
Katran 的主要特点
- 速度极快(特别是在驱动程序模式下使用 XDP)。
- 性能随 NIC 的 RX 队列数量线性扩展。
- RSS 友好封装。
请参阅下面的详细功能描述:
安装
当前测试的发行版:Ubuntu 20.04
要求:
- 最新的 Linux 内核 (5.6+)
- 最新版本的 clang 编译器 (6.0+) 对于 ubuntu 如果不确定运行sudo apt install build-essential
构建.sh
该脚本是一个简单的包装器getdeps.py(请参阅下一节)。它需要您的 PATH 中包含 python3.6 或更高版本。
要安装依赖项,请运行: ./build.sh install
构建: ./build.sh <params>
如果没有添加标志,则使用该--allow-system-packages标志执行默认构建: ./build.sh
要执行更复杂的操作或了解所有内容是如何构建的,您可以阅读 getdeps.py 部分和脚本。
获取deps.py
Meta 的许多 OSS 工具都使用此脚本。它将首先下载并构建所有必需的依赖项,然后调用 cmake 等来构建 katran。这将有助于确保您使用所有依赖库的相关版本进行构建,同时考虑到系统上本地安装的版本。
它是用 python 编写的,因此您的 PATH 中需要 python3.6 或更高版本。它适用于 Linux、macOS 和 Windows。
katran 的 cmake 构建的设置保存在其 getdeps 清单中
build/fbcode_builder/manifests/katran,如果需要,您可以在本地编辑。
该脚本将首先下载并构建所有必需的依赖项,然后调用 cmake 等来构建 katran。这将有助于确保您使用所有依赖库的相关版本进行构建,同时考虑到系统上本地安装的版本。
当前需要 python 3.6+ 在您的路径上。
python3 ./build/fbcode_builder/getdeps.py --allow-system-packages build katran
它将输出放入暂存区:
- installed/katran/lib/
您还可以指定一个--scratch-path参数来控制用于构建的临时目录的位置。您可以从日志中或使用以下命令找到默认的临时安装位置python3
./build/fbcode_builder/getdeps.py show-inst-dir
还有 --install-dir一些--install-prefix参数可以提供对安装目录的更细粒度的控制。但是,鉴于 katran 不提供提交之间的兼容性保证,我们通常建议构建库并将其安装到临时位置,然后将项目的构建指向此临时位置,而不是在传统的系统安装目录中安装 katran。例如,如果您使用 CMake 进行构建,则可以使用该CMAKE_PREFIX_PATH变量来允许 CMake 在构建项目时在此临时安装目录中查找 katran。
如果您想再次调用以进行迭代,则在临时构建目录中cmake有一个有用的脚本输出。run_cmake.py您可以从日志中或使用以下命令找到临时构建目录python3
./build/fbcode_builder/getdeps.py show-build-dir
build_katran.sh(已弃用)
要构建和安装 katran 库和 thrift/gRPC 示例 - 您需要运行build_katran.sh脚本。
它应该处理所有必需的依赖关系。如果您需要为其他 Linux 发行版构建它,则需要确保已安装: - folly - 最新版本的 clang 编译器(6.0+) - glog/gtest/gflags/elf 库
另外,如果你想构建示例,fbthrift也gRPC必须安装!
当我们在 CentOS 上运行 Meta 的 CI 时,我们会尽力支持在最新 Ubuntu 版本上构建 OSS。如果您对构建有任何问题或需要较旧的 Ubuntu 版本 - 打开 github 问题或最好向我们发送 PR :)
第 4 层负载均衡背后的动机
第 4 层负载均衡器 (lb) 可以轻松横向扩展第 7 层负载均衡器(终止 TCP 会话的负载均衡器)。与其他缩放 L7 lb 技术相比,L4 lb 的优点在于:
- 与 DNS 相比,它不需要等待 TTL 来重定向来自失败的 L7 lb 的流量。
- 与基于任播的解决方案相比,L4 lbs 对网络相关问题(这会触发大规模 ECMP 重新洗牌)更具弹性/能够更好地处理从池中添加/删除 L7 lbs,并为不平等负载平衡提供更好的支持。
katran运行环境要求
katran 正常工作有特殊要求。然而,我们确实相信该库的大多数潜在用户都可以轻松满足他们的要求:
- katran 仅在 DSR(直接服务响应)模式下工作。
- 网络拓扑应基于 L3(机架交换机顶部上方的所有内容都应进行路由)。这是因为我们正在“卸载”将数据包发送到真实服务器的路由决策到第一个路由设备(通过无条件从 katran 发送所有数据包)。
- katran 不支持分段(它不能转发分段数据包,如果生成的数据包大小大于 MTU,也不能自行分段)。这可以通过增加网络内的 MTU 或通过更改 L7 磅的广播 TCP MSS 来缓解(即使您增加了 MTU,也建议这样做,因为它将防止某些客户端出现与碎片相关的问题。例如,如果不是默认 TCP MSS 1460(对于 ipv4),您将通告 1450 - 它将帮助PPPoE连接后面的客户端)。
- katran 不支持带有 IP 选项集的数据包。
- 最大数据包大小不能大于 3.5k(默认为 1.5k)。
- katran 的构建假设是它将用于“棒上的负载均衡器”场景:其中单个接口将用于“从用户到 L4 lb(入口)”和“从 L4 lb 到 L7 lb”的流量(出口)。”
L4负载均衡网络拓扑
脚步:
- katran收到数据包
- 检查数据包的目的地是否配置为 VIP(虚拟 IP 地址 - 服务的 IP 地址)。
- 对于发往 VIP 的传入数据包 - katran 会检查它之前是否看到来自同一会话的数据包,如果有 - 它将数据包发送到同一个真实服务器(实际服务器/l7 lb,然后处理/终止 TCP 会话)。
- 如果是新会话 - 从数据包中的 5 个元组计算哈希值。
- 使用此哈希值 - 选择一个真实的服务器。
- 使用此查找信息更新会话表,以便 katran 可以简单地查找会话中下一个数据包的此信息,而不必再次计算哈希值。
- 将数据包封装在另一个IP数据包中并发送给真实的。
L4负载均衡失败场景
由于我们仅使用数据包标头中的数据来计算哈希值,然后使用该哈希值来选择真实服务器,因此不同的 L4 lb 在真实服务器选择中是一致的,即使彼此之间没有显式状态共享。此功能允许我们重新启动/耗尽单个 L4 磅,而不影响 TCP 会话,转至 L7 磅。
katran的功能描述
- 快速: katran 使用 XDP 进行数据包转发,这允许在网络接口卡 (NIC) 接收到数据包之后并且在内核有机会运行之前运行数据包处理例程(当 XDP 在“驱动程序模式”下工作时,katran 支持以及“通用 XDP”操作模式(与“驱动程序模式”相比,性能有所下降))。
- 性能与 NIC 的 RX 队列数量成线性关系: XDP 的工作方式是在每个接收到的数据包上调用 BPF 程序,如果您的 NIC 有多个队列,则每个队列的 BPF 程序将被独立调用。由于 katran 是完全无锁的,并且使用每个 CPU 版本的 BPF 映射 - 它可以线性扩展。
- RSS 友好封装: katran 使用 ipip 封装从 L4 lb 到 L7 lb 进行数据包转发。但是,为了能够在 L7 lb 接收端与 RSS 结合使用,而不是为每个 ipip 数据包使用相同的源,katran 制作了一个特殊的一种,以这种方式,不同的流将具有不同的外部(ipip)源IP,但同一流中的数据包将始终具有相同的。
- 固定大小(大小可在启动时配置)连接跟踪表,具有用于驱逐旧条目的 LRU 策略。
- 修改后的 Maglev 连接散列:它为我们提供了在发生故障时良好的弹性和出色的负载平衡功能。哈希经过修改,能够支持后端(L7 磅)服务器的不等权重
- 接收路径上无需繁忙循环:如果没有流量可供服务,您的负载均衡器将几乎不会消耗任何 CPU。
- katran(以及一般的 XDP)允许您在同一服务器上运行任何应用程序,而不会造成任何性能损失(与其他一些“内核旁路”技术相比)
使用案例
katran 库使用示例 -
在此存储库中,我们提供了两个简单的示例(example和example_grpc目录),说明如何在生产中使用 katran 库。它们基于 thrift 和 gRPC RPC 框架。该包装器的实际代码很简单,它们只是在公开的 RPC 端点与 katran 库的内部方法之间执行一对一的转换。
示例场景:
我们将使用 VM 来说明如何使用 katran 的简单步骤。我们将展示:
- 如何在独立模式下使用 katran。
- 如何在共享模式下使用 katran(我们还提供了 root xdp 程序的示例)。
- 如何使用 katran 的健康检查转发平面
- 我们将用一个真实的配置一个 VIP,并显示 tcpdump 的输出以显示数据包在线路上的外观。
开始卡特兰
第一步确保 BPF 的 jit 已启用(以获得最佳性能):net.core.bpf_jit_enable sysctl 应设置为 1:
sysctl net.core.bpf_jit_enable=1
我们将在我们的示例中使用 gRPC(但所有这些步骤也适用于 thrift。它们的编写是为了外观和感觉相似(具有相同的标志、相同的行为等)。唯一的区别是实际二进制文件所在的位置)。
首先,我们需要构建 cli 工具,它允许我们与服务器进行通信。您必须安装“go 工具链”以及能够构建 gRPC 客户端的所有必需库(
https://grpc.io/docs/tutorials/basic/go.html)。要构建 cli 工具,您需要从目录运行脚本example_grpc:
./build_grpc_client.sh
在启动 katran 之前,您需要收集这些数据(这里我们描述手动步骤。但是,强烈建议您在生产部署中使用某种形式的预运行脚本收集这些数据):
- 默认网关的 MAC 地址:katran 将所有路由卸载到默认网关。它通过将所有内容(我们确定为流向配置的 VIP 的流量)发送给它来实现这一点。您可以通过以下命令获取此信息:
$ ip route | grep default
default via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric 100
$ ip n show | grep 10.0.2.2
10.0.2.2 dev enp0s3 lladdr 52:54:00:12:35:02 REACHABLE
在此示例中,默认路由器的 MAC 地址是52:54:00:12:35:02
- 您需要知道您的 NIC 有多少个接收队列以及它们与 CPU 之间的映射:katran 内置了优化,因此它只会为实际转发流量的 CPU 分配内存。如果您不需要此优化 - 您可以通过指定所有 CPU 都用于转发来省略此步骤(例如:在 4 CPU 服务器上只需指定 -forwarding_cores="0,1,2,3" 标志)
如果您想使用内存优化,这里有一个示例说明如何实现此目的:您需要熟悉RSS 以及IRQ 亲和性(“固定”)的工作原理。
要获取当前为您的接口配置了多少个 rx 队列的列表,您可以运行以下命令:
ethtool -l <interface name>
假设您有一台具有 4 个 CPU 的服务器,但您的 NIC 只有一个 RX 队列。下一步是获取 NIC 已使用的 IRQ 号,为此您可以检查/proc/interrupts (在本例中 enp0s3 是一个接口)
$ cat /proc/interrupts | grep enp0s3
19: 740509 IO-APIC 19-fasteoi enp0s3
第一个字段是 IRQ 号。在此示例中enp0s3使用 IRQ 19。如果您的 NIC 具有多个 rx 队列,您将在此输出中看到多行。
下一步是将此 IRQ“固定”到特定 CPU(如果您的 NIC 有多个队列(例如 N 个)/您将看到上一个命令中的多个 IRQ - 您将需要重复此步骤 N 次。为了获得最佳性能,您需要在CPU和IRQ之间进行1对1的映射,并且它们不应该重叠(例如,单个CPU不应该分配给多个IRQ)。如果您正在运行 irqbalance(ubuntu/systemd 上默认) - 建议将其关闭
$ sudo systemctl stop irqbalance
$ sudo systemctl disable irqbalance
$ cd /proc/irq/19 # 19 is an IRQ number from previous step
$ sudo sh -c "echo 1 > smp_affinity" # allow only cpu 0 (smp_affinity is a bitmask) to handle IRQ 19
- 如果您使用具有多个物理 CPU(因此多个 NUMA 域)的服务器,您需要收集 CPU 到 NUMA 节点映射(如果您想使用 NUMA 提示进行内存分配,以实现最大性能。如果您不需要此优化 - 只需忽略-numa_nodes cli 标志)例如对于 cpu0,此信息(NUMA id)位于此处:
$ cat /sys/devices/system/cpu/cpu0/topology/physical_package_id
收集 cpu 和 NUMA 节点之间的映射后,对于 -forwarding_cores 列表中 -numa_nodes 中相同位置的每个 cpu 将是该 cpu 的 NUMA ID。
例如:我们有一台服务器,有4个转发cpu 0,1,2,3。cpus 0 和 2 属于 NUMA 节点 0 cpus 1 和 3 - 属于 NUMA 节点 1。对于这种情况,cli 标志如下所示: -forwarding_cores="0,1,2,3" -numa_nodes="0,1,0 ,1"
您需要创建隧道接口(katran 使用 ipip 封装进行转发和运行状况检查)。在负载均衡器方面,此隧道将用于运行状况检查转发(如果您不需要从中运行状况检查,则可以省略此步骤(通过传递 -hc_forwarding=false)。如果您愿意,这可能是理想的选择使用专用服务器进行健康检查和负载均衡器从它们获取世界状态(在这种情况下无需运行本地健康检查))
真实端必须配置相同的接口,以便能够接收 ipip 数据包并对其进行解封装。
$ sudo ip link add name ipip0 type ipip external
$ sudo ip link add name ipip60 type ip6tnl external
$ sudo ip link set up dev ipip0
$ sudo ip link set up dev ipip60
如果您需要运行 bpf 程序进行健康检查转发 - 您需要在出口接口上附加 clsact qdisc(本例中为 enp0s3):
$ sudo tc qd add dev enp0s3 clsact
- 禁用接收卸载:需要禁用接收卸载,因为 Katran 对它处理的数据包的最大大小施加了限制。如果您在驱动程序模式下运行 Katran,则必须禁用大型接收卸载 (LRO)。
$ /usr/sbin/ethtool --offload <interface name> lro off
如果您在通用模式下运行 Katran,则必须禁用通用接收卸载 (GRO)。
$ /usr/sbin/ethtool --offload <interface name> gro off
完成所有这些准备工作后,我们准备启动 katran_server
以独立模式启动 katran
独立模式是指 katran 直接连接到接口(并且您将无法在此接口上运行任何其他 XDP 程序)
$ sudo ./build/example_grpc/katran_server_grpc -balancer_prog ./deps/bpfprog/bpf/balancer.bpf.o -default_mac 52:54:00:12:35:02 -forwarding_cores=0 -healthchecker_prog ./deps/bpfprog/bpf/healthchecking_ipip.o -intf=enp0s3 -ipip_intf=ipip0 -ipip6_intf=ipip60 -lru_size=10000
在这个例子中:
- 默认路由器的 MAC 地址是 52:54:00:12:35:02
- 仅 cpu 0 配置为转发(通过 IRQ 关联)。
- 我们想要运行健康检查 bpf 程序。
- 我们使用 enp0s3 接口进行负载平衡(数据包将在此接口上接收)。
- 之前已创建 ipip0 和 ipip60 接口用于健康检查转发。
- 连接表的大小(我们要跟踪的流数)已配置为 10000(默认为 800 万)。
启动katran是共享模式
这是运行任何 XDP 相关内容的推荐方法。此方法允许您通过执行一个简单的技巧来运行多个 XDP 程序:安装特殊的“root”xdp 程序,该程序运行 prog_array 中的程序(唯一的要求是程序需要相互了解,例如链中的第一个程序)运行结束时必须尝试运行prog_array中的其他程序)。这使我们能够在负载均衡器前面运行基于 XDP 的防火墙。在此存储库中,我们提供了此类“root”xdp 程序的简单示例。我们配置一个小的 prog_array 并尝试从那里运行 xdp 程序。它位于katran/lib/bpf/xdp_root.c
对于我们的示例,我们将使用存储库中的 ./install_xdproot.sh 脚本。该脚本假设“root”程序将附加到 enp0s3 接口,并且它将自动附加 bpffs(BPF 文件系统)并附加共享 prog_array(其他 XDP 程序将在其中注册自己的数组)
./install_xdproot.sh
您将看到 bpffs 已被安装,并且在此文件系统上已创建特殊文件:
$ mount | grep bpf
bpffs on /sys/fs/bpf type bpf (rw,relatime)
$ ls -alh /sys/fs/bpf/jmp_eth0
-rw------- 1 root root 0 Mar 18 18:01 /sys/fs/bpf/jmp_eth0
现在您需要使用特殊标志运行 katran 二进制文件,以便它知道它应该在“共享”模式下工作。这些标志是:
- -map_path- 这是由“root”xdp 程序创建的文件路径
- -prog_pos- 这是 prog_array 中的一个位置(在我们的示例中,prog 数组的大小是 3 个元素(在“root”xdp 程序中定义),我们希望负载均衡器注册为该数组中的最后一个程序(因此使用索引2). 如果需要,这允许我们在负载均衡器前面运行 2 个 xdp 程序。
$ sudo ./build/example_grpc/katran_server_grpc -balancer_prog ./deps/bpfprog/bpf/balancer.bpf.o -default_mac 52:54:00:12:35:02 -forwarding_cores=0 -healthchecker_prog ./deps/bpfprog/bpf/healthchecking_ipip.o -intf=enp0s3 -ipip_intf=ipip0 -ipip6_intf=ipip60 -lru_size=10000 -map_path /sys/fs/bpf/jmp_eth0 -prog_pos=2
配置健康检查转发
仅当您想从负载均衡器本身运行运行状况检查时才适用(例如,您已使用 -hc_forwarding=true (默认)启动它)
healthchecks 转发的工作方式是将套接字标记配置为真实服务器映射。然后,如果您想检查特定真实上 vip 的运行状况 - 您发送一个带有配置的套接字标记的数据包在我们的示例中,我们将使用一个简单的 python 程序来生成此类数据包(只是为了展示如何在带有setsockopt 的套接字)。
假设我们有两个 VIP:10.100.1.1和fc00:100::1
对于 v4 VIP,我们使用地址为实数: 10.200.200.1,10.200.200.2和 fc00:200::1
对于 v6 VIP,我们仅使用一个真实的地址:fc00:200::1
要将 so_mark 配置为实际映射,我们将使用之前构建的 go 客户端:
$ cp ./example_grpc/goclient/bin/main ./katran_goclient
$ ./katran_goclient -new_hc 10.200.200.1 -somark 1000
exiting
$ ./katran_goclient -new_hc 10.200.200.2 -somark 1001
exiting
$ ./katran_goclient -new_hc fc00:200::1 -somark 1002
exiting
要列出所有当前配置的 somark 到实际映射,您可以运行以下命令:
$ ./katran_goclient -list_hc
somark: 1000 addr: 10.200.200.1
somark: 1001 addr: 10.200.200.2
somark: 1002 addr: fc00:200::1
exiting
现在让我们打开第二个屏幕并使用过滤器“proto 4 或 proto 41”运行 tcpdump 程序,此过滤器将匹配所有 ipip 或 ip6ip6 数据包。
让我们使用这个简单的 python 脚本来模拟执行健康检查的程序 (hc_it_client.py)
#!/usr/bin/env python
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import socket
import sys
import time
SO_MARK = 36
def send_packet(fam, num, dst, fwmark):
if fam == "4":
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
else:
s = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, SO_MARK, int(fwmark))
for _i in range(0, int(num)):
s.sendto("PING", (dst, 1337))
time.sleep(1)
def main():
send_packet(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])
if __name__ == "__main__":
main()
在第一个屏幕中,让我们运行我们的辅助 python 程序来生成发往10.100.1.1和fc00:100::1(我们的 VIP)的udp 数据包
$ sudo python hc_it_client.py 4 4 10.100.1.1 1000 # 4 packets with dst 10.100.1.1 and socket mark 1000
$ sudo python hc_it_client.py 4 4 10.100.1.1 1001 # same but with socket mark 1001
$ sudo python hc_it_client.py 4 4 10.100.1.1 1002 # w/ socket mark 1002
正如预期的那样,在 tcpdump 输出中我们可以看到,根据套接字标记,数据包作为 ipip 封装到特定的实数发送
$ sudo tcpdump -ni enp0s3 proto 4 or proto 41
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s3, link-type EN10MB (Ethernet), capture size 262144 bytes
18:25:10.438333 IP 10.0.2.15 > 10.200.200.1: IP 10.0.2.15.55835 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:11.439472 IP 10.0.2.15 > 10.200.200.1: IP 10.0.2.15.55835 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:12.441076 IP 10.0.2.15 > 10.200.200.1: IP 10.0.2.15.55835 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:13.443512 IP 10.0.2.15 > 10.200.200.1: IP 10.0.2.15.55835 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:16.003227 IP 10.0.2.15 > 10.200.200.2: IP 10.0.2.15.59985 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:17.004897 IP 10.0.2.15 > 10.200.200.2: IP 10.0.2.15.59985 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:18.006895 IP 10.0.2.15 > 10.200.200.2: IP 10.0.2.15.59985 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:19.008000 IP 10.0.2.15 > 10.200.200.2: IP 10.0.2.15.59985 > 10.100.1.1.1337: UDP, length 4 (ipip-proto-4)
18:25:21.043145 IP6 fc00:33::2 > fc00:200::1: IP 10.0.2.15.53918 > 10.100.1.1.1337: UDP, length 4
18:25:22.044215 IP6 fc00:33::2 > fc00:200::1: IP 10.0.2.15.53918 > 10.100.1.1.1337: UDP, length 4
18:25:23.045364 IP6 fc00:33::2 > fc00:200::1: IP 10.0.2.15.53918 > 10.100.1.1.1337: UDP, length 4
18:25:24.047293 IP6 fc00:33::2 > fc00:200::1: IP 10.0.2.15.53918 > 10.100.1.1.1337: UDP, length 4
对于 v6 VIP
$ sudo python hc_it_client.py 6 4 fc00:100::1 1002
18:30:05.300691 IP6 fc00:33::2 > fc00:200::1: IP6 fc00:33::2.37751 > fc00:100::1.1337: UDP, length 4
18:30:06.302625 IP6 fc00:33::2 > fc00:200::1: IP6 fc00:33::2.37751 > fc00:100::1.1337: UDP, length 4
18:30:07.304750 IP6 fc00:33::2 > fc00:200::1: IP6 fc00:33::2.37751 > fc00:100::1.1337: UDP, length 4
18:30:08.306662 IP6 fc00:33::2 > fc00:200::1: IP6 fc00:33::2.37751 > fc00:100::1.1337: UDP, length 4
不支持 ipv4 封装中的 ipv6(例如,您不能拥有带有 IPv4 实数的 IPv6 VIP。但是,您可以拥有带有 IPv6 实数的 IPv4 VIP)
转发平面配置
我们将在此示例中使用简单的拓扑:
<client> ---- <net> ---- <katran> ---- <net> ---- <server>
客户端将尝试使用 VIP (10.200.200.1) 启动 ssh 会话,然后运行 scp 命令从那里复制文件。
我们将在 katran 上配置此 VIP,并使用 1 个真实的(“服务器”)
在我们的示例中我们将看到:
- 数据包如何从“客户端”转发到“服务器”。
- katran 如何配置才能使其工作。
- 封装是什么样子的。
- 必须如何配置“服务器”才能正常工作。
- 如何将回复直接从“服务器”转发到“客户端”(katran 在 DSR(直接服务器返回)模式下工作)。
让我们开始配置服务器:
- 我们需要在服务器上创建ipip接口(katran使用ipip作为数据包转发的封装)。
$ sudo ip link add name ipip0 type ipip external
$ sudo ip link add name ipip60 type ip6tnl external
$ sudo ip link set up dev ipip0
$ sudo ip link set up dev ipip60
- Linux 的具体情况是,要使 ipip 接口正常工作,它必须至少配置单个 ip。我们将配置来自 127.0.0.0/8 网络的 IP,因为这在某种程度上是人造 IP(它具有本地意义) - 我们可以在整个队列中重复使用相同的 IP -
$ sudo ip a a 127.0.0.42/32 dev ipip0
- 由于大多数时候服务器都是通过单个接口连接的 - 我们不需要 rp_filter 功能:
for sc in $(sysctl -a | awk '/\.rp_filter/ {print $1}'); do echo $sc ; sudo sysctl ${sc}=0; done
- VIP必须在真实环境中配置
$ sudo ip a a 10.200.200.1/32 dev lo
经过这 4 个步骤后,服务器已完全配置为接收来自客户端的流量。
我们看一下 katran 的配置:
- 首先你需要配置一个VIP。在我们的例子中,我们对流向 ip 10.200.200.1 和目标端口 22/tcp (ssh) 的流量感兴趣。为了与 katran 交互,我们使用基于 go 的客户端,您可以使用--helpflag 运行它以查看它支持哪些选项。
$ ./katran_goclient -A -t 10.200.200.1:22
2018/03/19 12:50:02 Adding service: 10.200.200.1:22 6
2018/03/19 12:50:02 Vip modified
exiting
在这个例子中:
- -A - 添加新服务
- -t - 新服务基于 TCP
- :22 - 我们只对目标端口 22 的流量感兴趣
如果这是基于 IPv6 的 VIP,我们需要在方括号内指定它。例如 [fc00::1]:22
- 我们需要为这个 VIP 添加一个真实的。在这种情况下:真实的 IP 地址将是 10.0.0.2。正如在我们的示例中,VIP 将只有一个实数 - 我们不会为此实数配置任何权重。
$ ./katran_goclient -a -t 10.200.200.1:22 -r 10.0.0.2
2018/03/19 12:52:59 Reals modified
exiting
- -a - 添加新的真实到指定的 VIP
- -r - 真实的ip地址
您可以获得所有 VIP 的列表以及相应的真实 w/ -l 标志 -
$ ./katran_goclient -l
2018/03/19 12:54:05 vips len 1
VIP: 10.200.200.1 Port: 22 Protocol: tcp
Vip's flags:
-> 10.0.0.2 weight 1
exiting
现在,让我们从客户端启动 ssh 会话,并查看服务器端的 tcpdump 和 katran 的统计输出。在 katran,我们将运行带有标志的客户-s端-lru。该标志将显示总数据包和字节率。以及将显示连接表命中百分比。
./katran_goclient -s -lru
summary: 0 pkts/sec. lru hit: 0.00% lru miss: 0.00% (tcp syn: 0.00% tcp non-syn: 0.00% udp: 0.00%) fallback lru hit: 0 pkts/sec
summary: 9 pkts/sec. lru hit: 88.89% lru miss: 11.11% (tcp syn: 0.11% tcp non-syn: 0.00% udp: 0.00%) fallback lru hit: 0 pkts/sec
summary: 0 pkts/sec. lru hit: 0.00% lru miss: 0.00% (tcp syn: 0.00% tcp non-syn: 0.00% udp: 0.00%) fallback lru hit: 0 pkts/sec
summary: 2 pkts/sec. lru hit: 100.00% lru miss: 0.00% (tcp syn: 0.00% tcp non-syn: 0.00% udp: 0.00%) fallback lru hit: 0 pkts/sec
在服务器端,如果我们运行 tcpdump,我们可以看到入口 ipip 数据包和出口常规 IP,目的地为客户端 -
$ sudo tcpdump -ni enp0s8 proto 4 or host 10.200.200.1
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on enp0s8, link-type EN10MB (Ethernet), capture size 262144 bytes
15:48:53.338329 IP 172.16.215.45 > 10.0.0.2: IP 10.0.0.3.11991 > 10.200.200.1.22: Flags [S], seq 3909606823, win 65535, options [mss 1460,nop,wscale 6,sackOK,TS val 10629589 ecr 0], length 0 (ipip-proto-4)
15:48:53.338438 IP 10.200.200.1.22 > 10.0.0.3.11991: Flags [S.], seq 2576041211, ack 3909606824, win 28960, options [mss 1460,sackOK,TS val 2916608748 ecr 10629589,nop,wscale 6], length 0
15:48:53.338864 IP 172.16.215.45 > 10.0.0.2: IP 10.0.0.3.11991 > 10.200.200.1.22: Flags [.], ack 1, win 4106, options [nop,nop,TS val 10629590 ecr 2916608748], length 0 (ipip-proto-4)
15:48:53.339649 IP 172.16.215.45 > 10.0.0.2: IP 10.0.0.3.11991 > 10.200.200.1.22: Flags [P.], seq 1:39, ack 1, win 4106, options [nop,nop,TS val 10629591 ecr 2916608748], length 38 (ipip-proto-4)
15:48:53.339687 IP 10.200.200.1.22 > 10.0.0.3.11991: Flags [.], ack 39, win 453, options [nop,nop,TS val 2916608749 ecr 10629591], length 0
15:48:53.350785 IP 10.200.200.1.22 > 10.0.0.3.11991: Flags [P.], seq 1:33, ack 39, win 453, options [nop,nop,TS val 2916608761 ecr 10629591], length 32
15:48:53.351821 IP 172.16.215.45 > 10.0.0.2: IP 10.0.0.3.11991 > 10.200.200.1.22: Flags [P.], seq 39:1375, ack 33, win 4106, options [nop,nop,TS val 10629603 ecr 2916608761], length 1336 (ipip-proto-4)
这里有趣的部分是 IPIP 数据包的源 - 它不等于负载均衡器的源,而是一个精心设计的源,其中前两个八位字节等于
katran/lib/bpf/balancer_const.hIPIP_*_PREFIX 宏中的 172.16(在 IPIP_*_PREFIX 宏中定义并可配置) ),最后两个的设计方式对于单个 tcp 流来说是相同的,但不同的流将具有不同的源 IP。这样做的目的是为了利用 NIC 的 RSS 功能。
简而言之,数据包流如下所示:
- 从“client”到“katran”(向网络通告 VIP 可达性),其 IP 数据包的 src 为“client”,dst 为 VIP。
- 当“katran”收到这个数据包时,它会将它们封装并发送到真实的。该数据包将被 IPIP 封装。内部标头将声明相同(“客户端”->“VIP”)。外部标头包含专门设计的源地址,目标是“服务器”的地址。
- 当服务器收到此 IPIP 数据包时,它会删除外部 ip 标头,并处理原始数据包,并在发送回复时将其直接从“VIP”发送到“客户端”。
项目地址:
https://github.com/facebookincubator/katran
相关推荐
- VUE3前端开发入门系列教程二:使用iView框架辅助开发
-
1、安装iView新框架,支持VUE3npminstallview-ui-plus2、编辑src/main.js,添加以下内容,导入js和css到项目importViewUIPlusfrom...
- 万能前端框架uni app初探03:底部导航开发
-
前言本节我们使用uniapp的底部导航功能,点击不同tab会显示不同页面,这个功能在实际项目开发中几乎是必备的。一、基础知识1.tabBar如果应用是一个多tab应用,可以通过tabBar配...
- Rust Web 开发框架,前端你可以选择哪个?
-
Rust构建一切。在如今流行的语言中,Rust可谓是将构建和高效作为自己优美的身姿在大众视野中脱颖而出。它是一门赋予每个人构建可靠且高效软件能力的语言。它有什么特性呢?高性能。Rust速度惊人且内...
- 连载:前端开发中纠结的Javascript框架(上)
-
如今,前端开发有着许许多多的框架和库。其中一些好用,一些却不尽人意。通常我们会习惯性运用某一概念,模块或句法。事实上,并没有什么万能工具。这篇文章是关于未来框架的发展趋势——那就是没有框架!我从以下几...
- 前端开发框架的演进架构:提升用户体验和开发效率
-
前端开发框架是现代Web应用开发的重要工具,它不仅可以帮助开发者构建复杂的用户界面,还能够提升用户体验和开发效率。随着Web技术的不断发展,前端开发框架也在不断演进,为开发者提供了更丰富、更高效的工具...
- Google应用Mesh-TensorFlow框架,让CNN也能处理超高分辨率图像
-
为了要处理超高分辨率医疗图像数据,Google开发了一种空间数据分区(SpatialPartition)技术,在不牺牲图像分辨率的条件下,分析超高分辨率图像。Google使用Mesh-TensorF...
- 大模型安全挑战加剧:框架层漏洞成新靶心
-
近日,360数字安全集团发布了一份关于大模型安全漏洞的报告,揭示了当前大模型及围绕其构建的框架和应用中存在的严重安全问题。报告显示,360近期研究发现了近40个大模型相关的安全漏洞,其中既包括二进制内...
- Keras 3.0正式发布:可用于TensorFlow、JAX和PyTorch
-
机器之心报道编辑:陈萍经过5个月的更新迭代,Keras3.0终于来了。「大新闻:我们刚刚发布了Keras3.0版本!」Keras之父FrancoisChollet在X上激动的...
- TensorFlow和Keras入门必读教程(tensorflow与keras版本对应)
-
导读:本文对TensorFlow的框架和基本示例进行简要介绍。作者:本杰明·普朗什(BenjaminPlanche)艾略特·安德烈斯(EliotAndres)来源:华章科技01TensorFlo...
- 谷歌官方回应“TensorFlow遭弃”:还在投资开发,将与JAX并肩作战
-
鱼羊发自凹非寺量子位|公众号QbitAI终于,谷歌出面回应“TensorFlow遭弃”传闻:我们将继续致力于将TensorFlow打造为一流机器学习平台,与JAX并肩推动机器学习研究。这段时...
- 2025 年的PHP :现代 Web 开发的强大引擎
-
程序员还在吐槽PHP过时?2025年的PHP8.4直接封神了。看看最近更新的属性钩子、强类型系统,加上Laravel这些框架,老语言早就脱胎换骨。十年前说PHP弱类型容易崩代码的,现在脸疼不?联合类...
- 前端内卷终结者?htmx如何让开发者告别200行JS只做一个按钮
-
当你用React写一个点赞按钮需要引入3个状态管理库、编写80行JSX和120行钩子函数时,htmx只需要一行HTML:<buttonhx-post="/like"hx-sw...
- NativePHP桌面版V1.0正式发布(元气桌面电脑版下载)
-
导读:各位小伙伴,使用PHP构建桌面级系统的利器,NativePHP来了。概述NativePHP是一个用于使用PHP构建桌面应用的框架。它允许PHP开发人员使用熟悉的工具和技术创建跨平台的原生应用...
- PHP Laravel框架底层机制(php基本框架)
-
当然可以,Laravel是最受欢迎的PHP框架之一,以优雅的语法和丰富的生态而闻名。尽管开发体验非常“高端”,它的底层其实是由一系列结构清晰、职责分明的组件构成的。下面我从整体架构、核心流程、...
- PHP框架之Laravel框架教程:2. 控制器、路由、视图简单介绍
-
2.控制器、路由、视图简单介绍我们先建立控制器,目录是:app/Http/Controllers,新建控制器Ding.php,代码如下:Ding.php:<?phpnamespaceA...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- VUE3前端开发入门系列教程二:使用iView框架辅助开发
- 万能前端框架uni app初探03:底部导航开发
- Rust Web 开发框架,前端你可以选择哪个?
- 连载:前端开发中纠结的Javascript框架(上)
- 前端开发框架的演进架构:提升用户体验和开发效率
- Google应用Mesh-TensorFlow框架,让CNN也能处理超高分辨率图像
- 大模型安全挑战加剧:框架层漏洞成新靶心
- Keras 3.0正式发布:可用于TensorFlow、JAX和PyTorch
- TensorFlow和Keras入门必读教程(tensorflow与keras版本对应)
- 谷歌官方回应“TensorFlow遭弃”:还在投资开发,将与JAX并肩作战
- 标签列表
-
- 框架图 (58)
- flask框架 (53)
- quartz框架 (51)
- abp框架 (47)
- jpa框架 (47)
- springmvc框架 (49)
- 分布式事务框架 (65)
- scrapy框架 (56)
- shiro框架 (61)
- 定时任务框架 (56)
- java日志框架 (61)
- JAVA集合框架 (47)
- mfc框架 (52)
- abb框架断路器 (48)
- beego框架 (52)
- java框架spring (58)
- grpc框架 (65)
- tornado框架 (48)
- 前端框架bootstrap (54)
- orm框架有哪些 (51)
- ppt框架 (48)
- 内联框架 (52)
- cad怎么画框架 (58)
- ssm框架实现登录注册 (49)
- oracle字符串长度 (48)