简介
DPVS 是爱奇艺网络虚拟化团队基于DPDK (Data Plane Development Kit)和 LVS (Linux Virtual Server) 开发的高性能四层网络软件负载均衡器,支持 FullNAT /DR /Tunnel /SNAT /NAT64 /NAT 六种负载均衡转发方式和IPv4 /IPv6 /TCP /UDP /ICMP /ICMPv6 等多种网络协议。
部署环境:
第一套测试硬件为 intel i5-3470 + intel X710网卡
部署系统为 AlmaLinux 8.8
AlmaLinux 9.2 版本编译dpdk会报错 error: implicit declaration of function ‘netif_rx_ni’; did you mean ‘netif_rx’? [-Werror=implicit-function-declaration],内核函数变了,需要改源码才能用,故选择8.8版本。
第二套测试硬件为 海光 C86 7169 + intel 82599ES网卡
部署系统为 Anolis OS 8.8(由8.6 QU1升级而来,使用ANCK-4.19内核)与 openEuler 20.03 LTS SP3
在主板BIOS里关闭了超线程。
RHEL8系列的4.18内核不支持海光处理器,故选用国内适配过的发行版,均为4.19内核。
参考DPVS v1.9.0 发布文档,使用 DPDK-20.11.1 版本部署 DPVS v1.9.4 版本
编译
参考DPDK文档-系统要求准备环境
dnf group install 'Development Tools'
dnf install epel-release
#使用国内源的话按镜像站点要求安装epel
dnf module list | grep -i python
dnf module install python38
alternatives --set python3 /usr/bin/python3.8
#meson等对python版本有要求,安装指定版本并设置为默认值
dnf install python3-pyelftools
dnf install python3-pip
#安装好pip后建议换一下国内的PyPI镜像
pip3 install meson ninja
#注意pip模块与python版本相关,更新python后必须重新安装pip模块
dnf install numactl-devel popt-devel
dnf install libarchive elfutils-libelf
dnf install wget tree screen numactl
- Anolis OS 8.8 操作流程与命令是一样的,仅需要补充安装 openssl-devel 包。(使用了 python3.9 版本,实测无区别)
- openEuler 20.03 LTS SP3 略有差别:
没有EPEL源;预装python3.7版本不需要更新,也就不需要切换版本;同样需要补充安装 openssl-devel 包。
接下来准备编译
首先将下载的DPVS源码包dpvs-1.9.4.tar.gz解压至/opt
然后将解压好的dpvs-1.9.4目录重命名为dpvs-build
进入dpvs-build目录下,创建dpdk目录,将DPDK源码包dpdk-20.11.1.tar.xz移动到里面
之后的命令默认在/opt/dpvs-build下执行
./scripts/dpdk-build.sh -d
export PKG_CONFIG_PATH=/opt/dpvs-build/dpdk/dpdklib/lib64/pkgconfig
#按dpdk-build.sh结束后输出的命令导入PKG_CONFIG_PATH环境变量
make
#可用-j参数进行多线程编译
make install
到这里就编译部署完成了,DPVS安装在 /opt/dpvs-build/bin/ 目录下。
编译过程中警告
*** WARNING - this build will not support IPVS with IPv6. Please install libnl/libnl-3 dev libraries to support IPv6 with IPVS.
,需要补充 libnl3-devel 包以支持IPVS的IPv6
部署
参考DPVS的git页面文档进行操作:
一:配置节点内存巨页
参考DPDK文档-配置内存巨页与内存巨页配置
- INTEL测试机是单CPU配置
echo 4096 > /sys/kernel/mm/hugepages/hugepages-2048kB/nr_hugepages #配置8GB(4096个2MB)的内存巨页 mkdir /mnt/huge mount -t hugetlbfs nodev /mnt/huge
- 海光测试机有多个numa节点,且支持1GB内存巨页,按1GB巨页进行配置
echo 16 > /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages echo 16 > /sys/devices/system/node/node1/hugepages/hugepages-1048576kB/nr_hugepages echo 16 > /sys/devices/system/node/node2/hugepages/hugepages-1048576kB/nr_hugepages echo 16 > /sys/devices/system/node/node3/hugepages/hugepages-1048576kB/nr_hugepages #配置64GB(四个NODE分别配置16个1GB)的内存巨页 umount /dev/hugepages mount -t hugetlbfs -o pagesize=1G hugetlbfs /dev/hugepages #系统默认挂载的2M巨页,需要重新挂载成1G巨页 mkdir /mnt/huge mount -t hugetlbfs nodev /mnt/huge
按单CPU配置的方法做也可以,系统会自动把内存巨页平均分配到每个node上,效果和对每个node操作一样^排障5^。
系统显示处理器上有4个node,但只有两个能配置巨页,这是第一代ZEN架构的结构导致的。需要加内存让每个die都有内存才行^排障6^。
二:换绑驱动模块
为网卡换绑驱动,INTEL测试机无法绑定uio_pci_generic模块,但海光测试机可以。(不确定是网卡还是系统的原因?)
DPVS文档提到可以用igb_uio代替(但这个模块已经不是DPDK推荐使用的了,需要单独编译),而DPDK则推荐用vfio-pci模块(参考三种模块简介)。
使用VFIO模块
使用VFIO模块需要硬件与系统支持,与显卡直通配置一样:
1.在BIOS中启动VT-D
2.配置内核启动项参数启用iommu
配置好后进行网卡驱动绑定操作
modprobe vfio-pci
insmod ./dpdk/dpdklib/rte_kni.ko carrier=on
./dpdk/dpdklib/bin/dpdk-devbind.py --status
#这里输出结果是:
#Network devices using kernel driver
#===================================
#0000:01:00.0 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp1s0f0 drv=i40e unused=vfio-pci
#0000:01:00.1 'Ethernet Controller X710 for 10GbE SFP+ 1572' if=enp1s0f1 drv=i40e unused=vfio-pci
#0000:04:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller 8168' if=enp4s0 drv=r8169 unused=vfio-pci *Active*
#剩下的其它部分都是空
./dpdk/dpdklib/bin/dpdk-devbind.py -b vfio-pci 0000:01:00.0
##./dpdk/dpdklib/bin/dpdk-devbind.py -b vfio-pci 0000:01:00.1
###测试文件是单卡的,这里应该只绑定一个卡,参见排障3
./dpdk/dpdklib/bin/dpdk-devbind.py --status
#绑定成功输出结果是:
#Network devices using DPDK-compatible driver
#============================================
#0000:01:00.0 'Ethernet Controller X710 for 10GbE SFP+ 1572' drv=vfio-pci unused=i40e
#0000:01:00.1 'Ethernet Controller X710 for 10GbE SFP+ 1572' drv=vfio-pci unused=i40e
#
#Network devices using kernel driver
#===================================
#0000:04:00.0 'RTL8111/8168/8411 PCI Express Gigabit Ethernet Controller 8168' if=enp4s0 drv=r8169 unused=vfio-pci *Active*
#剩下的其它部分都是空
使用uio_pci_generic模块
modprobe uio_pci_generic
insmod ./dpdk/dpdklib/rte_kni.ko carrier=on
./dpdk/dpdklib/bin/dpdk-devbind.py --status
./dpdk/dpdklib/bin/dpdk-devbind.py -b uio_pci_generic 0000:41:00.0
./dpdk/dpdklib/bin/dpdk-devbind.py -b uio_pci_generic 0000:41:00.1
#绑定报错无输出就是成功,用status参数查看也正常
三:启动DPVS
cp conf/dpvs.conf.single-nic.sample /etc/dpvs.conf
#根据测试机网卡配置情况选择这个配置文件模板
./bin/dpvs &
#这里首次启动报错了,问题参见后面排障1-3,解决后成功启动
./bin/dpip link show
#查看网口状态
启动成功后可以看到绑定的CPU核心都是满载。遇到的问题见启动排障
业务
推荐参考此系列笔记了解基本原理与架构后再配置
编译完成后生成4个可执行文件:dpip dpvs ipvsadm keepalived
dpvs 是主程序
dpip 是维护工具,命令用法类似ip命令
ipvsadm 是控制LVS模块的管理工具
keepalived 是实现高可用功能的程序
LVS
实现负载均衡
keepalive
实现高可用功能
排障
DPVS启动报错:Cannot init mbuf pool on socket 0
参考此issue,是内存巨页配置量(报错时仅配置了2GB)不足。
改为8GB后不再报此错误。DPVS启动报错:netif_lcore_init: bad lcore configuration (error code: -4), exit ...
对照配置文件与启动输出,是CPU性能不足(报错时启用了两张网卡,日志报绑定8个核,但测试机只有4核)。
更换配置文件使用单卡配置进行测试,不报此错误但报第3个错误,解决第3个错误后依然报这个错。
查看配置文件,发现worker_defs部分配置绑定了8个CPU,测试机核心不足,用!号注释掉3-8的worker后启动成功不再报错。查看CPU占用率发现核心0-2显示满载。DPVS启动报错:ports in DPDK RTE (2) != ports in dpvs.conf(1)
官方文档提到了这个报错,原因是 DPVS 的 NIC 计数与 /etc/dpvs.conf 不匹配。报错时设置了两个网口,但配置文件是单卡的。
执行./dpdk/dpdklib/bin/dpdk-devbind.py -u 0000:01:00.1
解绑一张卡后不再报此错误。DPVS启动报错:DPVS_MAX_SOCKET is smaller than system numa nodes!
编译时DPVS_MAX_SOCKET 默认值是2, 与检测到的机器情况不一样。
出问题的是海光测试机器,用lscpu查看CPU可知有24个核心分成4个node(用numactl --hardware与numastat可查看详情)。参考此博客与此issue修改src/config.mk编译配置参数DPVS_MAX_SOCKET=4
与DPVS_MAX_LCORE=24
,之后重新编译后不再报此错误。DPVS启动报错:EAL: 32 hugepages of size 1073741824 reserved, but no mounted hugetlbfs found for that size
出问题的是海光测试机器,使用1GB内存巨页时出现此问题,1GB内存巨页挂载方式有问题?未解决,先用2M巨页DPVS启动报错:EAL: set_mempolicy failed: Invalid argument
最后面提示:Cause: failed to init tc: no memory出问题的是海光测试机器,情况类似此文,同样是巨页内存分配不均,与CPU结构有关。规格类似的AMD处理器是EPYC 7401,它所属的7001系列基板上有四个die:
当前机器插了两条内存,在系统内用numactl -H
查看,发现后两个node是没有内存的,按主板内存顺序给每个DIE加一条同规格内存后不再报错。主板BIOS里只有内存交叉的配置,没有找到关闭die的配置项。
DPVS提示dpdk网卡启动失败,输出如下:
NETIF: Ethdev port_id=0 invalid rss_hf: 0x3afbc, valid value: 0x38d34 NETIF: Ethdev port_id=0 invalid tx_offload: 0x1000e, valid value: 0x2a03f NETIF: netif_port_start: fail to bring up dpdk0 DPVS: Start dpdk0 failed, skipping ...
出问题的是海光测试机器,不影响DPVS主进程启动。
实际上这是两个警告,参考此issue,前两条 invalid rss_hf/tx_offload 是网卡rss与配置文件不匹配,启动时会按照实际网卡来加载,可以通过调整配置文件尝试修复,也可直接忽略;后两条是因为网卡没插入网线的警告,接好网线就不提示了。