写点什么

Intel HDSLB 高性能四层负载均衡器 — 基本原理和部署配置

作者:云物互联
  • 2024-05-26
    北京
  • 本文字数:17855 字

    阅读完需:约 59 分钟

前言

在上一篇《Intel HDSLB 高性能四层负载均衡器 — 快速入门和应用场景》中,我们着重介绍了 HDSLB(High Density Scalable Load Balancer,高密度可扩展的负载均衡器)作为新一代高性能四层负载均衡器的需求定位、分析了 HDSLB 在云计算和边缘计算应用场景中的特性优势,以及解读了 HDSLB 的性能测试数据。

再进一步的,在本篇中我们主要关注 HDSLB 的基本运行原理和部署配置方式,更侧重于实际的操作。为了让更广泛的开发者们都能够快捷方便的对 HDSLB 展开研究,所以在本篇中会采用 HDSLB-DPVS 开源版本来进行介绍。

HDSLB-DPVS 的基本原理

顾名思义,HDSLB-DPVS 是基于 DPVS 进行二次开发的项目。而 DPVS,又称为 DPDK-LVS,是一个参考了 LVS 内核态四层负载均衡器设计原理并基于 DPDK 用户态数据面加速框架进行开发的四层负载均衡器。可见,HDSLB-DPVS 的技术堆栈主要由以下 4 个部分组成:

  1. LVS

  2. DPDK

  3. DPVS

  4. HDSLB-DPVS

要清晰的理解 HDSLB-DPVS 的基本实现原理,我们需要从头开始讲起。

LVS

LVS(Linux Virtual Server,Linux 虚拟服务器)是一个诞生于 1998 年的四层负载均衡器开源项目,其目标是使用 Local Balancer 技术和 Server Cluster 技术来实现一个具有良好可伸缩性(Scalability)、可靠性(Reliability)和可管理性(Manageability)的 Virtual Server。

  • LVS:https://github.com/alibaba/LVS

在这里插入图片描述

现在来看,虽然 LVS 基于 Kernel 实现的数据面性能已经不合时宜,但在逻辑架构的设计层面,LVS 的核心术语依旧沿用至今,包括:

  • 「VS(Virtual Server,虚拟服务器)」:VS 是由 DS 和 RS 组合构成的一个逻辑概念,VS 最终通过一个 VIP 对外部 Clients 提供服务。

  • 「DS(Director Server,流量调度服务器)」:是充当 LB 流量入口的服务器,负责负载均衡策略的执行和流量分发。所以也称为 FE(前端服务器)。

  • 「RS(Real Server,真实服务器)」:RS 是真正用于处理请求流量的服务器,也称为 BE(后端服务器)。

  • 「VIP(Virtual IP,虚拟 IP 地址)」:VS 向外部 Client 提供服务的 IP 地址。

  • 「DIP(Director IP,直连 IP 地址)」:Director Server 向内部与 RS 进行通信的 IP 地址。

  • 「RIP(Real IP,真实 IP 地址)」:RS 与 DS 互通的 IP 地址。

  • 「CIP(Client IP,客户端的 IP 地址)」

  • 「NAT 反向代理转发模式」

  • 「IP Tunneling 透明转发模式」

  • 「DR 三角流量转发模式」

  • 等等

在这里插入图片描述

关于 LVS 更详细的内容,推荐阅读:《LVS & Keepalived 实现 L4 高可用负载均衡器

DPDK

随着 2010 年,IEEE 802.3 标准委员会发布了 40GbE 和 100GbE 802.3ba 以太网标准后,数据中心正式进入了 100G 时代。从那时起,Linux 内核协议栈的网络处理性能就一直备受挑战。先看几个数据:

  • CPU 访问 Main Memory 所需要的时长为 65 纳秒。

  • 跨 NUMA node 的 Main Memory 数据 Copy 所需要的时长为 40 纳秒。

  • CPU 处理一次硬件中断所需要的时间为 100 微秒。

但实际上,100G 网卡线速为 2 亿 PPS,即每个包处理的时间不能超过 50 纳秒。

可见,基于 Kernel 的数据面已经走到了拐点,DPDK 为此而生,并通过下列加速技术实现了 100G 线性转发。

  1. 使用用户态协议栈代替内核协议栈:Kernel by-pass (user space implementation).

  2. 使用轮训代替中断:Polling instead of interrupt.

  3. 使用多核编程代替多线程:Share-nothing, per-CPU for key data (lockless).

  4. 跨 CPU 无锁通信:Lockless message for high performance IPC.

  5. RX Steering and CPU affinity (avoid context switch).

  6. Zero Copy (avoid packet copy and syscalls).

  7. Batching TX/RX.

  8. etc...

  • DPDK:https://github.com/DPDK/dpdk

在这里插入图片描述

关于 DPDK 更详细的内容,推荐阅读:《DPDK — 数据加速方案的核心思想

DPVS

综上,由于 LVS 的数据面是一个 Linux Kernel Module(ipvs),其性能无法满足现代化需求,所以国内公司 iqiyi 基于 DPDK 开发了 DPVS。值得一提的是,由于 DPVS 项目由国内公司开源和维护,所以其开源社区对中文开发者也会更加友好。

  • DPVS:https://github.com/iqiyi/dpvs

在这里插入图片描述

除了性能方面的优化之外,在功能层面,DPVS 也提供了更丰富的能力,包括:

  • L4 Load Balancer, including FNAT, DR, Tunnel, DNAT modes, etc.

  • SNAT mode for Internet access from internal network.

  • NAT64 forwarding in FNAT mode for quick IPv6 adaptation without application changes.

  • Different schedule algorithms like RR, WLC, WRR, MH(Maglev Hashing), Conhash(Consistent Hashing) etc.

  • User-space Lite IP stack (IPv4/IPv6, Routing, ARP, Neighbor, ICMP ...).

  • Support KNI, VLAN, Bonding, Tunneling for different IDC environment.

  • Security aspect, support TCP syn-proxy, Conn-Limit, black-list, white-list.

  • QoS: Traffic Control.

在软件架构方面,DPVS 沿用了数据分离架构和基于 Keepalived 的 Master-Backup 高可用架构。

  • ipvsadm:用于 VS、RS 等逻辑资源对象的管理。

  • dpip:用于 IP、Route 等基础网络资源的管理。

  • keepalived:用于提供基于 VRRP 协议的主备高可用。

在这里插入图片描述

HDSLB-DPVS

HDSLB-DPVS 和 DPVS 本身都作为高性能负载均衡器,那么两者的本质区别是什么呢?答案就是更强大的性能!

  • HDSLB-DPVS :https://github.com/intel/high-density-scalable-load-balancer/tree/main

在这里插入图片描述

通常的,我们可以使用 RBP(Ratio of Bandwidth and Performance growth rate,带宽性能增速比)来定义网络带宽的增速比上 CPU 性能的增速,即:RBP=BW GR/Perf. GR。

如下图所示。2010 年前,网络的带宽年化增长大约是 30%,到 2015 年增长到 35%,然后在近年达到 45%。相对应的,CPU 的性能增长从 10 年前的 23%,下降到 12%,并在近年直接降低到 3.5%。在这 3 个时间段内,RBP 指标从 RBP~1 附近(I/O 压力尚未显现出来),上升到 RBP~3,并在近年超过了 RBP~10。

可见,CPU 几乎已经无法直接应对网络带宽的增速。而围绕 CPU 进行纯软件加速的 DPDK 框架正在面临挑战。

在这里插入图片描述

回到 DPVS 和 HDSLB-DPVS 的本质区别这个问题。在理论设计层面,DPVS 的目标是基于 DPDK 框架实现了软件层面的加速,而 HDSLB-DPVS 则更进一步的将这种加速融入到 CPU 和 NIC 互相结合的硬件平台之上,并实现了 “高密度” 和 “可扩展” 这 2 大目标:

  • 「高密度」:指的是单个 HDSLB 节点的 TCP 并发连接数量和吞吐量特别高。

  • 「可拓展」:指的是其性能可以随着 CPU Core 的数量或者资源总量的增加而线性拓展。

实践方面,在最新型的 Intel Xeon CPU(e.g. 3rd & 4th generation)和 E810 100G NIC 硬件平台上,实现了:

  • 「Concurrent Session」: 100M level / Node

  • 「Throughput」: > 8Mpps / Core @FNAT

  • 「TCP Session」 Est. Rate > 800K / Core

  • 「Linear growth」

对此,我们在《Intel HDSLB 高性能四层负载均衡器 — 快速入门和应用场景》文中已经对 HDSLB-DPVS 超越前代的性能数据进行了分析,这里不在赘述。

HDSLB 的部署配置

硬件要求

下面进入到实践环节,主要关注 HDSLB-DPVS 的编译、部署和配置。为了降低开发者门槛,所以本文主要使用了开发机低门槛配置来进行部署和调试。

本文 CPU 信息:

$ lscpuArchitecture:                    x86_64CPU op-mode(s):                  32-bit, 64-bitByte Order:                      Little EndianAddress sizes:                   46 bits physical, 57 bits virtualCPU(s):                          4On-line CPU(s) list:             0-3Thread(s) per core:              2root@l4lb:~# lscpuArchitecture:                    x86_64CPU op-mode(s):                  32-bit, 64-bitByte Order:                      Little EndianAddress sizes:                   46 bits physical, 57 bits virtualCPU(s):                          4On-line CPU(s) list:             0-3Thread(s) per core:              2Core(s) per socket:              2Socket(s):                       1NUMA node(s):                    1Vendor ID:                       GenuineIntelCPU family:                      6Model:                           106Model name:                      Intel(R) Xeon(R) Platinum 8350C CPU @ 2.60GHzStepping:                        6CPU MHz:                         2599.994BogoMIPS:                        5199.98Hypervisor vendor:               KVMVirtualization type:             fullL1d cache:                       96 KiBL1i cache:                       64 KiBL2 cache:                        2.5 MiBL3 cache:                        48 MiBNUMA node0 CPU(s):               0-3Vulnerability Itlb multihit:     Not affectedVulnerability L1tf:              Not affectedVulnerability Mds:               Not affectedVulnerability Meltdown:          Not affectedVulnerability Mmio stale data:   Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknownVulnerability Retbleed:          Not affectedVulnerability Spec store bypass: VulnerableVulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user pointer sanitizationVulnerability Spectre v2:        Vulnerable, IBPB: disabled, STIBP: disabled, PBRSB-eIBRS: VulnerableVulnerability Srbds:             Not affectedVulnerability Tsx async abort:   Not affectedFlags:                           fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss ht syscall nx pdpe1gb rdtscp lm constant_ts                                 c arch_perfmon rep_good nopl xtopology cpuid tsc_known_freq pni pclmulqdq ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_tim                                 er aes xsave avx f16c rdrand hypervisor lahf_lm abm 3dnowprefetch cpuid_fault invpcid_single ssbd ibrs ibpb ibrs_enhanced fsgsbase tsc_adjust bm                                 i1 avx2 smep bmi2 erms invpcid avx512f avx512dq rdseed adx smap avx512ifma clflushopt clwb avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xge                                 tbv1 xsaves arat avx512vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid arch_capabilities
复制代码

软件要求

  • OS:Ubuntu 20.04.3

  • Kernel:5.4.0-110-generic

  • GCC:9.4.0

  • DPDK:20.08

值的注意的是,Ubuntu /boot 分区要大于 2G,避免出现内核升级故障问题。参考引用:https://askubuntu.com/questions/1207958/error-24-write-error-cannot-write-compressed-block

本文 OS 信息:

# 更新系统$ sudo apt-get update -y && sudo apt-get upgrade -y# Dev$ sudo apt-get install git vim wget patch unzip -y# popt$ sudo apt-get install libpopt-dev -y# NUMA$ sudo apt-get install libnuma-dev -y$ sudo apt-get install numactl -y# Pcap$ sudo apt-get install libpcap-dev -y # SSL$ sudo apt-get install libssl-dev -y

# Kernel 5.4.0-136$ uname -r5.4.0-136-generic
$ ll /boot/vmlinuz*lrwxrwxrwx 1 root root       25 Dec 27  2022 /boot/vmlinuz -> vmlinuz-5.4.0-136-generic-rw------- 1 root root 13660416 Aug 10  2022 /boot/vmlinuz-5.4.0-125-generic-rw------- 1 root root 13668608 Nov 24  2022 /boot/vmlinuz-5.4.0-136-generic-rw------- 1 root root 11657976 Apr 21  2020 /boot/vmlinuz-5.4.0-26-genericlrwxrwxrwx 1 root root       25 Dec 27  2022 /boot/vmlinuz.old -> vmlinuz-5.4.0-125-generic
$ dpkg -l | egrep "linux-(signed|modules|image|headers)" | grep $(uname -r)ii  linux-headers-5.4.0-136-generic       5.4.0-136.153                     amd64        Linux kernel headers for version 5.4.0 on 64 bit x86 SMPii  linux-image-5.4.0-136-generic         5.4.0-136.153                     amd64        Signed kernel image genericii  linux-modules-5.4.0-136-generic       5.4.0-136.153                     amd64        Linux kernel extra modules for version 5.4.0 on 64 bit x86 SMPii  linux-modules-extra-5.4.0-136-generic 5.4.0-136.153                     amd64        Linux kernel extra modules for version 5.4.0 on 64 bit x86 SMP
# GCC 9.4.0$ gcc --versiongcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0Copyright (C) 2019 Free Software Foundation, Inc.This is free software; see the source for copying conditions.  There is NOwarranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# 文件描述符$ ulimit -n 655350$ echo "ulimit -n 655350" >> /etc/rc.local$ chmod a+x /etc/rc.local
复制代码

编译安装 DPDK

DPDK 安装部署的详细内容,推荐阅读:《DPDK — 安装部署》。

$ cd /root/$ git clone https://github.com/intel/high-density-scalable-load-balancer hdslb
$ wget http://fast.dpdk.org/rel/dpdk-20.08.tar.xz$ tar vxf dpdk-20.08.tar.xz
# 打补丁$ cp hdslb/patch/dpdk-20.08/*.patch dpdk-20.08/$ cd dpdk-20.08/$ patch -p 1 < 0002-support-large_memory.patch$ patch -p 1 < 0003-net-i40e-ice-support-rx-markid-ofb.patch
# 编译$ make config T=x86_64-native-linuxapp-gcc MAKE_PAUSE=n$ make MAKE_PAUSE=n -j 4
复制代码

编译安装 HDSLB-DPVS

HDSLB-DPVS 的编译安装过程中需要依赖许多 CPU 硬件加速指令,例如:AVX2、AVX512 等等。要编译成功,有 2 方面的要求:

  1. 要求 CPU 硬件支持:推荐使用 Intel Xeon 数据中心系列,例如:Intel Xeon Gold。

  2. 要求 GCC 版本支持:推荐采用版本较高的 GCC,例如本文中的 9.4.0。

$ cd dpdk-20.08/$ export RTE_SDK=$PWD
$ cd hdslb/$ chmod +x tools/keepalived/configure
# 编译安装$ make -j 4$ make install
复制代码

配置大页内存

在物理机测试环境中,大页内存应该尽可能的给,HDSLB 的 LB connect pool 需要分配大量的内存,这与实际的性能规格有直接关系。

$ mkdir /mnt/huge_1GB$ mount -t hugetlbfs nodev /mnt/huge_1GB
$ vim /etc/fstabnodev /mnt/huge_1GB hugetlbfs pagesize=1GB 0 0
$ # for NUMA machine$ echo 15 > /sys/devices/system/node/node0/hugepages/hugepages-1048576kB/nr_hugepages
$ vim /etc/default/grubGRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT} default_hugepagesz=1G hugepagesz=1G hugepages=15" 
$ sudo update-grub$ init 6
$ cat /proc/meminfo | grep HugeAnonHugePages:         0 kBShmemHugePages:        0 kBFileHugePages:         0 kBHugePages_Total:      13HugePages_Free:       13HugePages_Rsvd:        0HugePages_Surp:        0Hugepagesize:    1048576 kBHugetlb:        13631488 kB
$ free -h              total        used        free      shared  buff/cache   availableMem:           15Gi        13Gi       2.0Gi       2.0Mi       408Mi       2.2GiSwap:            0B          0B          0B
复制代码

配置网卡

$ modprobe vfio-pci$ modprobe vfio enable_unsafe_noiommu_mode=1 # https://stackoverflow.com/questions/75840973/dpdk20-11-3-cannot-bind-device-to-vfio-pci$ echo 1 > /sys/module/vfio/parameters/enable_unsafe_noiommu_mode
$ cd dpdk-20.08/$ export RTE_SDK=$PWD$ insmod ${RTE_SDK}/build/kmod/rte_kni.ko
$ ${RTE_SDK}/usertools/dpdk-devbind.py --status-dev netNetwork devices using kernel driver===================================0000:01:00.0 'Virtio network device 1000' if=eth0 drv=virtio-pci unused=vfio-pci *Active*0000:03:00.0 'Virtio network device 1000' if=eth1 drv=virtio-pci unused=vfio-pci0000:04:00.0 'Virtio network device 1000' if=eth2 drv=virtio-pci unused=vfio-pci

$ ifconfig eth1 down # 0000:03:00.0$ ifconfig eth2 down # 0000:04:00.0$ ${RTE_SDK}/usertools/dpdk-devbind.py -b vfio-pci 0000:03:00.0 0000:04:00.0
$ ${RTE_SDK}/usertools/dpdk-devbind.py --status-dev netNetwork devices using DPDK-compatible driver============================================0000:03:00.0 'Virtio network device 1000' drv=vfio-pci unused=0000:04:00.0 'Virtio network device 1000' drv=vfio-pci unused=Network devices using kernel driver===================================0000:01:00.0 'Virtio network device 1000' if=eth0 drv=virtio-pci unused=vfio-pci *Active*
复制代码

配置 HDSLB-DPVS

$ cp conf/hdslb.conf.sample /etc/hdslb.conf
# 配置解析$ cat /etc/hdslb.conf!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! This is hdslb default configuration file.!! The attribute "<init>" denotes the configuration item at initialization stage. Item of! this type is configured oneshoot and not reloadable. If invalid value configured in the! file, hdslb would use its default value.!! Note that hdslb configuration file supports the following comment type:!   * line comment: using '#" or '!'!   * inline range comment: using '<' and '>', put comment in between!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
! global configglobal_defs {    log_level   DEBUG # 方便调试    ! log_file    /var/log/hdslb.log    ! log_async_mode    on}
! netif confignetif_defs {    <init> pktpool_size     1048575    <init> pktpool_cache    256    # LAN Interface 配置    <init> device dpdk0 {        rx {            queue_number        3            descriptor_number   1024            ! rss                 all        }        tx {            queue_number        3            descriptor_number   1024        }        fdir {            mode                perfect            pballoc             64k            status              matched        }        ! promisc_mode        kni_name                dpdk0.kni    }    # WAN Interface 配置    <init> device dpdk1 {        rx {            queue_number        3            descriptor_number   1024            ! rss                 all        }        tx {            queue_number        3            descriptor_number   1024        }        fdir {            mode                perfect            pballoc             64k            status              matched        }        ! promisc_mode        kni_name                dpdk1.kni    }
    ! <init> bonding bond0 {    !    mode        0    !    slave       dpdk0    !    slave       dpdk1    !    primary     dpdk0    !    kni_name    bond0.kni    !}}
! worker config (lcores)worker_defs {    # control plane CPU    <init> worker cpu0 {        type    master        cpu_id  0    }    # data plane CPU    # dpdk0、1 这 2 个 Port 的同一个收发队列共用同一个 CPU    <init> worker cpu1 {        type    slave        cpu_id  1        port    dpdk0 {            rx_queue_ids     0            tx_queue_ids     0            ! isol_rx_cpu_ids  9            ! isol_rxq_ring_sz 1048576        }        port    dpdk1 {            rx_queue_ids     0            tx_queue_ids     0            ! isol_rx_cpu_ids  9            ! isol_rxq_ring_sz 1048576        }    }    <init> worker cpu2 {        type    slave        cpu_id  2        port    dpdk0 {            rx_queue_ids     1            tx_queue_ids     1            ! isol_rx_cpu_ids  10            ! isol_rxq_ring_sz 1048576        }        port    dpdk1 {            rx_queue_ids     1            tx_queue_ids     1            ! isol_rx_cpu_ids  10            ! isol_rxq_ring_sz 1048576        }    }    <init> worker cpu3 {        type    slave        cpu_id  3        port    dpdk0 {            rx_queue_ids     2            tx_queue_ids     2            ! isol_rx_cpu_ids  11            ! isol_rxq_ring_sz 1048576        }        port    dpdk1 {            rx_queue_ids     2            tx_queue_ids     2            ! isol_rx_cpu_ids  11            ! isol_rxq_ring_sz 1048576        }    }
}
! timer configtimer_defs {    # cpu job loops to schedule dpdk timer management    schedule_interval    500}
! hdslb neighbor configneigh_defs {    <init> unres_queue_length  128    <init> timeout             60}
! hdslb ipv4 configipv4_defs {    forwarding                 off    <init> default_ttl         64    fragment {        <init> bucket_number   4096        <init> bucket_entries  16        <init> max_entries     4096        <init> ttl             1    }}
! hdslb ipv6 configipv6_defs {    disable                     off    forwarding                  off    route6 {        <init> method           hlist        recycle_time            10    }}
! control plane configctrl_defs {    lcore_msg {        <init> ring_size                4096        sync_msg_timeout_us             30000000        priority_level                  low    }    ipc_msg {        <init> unix_domain /var/run/hdslb_ctrl    }}
! ipvs configipvs_defs {    conn {        <init> conn_pool_size       2097152        <init> conn_pool_cache      256        conn_init_timeout           30        ! expire_quiescent_template        ! fast_xmit_close        ! <init> redirect           off    }
    udp {        ! defence_udp_drop        uoa_mode        opp        uoa_max_trail   3        timeout {            normal      300            last        3        }    }
    tcp {        ! defence_tcp_drop        timeout {            none        2            established 90            syn_sent    3            syn_recv    30            fin_wait    7            time_wait   7            close       3            close_wait  7            last_ack    7            listen      120            synack      30            last        2        }        synproxy {            synack_options {                mss             1452                ttl             63                sack                ! wscale                ! timestamp            }            ! defer_rs_syn            rs_syn_max_retry    3            ack_storm_thresh    10            max_ack_saved       3            conn_reuse_state {                close                time_wait                ! fin_wait                ! close_wait                ! last_ack           }        }    }}
! sa_pool configsa_pool {    pool_hash_size   16}
复制代码

启动 HDSLB-DPVS

$ cd hdslb/$ ./bin/hdslbcurrent thread affinity is set to FEAL: Detected 4 lcore(s)EAL: Detected 1 NUMA nodesEAL: Multi-process socket /var/run/dpdk/rte/mp_socketEAL: Selected IOVA mode 'PA'EAL: Probing VFIO support...EAL: VFIO support initializedEAL:   Invalid NUMA socket, default to 0EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:01:00.0 (socket 0)EAL:   Invalid NUMA socket, default to 0EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:03:00.0 (socket 0)EAL:   using IOMMU type 8 (No-IOMMU)EAL: Ignore mapping IO port bar(0)EAL:   Invalid NUMA socket, default to 0EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:04:00.0 (socket 0)EAL: Ignore mapping IO port bar(0)EAL: No legacy callbacks, legacy socket not createdDPVS: HDSLB version: , build on 2024.05.24.14:37:02CFG_FILE: Opening configuration file '/etc/hdslb.conf'.CFG_FILE: log_level = WARNINGNETIF: dpdk0:rx_queue_number = 3NETIF: dpdk1:rx_queue_number = 3NETIF: worker cpu1:dpdk0 rx_queue_id += 0NETIF: worker cpu1:dpdk0 tx_queue_id += 0NETIF: worker cpu1:dpdk1 rx_queue_id += 0NETIF: worker cpu1:dpdk1 tx_queue_id += 0NETIF: worker cpu2:dpdk0 rx_queue_id += 1NETIF: worker cpu2:dpdk0 tx_queue_id += 1NETIF: worker cpu2:dpdk1 rx_queue_id += 1NETIF: worker cpu2:dpdk1 tx_queue_id += 1NETIF: worker cpu3:dpdk0 rx_queue_id += 2NETIF: worker cpu3:dpdk0 tx_queue_id += 2NETIF: worker cpu3:dpdk1 rx_queue_id += 2NETIF: worker cpu3:dpdk1 tx_queue_id += 2Kni: kni_add_dev: fail to set mac FA:27:00:00:0A:02 for dpdk0.kni: Timer expiredKni: kni_add_dev: fail to set mac FA:27:00:00:0B:F6 for dpdk1.kni: Timer expired
复制代码

在这里插入图片描述

HDSLB-DPVS 进程起来后,可以看见 2 个 DPDK Port 和对应的 2 个 KNI Interface。其中 DPDK Port 用于 LB 数据面转发,而 KNI 则用于 Keepalived HA 部署模式。

$ cd hdslb/bin/$ ./dpip link show1: dpdk0: socket 0 mtu 1500 rx-queue 3 tx-queue 3    UP 10000 Mbps half-duplex auto-nego    addr FA:27:00:00:0A:02 OF_TX_IP_CSUM2: dpdk1: socket 0 mtu 1500 rx-queue 3 tx-queue 3    UP 10000 Mbps half-duplex auto-nego    addr FA:27:00:00:0B:F6 OF_TX_IP_CSUM

$ ip a1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00    inet 127.0.0.1/8 scope host lo       valid_lft forever preferred_lft forever    inet6 ::1/128 scope host       valid_lft forever preferred_lft forever2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000    link/ether fa:27:00:00:00:c0 brd ff:ff:ff:ff:ff:ff    inet 192.168.0.4/25 brd 192.168.0.127 scope global eth0       valid_lft forever preferred_lft forever    inet6 fe80::f827:ff:fe00:c0/64 scope link       valid_lft forever preferred_lft forever71: dpdk0.kni: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000    link/ether fa:27:00:00:0a:02 brd ff:ff:ff:ff:ff:ff72: dpdk1.kni: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000    link/ether fa:27:00:00:0b:f6 brd ff:ff:ff:ff:ff:ff
复制代码

测试 HDSLB-DPVS Two-arm Full-NAT 模式

请添加图片描述

  • HDSLB-DPVS

$ cd hdslb/bin
# add VIP to WAN interface$ ./dpip addr add 10.0.0.100/32 dev dpdk1
# route for WAN/LAN access$ ./dpip route add 10.0.0.0/16 dev dpdk1$ ./dpip route add 192.168.100.0/24 dev dpdk0
# add routes for other network or default route if needed.$ ./dpip route showinet 10.0.0.100/32 via 0.0.0.0 src 0.0.0.0 dev dpdk1 mtu 1500 tos 0 scope host metric 0 proto autoinet 192.168.100.0/24 via 0.0.0.0 src 0.0.0.0 dev dpdk0 mtu 1500 tos 0 scope link metric 0 proto autoinet 10.0.0.0/16 via 0.0.0.0 src 0.0.0.0 dev dpdk1 mtu 1500 tos 0 scope link metric 0 proto auto
# add service <VIP:vport> to forwarding, scheduling mode is RR.$ ./ipvsadm -A -t 10.0.0.100:80 -s rr
# add two RS for service, forwarding mode is FNAT (-b)$ ./ipvsadm -a -t 10.0.0.100:80 -r 192.168.100.2 -b$ ./ipvsadm -a -t 10.0.0.100:80 -r 192.168.100.3 -b
# add at least one Local-IP (LIP) for FNAT on LAN interface$ ./ipvsadm --add-laddr -z 192.168.100.200 -t 10.0.0.100:80 -F dpdk0
# Check$  ./ipvsadm -LnIP Virtual Server version 0.0.0 (size=0)Prot LocalAddress:Port Scheduler Flags  -> RemoteAddress:Port           Forward Weight ActiveConn InActConnTCP  10.0.0.100:80 rr  -> 192.168.100.2:80             FullNat 1      0          0  -> 192.168.100.3:80             FullNat 1      0          0
复制代码
  • Server

$ python -m SimpleHTTPServer 80
复制代码
  • Client

$ curl 10.0.0.100
复制代码

问题分析

「问题 1」:hdslb/tools/keepalived/configure 没有执行权限。

make[1]: Leaving directory '/root/hdslb/src'make[1]: Entering directory '/root/hdslb/tools'if [ ! -f keepalived/Makefile ]; then \        cd keepalived && \        ./configure && \        cd -; \fi/bin/sh: 3: ./configure: Permission deniedmake[1]: *** [Makefile:29: keepalived_conf] Error 126make[1]: Leaving directory '/root/hdslb/tools'make: *** [Makefile:33: all] Error 1
# 解决$ chmod +x /root/hdslb/tools/keepalived/configure
复制代码

「问题 2」:缺少配置文件

Cause: ports in DPDK RTE (2) != ports in dpvs.conf(0)
# 解决$ cp conf/hdslb.conf.sample /etc/hdslb.conf
复制代码

「问题 3」:开发机 2MB hugepage size 太小

Cause: Cannot init mbuf pool on socket 0
# 解决:把 hugepagesize 配置为 1G# ref:https://stackoverflow.com/questions/51630926/cannot-create-mbuf-pool-with-dpdk
复制代码

「问题 4」:缺少 rte_kni 模块

Cause: add KNI port fail, exiting...
# 解决$ insmod ${RTE_SDK}/build/kmod/rte_kni.ko
复制代码

「问题 5」:开发机大页内存不够

Kni: kni_add_dev: fail to set mac FA:27:00:00:07:AA for dpdk0.kni: Timer expiredKni: kni_add_dev: fail to set mac FA:27:00:00:00:E1 for dpdk1.kni: Timer expiredIPSET: ipset_init: lcore 3: nothing to do.IPVS: dp_vs_conn_init: lcore 3: nothing to do.IPVS: fail to init synproxy: no memorySegmentation fault (core dumped)
# 解决:扩容到 15G。
复制代码

「问题 6」:开发机网卡不支持 HDSLB-DPVS 需要的 hardware offloads 功能。

Kni: kni_add_dev: fail to set mac FA:27:00:00:0A:02 for dpdk0.kni: Timer expiredKni: kni_add_dev: fail to set mac FA:27:00:00:0B:F6 for dpdk1.kni: Timer expiredEthdev port_id=0 requested Rx offloads 0x62f doesn't match Rx offloads capabilities 0xa1d in rte_eth_dev_configure()NETIF: netif_port_start: fail to config dpdk0EAL: Error - exiting with code: 1  Cause: Start dpdk0 failed, skipping ...
# 解决:修改 netif 模块,不启动不支持的 offloads 功能。static struct rte_eth_conf default_port_conf = {    .rxmode = {......        .offloads = 0,        //.offloads = DEV_RX_OFFLOAD_CHECKSUM | DEV_RX_OFFLOAD_VLAN,    },......    .txmode = {......        .offloads = 0,        //.offloads = DEV_TX_OFFLOAD_IPV4_CKSUM | DEV_TX_OFFLOAD_UDP_CKSUM | DEV_TX_OFFLOAD_TCP_CKSUM | DEV_TX_OFFLOAD_MBUF_FAST_FREE,    },
复制代码

NOTE:根据 DPDK 的文档,offloads mask 的每个 bit 都代表了特定的卸载功能。以下 0-15bit 对应的 Features:

  1. DEV_RX_OFFLOAD_VLAN_STRIP

  2. DEV_RX_OFFLOAD_IPV4_CKSUM

  3. DEV_RX_OFFLOAD_UDP_CKSUM

  4. DEV_RX_OFFLOAD_TCP_CKSUM

  5. DEV_RX_OFFLOAD_TCP_LRO

  6. DEV_RX_OFFLOAD_QINQ_STRIP

  7. DEV_RX_OFFLOAD_OUTER_IPV4_CKSUM

  8. DEV_RX_OFFLOAD_MACSEC_STRIP

  9. DEV_RX_OFFLOAD_VLAN_FILTER

  10. DEV_RX_OFFLOAD_VLAN_EXTEND

  11. DEV_RX_OFFLOAD_SCATTER

  12. DEV_RX_OFFLOAD_TIMESTAMP

  13. DEV_RX_OFFLOAD_SECURITY

  14. DEV_RX_OFFLOAD_KEEP_CRC

  15. DEV_RX_OFFLOAD_SCTP_CKSUM

  16. DEV_RX_OFFLOAD_OUTER_UDP_CKSUM

「问题 7」:开发机网络不支持 RSS 多队列。valid value: 0x0 表示当前网卡不支持任何 RSS 哈希函数。


Kni: kni_add_dev: fail to set mac FA:27:00:00:0A:02 for dpdk0.kni: Timer expiredKni: kni_add_dev: fail to set mac FA:27:00:00:0B:F6 for dpdk1.kni: Timer expiredEthdev port_id=0 invalid rss_hf: 0x3afbc, valid value: 0x0NETIF: netif_port_start: fail to config dpdk0EAL: Error - exiting with code: 1  Cause: Start dpdk0 failed, skipping ...
# 解决方式 1:使用支持 multi-queues 和 RSS hash 的网卡。# 解决方式 2:修改 netif 模块,不启动 multi-queues 和 RSS hash 功能。static struct rte_eth_conf default_port_conf = {    .rxmode = {        //.mq_mode        = ETH_MQ_RX_RSS,        .mq_mode        = ETH_MQ_RX_NONE,......    },    .rx_adv_conf = {        .rss_conf = {            .rss_key = NULL,            //.rss_hf  = /*ETH_RSS_IP*/ ETH_RSS_TCP,            .rss_hf  = 0        },    },......port->dev_conf.rx_adv_conf.rss_conf.rss_hf = 0;    
复制代码

「问题 8」:不支持多播地址配置

Kni: kni_add_dev: fail to set mac FA:27:00:00:0A:02 for dpdk0.kni: Timer expiredKni: kni_add_dev: fail to set mac FA:27:00:00:0B:F6 for dpdk1.kni: Timer expiredNETIF: multicast address add failed for device dpdk0EAL: Error - exiting with code: 1  Cause: Start dpdk0 failed, skipping ...
# 解决:关闭多播功能    //ret = idev_add_mcast_init(port);    //if (ret != EDPVS_OK) {    //    RTE_LOG(WARNING, NETIF, "multicast address add failed for device %s\n", port->name);    //    return ret;    //}
复制代码

「问题 9」:LB connect pool 内存太小,程序崩溃退出。

$ ./ipvsadm -A -t 10.0.0.100:80 -s rr[sockopt_msg_recv] socket msg header recv error -- 0/88 recieved  
IPVS: lb_conn_hash_table_init: lcore 0: create conn_hash_tbl failed. Requested size: 1073741824 bytes. LB_CONN_CACHE_LINES_DEF: 1, LB_CONN_TBL_SIZE: 16777216
# 解决方式 1:继续加大页内存到实际需要的大小。# 解决方式 2:# 1):释放一个 lcore 的大页内存# 2):调小 DPVS_CONN_POOL_SIZE_DEF 从 2097152 减少到 1048576//#define DPVS_CONN_POOL_SIZE_DEF     2097152#define DPVS_CONN_POOL_SIZE_DEF     1048576
复制代码

「问题 10」:编译器版本低缺少编译指令。

error: inlining failed in call to always_inline   "'_mm256_cmpeq_epi64_mask':"  : target specific option mismatch
# 解决:# 1)升级 GCC 版本到 9.4.0# 2)确定 CPU 支持指令集。ref:https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#expand=3828,301,2553&text=_mm256_cmpeq_epi64_mask&ig_expand=872
复制代码

在这里插入图片描述

最后

值得注意的是上述问题记录是笔者在低配开发机中调试程序时所遇见的问题,实际上在一个资源充足的物理测试机上通常不会出现由于资源不足导致的大部分问题。

最后,本篇主要介绍了 Intel HDSLB 的基本运行原理和部署配置的方式,希望能够帮助读者们顺利的把 HDSLB-DPVS 项目 “玩” 起来。后面,我们将再次开发机环境的基础之上,通过《Intel HDSLB 高性能四层负载均衡器 — 高级特性和代码剖析》,继续深入挖掘 HDSLB-DPVS 的高级特性、软件架构分析和代码解读。敬请继续期待。:)

用户头像

云物互联

关注

还未添加个人签名 2018-02-26 加入

还未添加个人简介

评论

发布
暂无评论
Intel HDSLB 高性能四层负载均衡器 — 基本原理和部署配置_云物互联_InfoQ写作社区