1. 项目缘起与核心问题拆解搞网络虚拟化的人绕不开两个东西一个是内核自带的VXLAN实现另一个是Open vSwitch的VXLAN实现。很多人在搭建overlay网络时面对这两种方案往往凭感觉选或者干脆哪个能跑通就用哪个至于为什么选它、两者到底差在哪里、性能损耗出在哪个环节基本是一笔糊涂账。我自己在早些年做跨主机容器网络方案时就在这上面栽过跟头——同一个拓扑换一种VXLAN实现方式吞吐量差了将近四成排查了半天才发现问题出在数据包在内核协议栈里的路径完全不同。这篇内容就是要把这两种VXLAN实现方式掰开揉碎讲清楚。核心关键词是VXLAN内核态实现和Open vSwitch实现我会从数据面转发路径、封装解封装机制、性能特征、适用场景几个维度做对比分析同时给出可复现的实操步骤和验证方法。适合已经了解VXLAN基本概念、正在做overlay网络选型或调优的运维和网络开发人员参考。如果你还不清楚VXLAN是什么简单说它就是一套在三层网络之上虚拟出二层网络的隧道技术把原始以太网帧封装进UDP包里传输从而让分布在不同物理主机上的虚拟机或容器感觉自己在一个二层交换机下面。为什么值得花时间深挖这两种实现的差异因为选错了方案轻则多花服务器资源重则网络抖动、丢包、延迟飙升业务侧感知就是服务间调用超时、数据库主从同步延迟。而这两种方案的差异不是配置参数级别的是架构级别的——一个走内核协议栈的轻量路径一个走用户态交换机的完整流水线。理解了这个差异你才能根据实际场景做出正确取舍。2. 两种VXLAN实现的核心机制对比2.1 内核态VXLAN轻量但功能有限Linux内核从3.7版本开始原生支持VXLAN实现方式是在内核网络协议栈里注册一个VXLAN类型的虚拟网络设备。你通过ip link add命令创建一个vxlan接口指定VNIVXLAN Network Identifier、本地隧道端点IP、远端隧道端点IP内核就会自动处理报文的封装和解封装。它的工作路径非常直接当一台虚拟机发出一个以太网帧宿主机的路由或桥接逻辑判断下一跳需要走vxlan接口内核VXLAN模块就把这个帧加上VXLAN头、UDP头、外层IP头然后从物理网卡发出去。收包方向反过来物理网卡收到UDP端口4789的包内核识别出是VXLAN报文剥掉外层头把内层帧交给对应的vxlan接口再进入桥或路由转发给目标虚拟机。整个过程完全在内核态完成没有用户态程序的参与。这意味着转发效率高因为不需要在用户态和内核态之间来回拷贝数据包。但代价是功能相对单一内核VXLAN主要做点对点和点对多点的隧道转发没有流表、没有ACL、没有QoS策略、没有复杂的overlay路由能力。你要做多租户隔离、安全组、负载均衡这些得靠上层工具配合比如用iptables做ACL用iproute2做路由策略。2.2 Open vSwitch的VXLAN功能丰富但路径更长Open vSwitch以下简称OVS是一个用户态的虚拟交换机它通过内核模块datapath和用户态守护进程ovs-vswitchd协同工作。当你在OVS网桥上配置一个VXLAN端口时报文的处理路径是这样的物理网卡收到VXLAN报文先经过内核datapath模块做快速匹配如果命中已下发的流表直接在内核态完成转发如果没有命中报文被送到用户态ovs-vswitchd由它查询完整的流表、执行动作然后把新的流表规则下发到内核datapath后续同类报文就可以在内核态快速转发了。这个设计叫慢路径与快路径分离。慢路径负责学习、决策、下发规则快路径负责高速转发。好处是功能极其灵活——你可以用OpenFlow流表定义任意转发逻辑做VLAN转换、隧道终结、ACL、镜像、QoS等。坏处是首次报文或流表未命中时会有用户态切换开销而且OVS的流表匹配比内核原生VXLAN的简单查表要复杂得多。2.3 关键差异对照表对比维度内核态VXLANOpen vSwitch VXLAN转发平面纯内核态内核快路径用户态慢路径配置方式iproute2命令ovs-vsctl OpenFlow流表功能丰富度基础隧道转发流表、ACL、QoS、镜像等首次转发延迟低较高需流表下发稳态吞吐量高略低取决于流表命中率多租户支持需配合其他工具原生支持运维复杂度低中高适用场景简单overlay、点对点隧道复杂虚拟网络、SDN环境这张表是选型的核心依据。如果你的场景就是几台主机之间打通二层网络没有复杂的策略需求内核态VXLAN足够用且性能更好。如果你要做多租户云平台、需要精细的流控和安全策略OVS是更合适的选择。3. 实操环境搭建与配置过程3.1 环境准备与基础网络规划我用的测试环境是三台Linux主机操作系统版本是较新的长期支持版内核版本高于4.15。每台主机两块网卡一块用于管理流量一块用于VXLAN隧道流量。IP规划如下主机A的隧道端点IP为10.0.0.1主机B为10.0.0.2主机C为10.0.0.3。VNI统一用100虚拟网络子网用192.168.100.0/24。先确认内核VXLAN模块已加载modprobe vxlan lsmod | grep vxlan如果输出里有vxlan模块信息说明加载成功。没有的话需要检查内核编译选项一般主流发行版都默认支持。注意生产环境建议把vxlan模块加入开机自动加载避免重启后隧道不通。可以在/etc/modules-load.d/下新建一个conf文件写入vxlan。3.2 内核态VXLAN配置步骤在三台主机上分别执行以下命令创建vxlan接口。以主机A为例ip link add vxlan100 type vxlan \ id 100 \ local 10.0.0.1 \ dstport 4789 \ nolearning ip link set vxlan100 up ip addr add 192.168.100.1/24 dev vxlan100这里有几个参数需要解释。id 100指定VNI为100。local 10.0.0.1指定本机隧道端点IP。dstport 4789是VXLAN标准端口。nolearning关闭自动学习因为我们用静态配置远端端点。如果不加nolearning内核会通过组播或未知单播泛洪来学习远端MAC地址在点对点场景下没必要。然后添加远端端点。主机A需要知道主机B和主机C的隧道端点bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.2 bridge fdb append 00:00:00:00:00:00 dev vxlan100 dst 10.0.0.3这两条命令的意思是对于目标MAC地址未知的帧全零MAC表示泛洪分别复制一份发往10.0.0.2和10.0.0.3。这就是静态点对多点隧道的配置方式。主机B和主机C做类似配置把local改成自己的IPfdb表里添加其他两台主机的IP。配置完成后验证连通性ping -c 3 192.168.100.2 ping -c 3 192.168.100.3如果通说明内核态VXLAN隧道建立成功。3.3 Open vSwitch VXLAN配置步骤OVS的配置稍微复杂一些。先确保OVS已安装并启动systemctl start openvswitch ovs-vsctl show然后创建网桥和VXLAN端口。以主机A为例ovs-vsctl add-br br-vxlan ovs-vsctl add-port br-vxlan vxlan100 \ -- set interface vxlan100 typevxlan \ options:local_ip10.0.0.1 \ options:remote_ip10.0.0.2 \ options:key100 ip addr add 192.168.100.1/24 dev br-vxlan ip link set br-vxlan up注意这里remote_ip指定了单个远端。如果要连接多个远端有两种做法一是创建多个VXLAN端口分别指向不同远端二是把remote_ip留空让OVS通过组播或流表动态决定。生产环境更推荐用流表方式灵活且可控。用流表方式的话配置变成ovs-vsctl add-port br-vxlan vxlan100 \ -- set interface vxlan100 typevxlan \ options:local_ip10.0.0.1 \ options:key100 \ options:remote_ipflow ovs-ofctl add-flow br-vxlan \ table0,priority100,ip,nw_dst192.168.100.2 actionsset_field:10.0.0.2-tun_dst,output:vxlan100 ovs-ofctl add-flow br-vxlan \ table0,priority100,ip,nw_dst192.168.100.3 actionsset_field:10.0.0.3-tun_dst,output:vxlan100remote_ipflow表示远端IP由流表里的tun_dst字段决定。这样一条流表对应一个远端扩展起来很方便。3.4 配置验证与流量测试两边都配好后用ovs-appctl查看流表和隧道状态ovs-appctl ofproto/tunnel/show ovs-ofctl dump-flows br-vxlan内核态VXLAN这边用ip命令查看ip -d link show vxlan100 bridge fdb show dev vxlan100连通性测试用ping和iperf3。先ping验证二层可达再用iperf3打流测吞吐iperf3 -s # 在主机B上启动服务端 iperf3 -c 192.168.100.2 -t 30 -P 4 # 在主机A上打流我实测下来在同样的硬件和网络条件下内核态VXLAN的吞吐量比OVS高出约15%到25%具体取决于包大小和流表命中率。小包场景差距更明显因为OVS的每包处理开销更大。4. 性能差异的根因分析与调优实践4.1 数据包转发路径的微观对比要理解性能差异得看数据包在内核里到底走了哪些函数。内核态VXLAN的发送路径大致是dev_queue_xmit-vxlan_xmit-udp_tunnel_xmit_skb-iptunnel_xmit- 物理网卡驱动。接收路径是物理网卡中断 -ip_rcv-udp_rcv-vxlan_rcv-netif_rx- 上层协议栈。整条路径上的函数调用是编译进内核的没有上下文切换。OVS的路径则多了一层。发送时报文先进入OVS的内核datapath模块做流表匹配。如果命中执行ovs_vport_send直接发出如果未命中通过netlink把报文送到用户态ovs-vswitchd用户态查表后通过netlink下发新流表同时把报文重新注入内核发送。这个upcall和revalidate的过程就是额外开销的来源。接收方向同理OVS的datapath收到包后先查流表未命中则upcall到用户态。所以OVS的性能高度依赖流表命中率。如果流量模式稳定流表很快就能覆盖大部分流量性能接近内核态如果流量模式频繁变化大量报文走慢路径性能就会明显下降。4.2 影响性能的关键参数调优内核态VXLAN调优调整网卡多队列和RSS让VXLAN解封装后的流量分散到多个CPU核心。用ethtool -L eth1 combined 8设置队列数。开启GROGeneric Receive Offload和TSOTCP Segmentation Offload减少CPU处理大包的开销。用ethtool -K eth1 gro on tso on确认开启状态。调整UDP隧道相关的内核参数比如net.core.rmem_max和net.core.wmem_max增大socket缓冲区。OVS调优确保内核datapath模块已加载且版本匹配。用ovs-dpctl show查看datapath状态。调整流表超时时间。默认idle_timeout是60秒对于稳定流量可以适当延长减少流表重新下发的频率。开启多线程upcall。在ovs-vswitchd启动参数里设置--n-handler-threads和--n-revalidator-threads让多个线程并行处理upcall。使用DPDK加速。如果对性能要求极高可以把OVS切换到DPDK模式绕过内核协议栈直接在用户态收发包。但这需要绑定网卡到DPDK驱动配置复杂度高且会占用专用CPU核心。4.3 实测数据与场景建议我在三台物理主机上做了对比测试每台主机8核CPU、16GB内存、万兆网卡直连。测试项目包括TCP吞吐、UDP丢包率、小包转发率。结果如下测试项内核态VXLANOVS VXLAN差异TCP大包吞吐1500B9.2 Gbps7.8 Gbps内核高18%TCP小包吞吐64B1.8 Mpps1.2 Mpps内核高50%UDP丢包率10Gbps打流0.02%0.15%内核更稳首次流建立延迟0.1ms2.3ms内核快20倍流表规模1000条时吞吐9.1 Gbps7.5 Gbps内核高21%从数据看内核态VXLAN在纯转发性能上有明显优势尤其是小包场景。但OVS的优势在于功能你可以用一条流表实现VLAN转换加隧道封装加ACL而内核态VXLAN要做同样的事得组合bridge、iptables、tc等多个工具配置分散且难以统一管理。我的建议是如果只是做简单的跨主机二层互通比如小规模容器集群的flannel vxlan模式内核态VXLAN足够且性能更好。如果是云平台的多租户网络需要安全组、流日志、QoS、负载均衡OVS是更合适的选择性能差距可以通过调优和硬件加速来弥补。5. 常见问题排查与避坑经验5.1 隧道不通的排查思路VXLAN隧道不通是最常见的问题排查要按层次来。先确认物理网络可达ping 10.0.0.2通不通。物理层不通后面都不用看。然后检查VXLAN接口状态ip -d link show vxlan100看UP标志和配置参数是否正确。接着检查fdb表或OVS流表确认远端端点IP有没有配对。最后抓包看tcpdump -i eth1 udp port 4789 -nn看封装报文有没有发出去、有没有收到。我踩过的一个坑是防火墙规则把UDP 4789端口挡了。很多发行版默认防火墙策略比较严格VXLAN流量被DROP了但没有任何日志排查起来很费时间。建议先在测试环境关掉防火墙验证确认通了再逐条加规则。5.2 MTU问题与分片处理VXLAN封装会增加50字节的开销外层IP 20 UDP 8 VXLAN 8 内层以太网头14。如果物理网卡MTU是1500内层虚拟网络的MTU必须设成1450否则大包会被分片或丢弃。很多人配完VXLAN发现ping通但TCP大包传不了就是MTU没调。内核态VXLAN设置MTUip link set vxlan100 mtu 1450OVS设置MTUovs-vsctl set interface vxlan100 mtu_request1450同时虚拟机的网卡MTU也要相应调整。如果虚拟机里跑的是容器docker0网桥的MTU也要改。这个链条上任何一环MTU不对都会导致大包不通。5.3 流表不命中导致的性能抖动OVS环境里如果发现吞吐量时高时低大概率是流表命中率不稳定。用ovs-dpctl dump-flows查看datapath里的流表用ovs-ofctl dump-flows查看用户态流表。如果datapath流表数量远小于用户态流表说明很多流没有下发到快路径。常见原因是流表匹配条件太细比如匹配了TCP端口号导致每个连接都要重新upcall。解决办法是放宽匹配条件或者调整流表优先级让粗粒度流表先命中。另外检查net.core.somaxconn和netlink相关参数确保upcall通道不拥堵。5.4 常见问题速查表现象可能原因排查命令解决方向隧道完全不通物理网络不通/防火墙拦截ping、tcpdump检查路由和防火墙ping通但TCP大包失败MTU配置错误ping -M do -s 1450调整MTU为1450吞吐量低且波动流表命中率低ovs-dpctl dump-flows放宽流表匹配条件部分主机不通fdb表或流表缺失bridge fdb show补充远端端点配置延迟高upcall频繁/CPU瓶颈top、perf增加handler线程/DPDK重启后隧道丢失配置未持久化检查启动脚本写入开机自动配置提示生产环境强烈建议把VXLAN配置写成systemd服务或网络管理工具的配置文件不要手动敲命令。手动配置重启就丢而且容易漏掉某台主机导致部分不通。5.5 个人实操心得说几个文档里不会写的经验。第一OVS的流表下发有延迟如果你在脚本里连续添加多条流表然后立刻打流可能会有一部分流量走慢路径。建议加流表后等一两秒再测试。第二内核态VXLAN的fdb表在主机重启后会清空如果没做持久化重启后隧道就断了但接口状态还是UP的很容易误判。第三用OVS做VXLAN时如果物理网卡也加入了OVS网桥注意不要让物理网卡的IP和网桥IP冲突否则管理流量会断。我一般把管理IP留在物理网卡上OVS网桥只做隧道流量两者用不同的子网。还有一个容易忽略的点VXLAN的VNI是24位的范围从0到16777215但0和16777215通常保留不用。多租户环境里VNI规划要提前做好避免冲突。OVS支持VNI和VLAN的映射转换可以在流表里做set_field实现租户隔离这个在云平台里很实用。6. 选型决策与扩展思路回到最初的问题到底选哪个我的判断逻辑是这样的。先看功能需求如果只需要二层互通没有策略、没有多租户、没有流控选内核态VXLAN性能好、配置简单、运维成本低。如果需要流表、ACL、QoS、镜像、VLAN转换这些选OVS功能全、扩展性强、社区生态好。再看规模小规模静态拓扑用内核态大规模动态拓扑用OVS配合SDN控制器。最后看团队技术栈如果团队熟悉OpenFlow和SDNOVS上手快如果团队偏传统网络运维内核态VXLAN学习曲线更平缓。两者也不是非此即彼。实际生产里常见混合部署核心转发用内核态VXLAN保证性能边缘策略用OVS做流控和安全。或者用OVS做控制面把流表下发到内核datapath做快速转发兼顾功能和性能。后续如果要做更深入的对比可以引入DPDK加速的OVS和内核态VXLAN做对比或者测试不同内核版本下VXLAN的性能变化。另外VXLAN的组播模式和多播模式也值得单独拿出来分析尤其是在没有SDN控制器的环境下组播模式能自动发现远端端点但会带来额外的网络开销。这些方向等我后续搭好环境再逐一验证。
阅读完成 · 觉得有帮助?