L3 路由器支持 ECMP¶
蓝图: https://blueprints.launchpad.net/neutron/+spec/support-for-ecmp
Launchpad Bug: https://bugs.launchpad.net/neutron/+bug/1880532
ECMP 是一种路由技术,允许流量通过多个不同的链路到达相同的目标地址。Neutron 不需要计算等价路由路径,而是将这部分工作交给使用 ECMP API 的应用程序。Neutron 只需要接收这些参数并配置路由器。由于我们在 Linux 中通过 iproute2 实用程序提供了“ip route”命令,Neutron 可以简单地使用 pyroute2 并将路由条目添加到 Neutron 路由器命名空间来解决 ECMP。
当前此功能设计用于支持 Octavia 的多活方案,允许 Octavia 中的负载均衡器同时具有多个 amphora。通过在路由器中配置 ECMP 路由,多个 amphora 可以同时拥有一个虚拟 IP,以服务需要高并发支持的一组功能。
注意
标有 [P2] 的项目指的是优先级较低的功能,只有在初始发布后才会设计/实现。
[P2] 目前等价路由是一个简单的 5 元组,这意味着如果我们有一个 <nexthop> 不可达并将其从 ECMP 路由中删除,所有连接都会被重新分配。为了避免这种情况,我们打算使用一致哈希而不是原始方案。该方案基于 iptables-1.4.15 或更高版本中添加的 hmark。请参阅 iptables 的历史文件 [1]。
然后此规范描述了如何在 Neutron 中实现 ECMP。
问题描述¶
Octavia 提出了一个在 [2] 上主动-主动负载均衡设计。
拓扑描述¶
Tenant Backend
+----------------+ Network
| | +
Internet+-------------->+ router/gw +----------------->
| | ECMP |
+----------------+ |
|
Management |
Network |
+ |
| | +----------+
| +-----------------------+ | | Tenant |
| +----+ +---------+ <---------+Service(1)|
| |MGMT| loadbalancer(1) | VIP|Back| | | |
<----------+ IP | | | IP +---------> +----------+
| +---------------------------------+ |
| | | +----------+
| | | | Tenant |
| | ICMP <---------+Service(2)|
| | DETECT | | |
| | | +----------+
| | |
| +-----------------------+ v | +----------+
| +----+ +---------+ | | Tenant |
| |MGMT| loadbalancer(2) | VIP|Back| <---------+service(3)|
<----------+ IP | | | IP +---------> | |
| +---------------------------------+ | +----------+
| | |
| | |
| +-------------+ | | ● ● ●
| |Octavia Lbaas| | |
<---------+ Controller | ● ● ● | ICMP |
| +-------------+ | DETECT | +----------+
| | | | Tenant |
| | <---------+Service(M)|
| | | | |
| +-----------------------+ v | +----------+
| +----+ +---------+ |
| |MGMT| loadbalancer(n)| VIP|Back| |
<----------+ IP | | | IP +--------->
| +---------------------------------+ |
+ +
该程序提出了这样一个方案
多个负载均衡服务器在一个 vip-subnet 中,共享一个虚拟 IP 和一个或多个后端池来响应客户端的请求,并且每个负载均衡器都有自己的 IP 地址。
客户端将请求发送到 VIP,然后路由器将每个请求分发到配置了正确 VIP 的负载均衡服务器。
最终,负载均衡服务器将请求分发到后端。负载均衡器和租户服务 vm 可以位于同一个子网或不同的网络中。
在这种情况下,Octavia 需要路由器支持 ECMP 以分发请求。因此,Octavia 可以向 Neutron 发送一个创建 ECMP 路由的请求,然后 Neutron L3 代理在 Neutron 路由器的命名空间中执行命令以创建 ECMP 条目,使用 VIP 作为路由条目的目标 IP,以及几个负载均衡器的 IP 作为 nexthop IP。因此,具有 VIP 作为其目标的那些请求可以分发到每个负载均衡器。
整个过程实现了两级负载均衡,即负载均衡器之间的负载均衡和后端真实服务器之间的负载均衡
[P2] 基于当前生产环境中的公共云运营商实现,租户通常只看到同一个网络中的 IP,因此考虑到相同的广播域,路由器需要在相应的接口上启用代理 ARP(用户需要自行禁用 nexthop 中 vm 的代理 ARP 功能)
用户工作流程¶
通常,用户可以将 ECMP 功能用于自己的目的。为了将 ECMP 条目放入路由器命名空间,用户可以使用命令设置具有相同目标的路由
openstack router add route \
--route destination=20.0.20.0/24,gateway=12.0.0.11 \
--route destination=20.0.20.0/24,gateway=12.0.0.12 router-ecmp
并使用以下命令撤销 ECMP 条目
openstack router add route \
--route destination=20.0.20.0/24,gateway=12.0.0.11 \
--route destination=20.0.20.0/24,gateway=12.0.0.12 router-ecmp
有关路由器相关的 OSC 的更多信息,请阅读 [3]。
Octavia 用例的集成序列图如下
+------+ +--------+ +-------+ +--------+ +-------+ +------------+
|client| |Octavia | |Neutron| |LB Node | |qrouter| |service pool|
+------+ +---+----+ +---+---+ +---+----+ +---+---+ +------+-----+
|create LB | | | | |
+-------------> | create ecmp | | | |
|service +--------------> | | |
| | LB server boot | | |
| +--------------+---------->+ | |
| | | set ecmp route | |
| | ecmp done +-----------+--------->+ |
| +<-------------| | | |
| | LB server boot done | | |
|LB service done+<-------------+-----------+ | |
+<--------------+ | | | |
| | | | | |
| | | | | |
|sending request| | | | |
+---------------------------------------------------->| |
| | | | pick a LB node |
| | | +<---------| |
| | | | pick a service node |
| | | +---------------------->+
| | | | |response |
| | | +<----------------------+
| | response | | | |
+<-----------------------------------------+ | |
| | | | | |
| | | | | |
v v + v v v
假设用户有一组需要多活负载均衡方案的服务,因此用户向 Octavia 发送请求以创建负载均衡器,指定拓扑为多活。并向 Octavia 发布一个 vip-subnet 以分配 IP 或直接发布一个由 Octavia 定义的虚拟端口,然后用户需要提交诸如池、成员、监听器等参数,但后者与 Neutron 无关,您可以在 Octavia 文档中找到它们。
在 Octavia 创建负载均衡器时,它还会向 Neutron 发送一个 update_router 请求或一个 add_extraroutes 请求,发布几个具有相同 destination 参数的 routes 条目,并将负载均衡器的 IP 作为 nexthop 参数。
Neutron 接收到来自 Octavia 的请求,通过计算是否存在具有相同目标地址的多个路由来确定是否添加 ECMP 路由,确保路由器将具有 VIP 作为其目标的那些数据包分发出去。
当用户删除多活负载均衡器时,这些 ECMP 路由将被删除,并且在添加或删除负载均衡节点时可以进行修改。
数据流¶
[P2](如果位于同一个网络上,使用 ARP 代理)客户端请求 VIP 的 mac 地址并基于此 mac 地址访问服务,路由器将使用网关 MAC 地址进行响应。
客户端的数据报首先将被传输到路由器。
路由器网关检查 ECMP 路由条目,然后将客户端的数据包转发到负载均衡器。
负载均衡器接受来自客户端的连接,接收流量,然后将其分发到后端服务器池。
来自后端服务器池的回复流量通过负载均衡器,然后到达路由器(如果位于同一个网络上,则直接返回到内网客户端),这些数据包最终由路由器转发回去。
提议的变更¶
概述¶
在服务器端¶
服务器端无需进行任何更改。
在代理端¶
修改 L3 代理中处理 router_update 事件的逻辑,以支持在路由器中添加 ECMP 路由。RouterInfo 中的 routes_updated 函数的行为如下
当发现有多个路由具有相同的目标地址时,L3 代理应执行一个 pyroute2 代码,如下所示
ip.route('replace', dst='<destination_ip>',multipath=[{"gateway":
"<nexthop1>"},{"gateway":"<nexthop2>"}])
然后命名空间中将存在一个 ip route 条目,如下所示
<vip> proto static
nexthop via <nexthop_ip1> dev qr-xxxxxxxx-nn weight 1
nexthop via <nexthop_ip2> dev qr-xxxxxxxx-nn weight 1
然后路由器会随机选择一个 <nexthop_ip> 并将其 mac 地址填充到包的 dst_mac 地址中,当它想要到达 <destination_ip> 时。
[p2]为了在删除负载均衡节点时保持连接,请使用 iptables 而不是简单的 ip route 条目。
使用 HMARK 在 mangle 表中标记流,fwmark 值由源地址确定。
通过 fwmark 值将流分发到不同的表。
存在 fwmark 值和表值之间的映射
为每个表提供一个默认的 nexthop ip。
当 nexthop 不可达时,修改 fwmark 值和表值之间的映射。
[p2]为了让同一网络中的流量通过路由器,L3 代理还将让路由器通过设置命令使用 Proxy ARP
sysctl -w net.ipv4.conf.<NIC_1>.proxy_arp_pvlan=1
<NIC_1> 是路由器接口的名称,该接口连接到目标子网。例如,路由器 R1 连接到子网 sub-1,其 cidr 为 10.10.10.0/24,因此路由器相关的命名空间中将存在一个虚拟网络接口设备 qr-abcdefgh 作为子网 sub-1 的网关,然后添加一个目标为 10.10.10.5/32 的 ECMP 路由,该目标位于子网 sub-1 的范围内,此时将执行上述命令,<NIC_1> 将为 qr-abcdefgh。
为了使 ARP 代理可选,在 L3Agent.ini 中添加一个配置选项
[ECMP] router_interface_arp_proxy = True
数据模型影响¶
无
REST API 影响¶
以下 REST API 将受到影响
PUT /v2.0/routers/<router_id>/add_extraroutes
PUT /v2.0/routers/<router_id>/remove_extraroutes
PUT /v2.0/routers/<router_id>
以上三个 API 是当前用于添加/删除自定义路由的方法。请参阅 [4] 上 extraroutes 的用法。(第三个 API PUT /v2.0/routers/<router_id> 不建议用于添加路由)
在 ECMP 路由实现之前,当 L3 代理接收到具有相同目标地址和不同 nexthop 的多个路由条目时,它只会保留其中一个条目,或者用新的条目替换现有条目。但现在经过这些更改,路由器中将存在一个 ECMP 路由。因此,您可以添加一个如下所示的 ECMP 路由条目
PUT /v2.0/routers/{router_id}/add_extraroutes
{ "router":
{ "routes":
[ { "destination": "192.168.1.6/32",
"nexthop": "192.168.1.88" },
{ "destination": "192.168.1.6/32",
"nexthop": "192.168.1.99" }
...
]
}
}
然后您可以在路由器相关的命名空间中找到 ECMP 路由
#ip route
192.168.1.6/32 proto static
nexthop via 192.168.1.88 dev qr-9adb238b-c2 weight 1
nexthop via 192.168.1.99 dev qr-9adb238b-c2 weight 1
为了使此行为更改可发现,将添加一个名为“ecmp_routes”的 shim 扩展。 [p2]为了使 ARP 代理行为可发现,将添加一个名为“ecmp_arp”的 shim 扩展,当配置文件中的相关选项 router_interface_arp_proxy 为 False 时,它将被动态删除。
实现¶
负责人¶
XiaoYu Zhu
工作项¶
L3 代理更新
测试
文档
测试¶
Tempest 测试¶
Tempest 测试
功能测试¶
需要编写新的测试
文档影响¶
用户文档¶
用户文档
API 参考
开发人员文档¶
需要 devref 文档