在接触一项新事物时,我习惯从宏观角度去了解。也就是从它的产生背景、基本概念、大致的原理图来了解。如果能找到灵魂paper来读一下是最好。然后就是编译运行,遇到不懂的概念再次反过来理解。然后再抓住一条线,例如四层数据包如何转发来进行代码研读。也就是说先从大图像了解概貌入手,然后运行程序敲几个命令有个感性的认识,然后再沿着一条线去细读反过来再细化最初的大图像。
DPVS是一种基于DPDK的高性能四层负载均衡器。它来源于Linux Virtual Server LVS及其修改后的alibaba/LVS. 那LVS是什么呢?Linux Virtual Server是构建在实服务器集群上的高度可伸缩和高可用的服务器,负载平衡器运行在Linux操作系统上。服务器集群的架构对最终用户是完全透明的,用户之间的交互就好像它是一个高性能的虚拟服务器。因此,DPVS使用了LVS里面的核心概念(这些在http://www.linuxvirtualserver.org/zh/index.html官网有详细说明,这里做个摘要):
- NAT: 通过网络地址转换,调度器重写请求报文的目标地址,根据预设的调度算法,将请求分派给后端的真实服务器;真实服务器的响应报文通过调度器时,报文的源地址被重写,再返回给客户,完成整个负载调度过程。
- TUN: 采用NAT技术时,由于请求和响应报文都必须经过调度器地址重写,当客户请求越来越多时,调度器的处理能力将成为瓶颈。为了解决这个问题,调度器把请求报 文通过IP隧道转发至真实服务器,而真实服务器将响应直接返回给客户,所以调度器只处理请求报文。由于一般网络服务应答比请求报文大许多,采用 VS/TUN技术后,集群系统的最大吞吐量可以提高10倍。
- DR: 通过改写请求报文的MAC地址,将请求发送到真实服务器,而真实服务器将响应直接返回给客户。同VS/TUN技术一样,VS/DR技术可极大地 提高集群系统的伸缩性。这种方法没有IP隧道的开销,对集群中的真实服务器也没有必须支持IP隧道协议的要求,但是要求调度器与真实服务器都有一块网卡连 在同一物理网段上。
- FNAT: IPVS的一种新的报文转发方式,区别于DR/NAT/TUNNEL. 该模式处理原则如下:引入local ip address(即IDC 内部ip地址lip), IPVS转换cip(client ip)--vip to/from lip--rip(remote ip),这里lip和rip都是IDC内部IP地址,因此LVS负载均衡器和真实服务器可以在不同的vlan,真实的服务器只需要能访问到内网即可。
其他概念:
- 单臂(one arm): 指所有的客户端和服务器都在负载均衡器的同一侧,LB通过相同的逻辑网络接口转发流量。
- 双臂(two arms): 客户机位于负载平衡器(LB)的一端,服务器位于负载平衡器(RS)的另一端,然后LB在其两个逻辑网络接口之间转发数据包。例如广域网到局域网的负载均衡.
编译安装
虽然github官方上说明不再支持dpdk-stable-20.11.1之前的版本了,但是目前新分支还出与开发阶段,我没有编译通过。所以我用的版本还是dpdk18.11.2 + dpvs1.8. 首先安装dpvs1.8版本在github上的官方介绍一样下载1.8版本的dpvs源代码。
$ git clone https://github.com/iqiyi/dpvs.git
$ cd dpvs
下不来的话可以直接去码云网站https://gitee.com 下载release包。然后进到dpvs目录,再下载dpdk源码:
$ wget https://fast.dpdk.org/rel/dpdk-20.11.1.tar.xz # download from dpdk.org if link failed.
$ tar xf dpdk-20.11.1.tar.xz
接下来打补丁,在打补丁之前我们先来安装一些工具包防止在后面的编译过程中报错,有的话可以跳过:
yum install python3 (Python 3.5 or later.)
pip3 install meson ninja //Meson (version 0.49.2+) and ninja
pip3 install pyelftools 或者yum install pyelftools
yum install numactl-devel
yum install -y popt-devel
yum install -y automake
yum install -y libnl3 libnl3-devel
yum install -y openssl openssl-devel
yum install -y numactl kernel-devel libpcap-devel
yum install -y unzip patch numactl-devel numactl
另外,注意安装gcc前要安装和内核版本匹配的kernel-devel, 查看 ls /usr/src/kernels/, 并且 ldd --version 查看glibc版本要求 glibc >= 2.7(拜托2.17 大于 2.7)
编译dpdk
在编译dpvs之前要先编译DPDK:
cd dpvs-1.8/
cp patch/dpdk-stable-18.11.2/*.patch dpdk-stable-18.11.2/
cd dpdk-stable-18.11.2/
patch -p1 < 000
...
make config T=x86_64-native-linuxapp-gcc
make
export RTE_SDK=$PWD
export RTE_TARGET=build
echo 8192 > /sys/devices/system/node/node0/hugepages/hugepages-2048kB/nr_hugepages
echo 8192 > /sys/devices/system/node/node1/hugepages/hugepages-2048kB/nr_hugepages
mkdir /mnt/huge
mount -t hugetlbfs nodev /mnt/huge
grep Huge /proc/meminfo
# 需要开机自动挂载的话可以在
$ echo "nodev /mnt/huge hugetlbfs defaults 0 0" >> /etc/fstab
modprobe uio
cd dpdk-stable-18.11.2
insmod build/kmod/igb_uio.ko
insmod build/kmod/rte_kni.ko carrier=on
./usertools/dpdk-devbind.py --status
// 172.18.8.129: eno4 100.200.0.129 30:fd:65:32:e8:c3 0000:1a:00.3
// 172.18.8.129: eno1 30:fd:65:32:e8:c0 0000:1a:00.0
ifconfig eno4 down
./usertools/dpdk-devbind.py -b igb_uio 0000:1a:00.3
./usertools/dpdk-devbind.py --status
./usertools/dpdk-devbind.py -u 0000:1a:00.0
./usertools/dpdk-devbind.py -b i40e 0000:1a:00.0
编译dpvs
编译dpvs比较简单,只需要配置export PKG_CONFIG_PATH=/opt/sj/dpvs-1.8/dpdk-stable-18.11.2/dpdklib/lib64/pkgconfig/libdpdk.pc 然后到dpvs目录下编译即可
cd ..
make // 报 inline 函数未定义的错误,需要在 src/Makefile CFLAGS 参数最后-mcmodel=medium之前加上 -fgnu89-inline
make install
运行DPVS
拷贝./conf/下合适的配置文件到 /etc/dpvs.conf
运行./bin/dpvs 如果报段错误退出则需要调整配置文件中的pktpool_size,我猜测是因为这个值太大了导致内存不足。可以把这个值改小一些,并且屏蔽一些cpu,减少消耗。我这样操作之后能跑起来了。