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

目录

文章目录

  • 目录
  • 前言
  • HDSLB-DPVS 的基本原理
    • LVS
    • DPDK
    • DPVS
    • HDSLB-DPVS
  • HDSLB 的部署配置
    • 硬件要求
    • 软件要求
    • 编译安装 DPDK
    • 编译安装 HDSLB-DPVS
    • 配置大页内存
    • 配置网卡
    • 配置 HDSLB-DPVS
    • 启动 HDSLB-DPVS
  • 测试 HDSLB-DPVS Two-arm Full-NAT 模式
  • 问题分析
  • 最后

前言

在上一篇《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 架构Intel Xeon CPU 四代支持 AVX512 系列指令集的 Intel CPU 型号,例如:Skylake 等
CPU 资源2NUMA,关闭超线程1NUMA,4C
Memory 资源128G16G
NIC 型号Intel E810 100GVirtI/O 驱动,支持多队列

本文 CPU 信息:

$ lscpu
Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   46 bits physical, 57 bits virtual
CPU(s):                          4
On-line CPU(s) list:             0-3
Thread(s) per core:              2root@l4lb:~# lscpu
Architecture:                    x86_64
CPU op-mode(s):                  32-bit, 64-bit
Byte Order:                      Little Endian
Address sizes:                   46 bits physical, 57 bits virtual
CPU(s):                          4
On-line CPU(s) list:             0-3
Thread(s) per core:              2
Core(s) per socket:              2
Socket(s):                       1
NUMA node(s):                    1
Vendor ID:                       GenuineIntel
CPU family:                      6
Model:                           106
Model name:                      Intel(R) Xeon(R) Platinum 8350C CPU @ 2.60GHz
Stepping:                        6
CPU MHz:                         2599.994
BogoMIPS:                        5199.98
Hypervisor vendor:               KVM
Virtualization type:             full
L1d cache:                       96 KiB
L1i cache:                       64 KiB
L2 cache:                        2.5 MiB
L3 cache:                        48 MiB
NUMA node0 CPU(s):               0-3
Vulnerability Itlb multihit:     Not affected
Vulnerability L1tf:              Not affected
Vulnerability Mds:               Not affected
Vulnerability Meltdown:          Not affected
Vulnerability Mmio stale data:   Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown
Vulnerability Retbleed:          Not affected
Vulnerability Spec store bypass: Vulnerable
Vulnerability Spectre v1:        Mitigation; usercopy/swapgs barriers and __user pointer sanitization
Vulnerability Spectre v2:        Vulnerable, IBPB: disabled, STIBP: disabled, PBRSB-eIBRS: Vulnerable
Vulnerability Srbds:             Not affected
Vulnerability Tsx async abort:   Not affected
Flags:                           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 -r
5.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-generic
lrwxrwxrwx 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 SMP
ii  linux-image-5.4.0-136-generic         5.4.0-136.153                     amd64        Signed kernel image generic
ii  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 SMP
ii  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 --version
gcc (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; 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/fstab
nodev /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/grub
GRUB_CMDLINE_LINUX_DEFAULT="${GRUB_CMDLINE_LINUX_DEFAULT} default_hugepagesz=1G hugepagesz=1G hugepages=15" 

$ sudo update-grub
$ init 6

$ cat /proc/meminfo | grep Huge
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:      13
HugePages_Free:       13
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:    1048576 kB
Hugetlb:        13631488 kB

$ free -h
              total        used        free      shared  buff/cache   available
Mem:           15Gi        13Gi       2.0Gi       2.0Mi       408Mi       2.2Gi
Swap:            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 net
Network 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-pci
0000: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 net
Network 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 config
global_defs {
    log_level   DEBUG # 方便调试
    ! log_file    /var/log/hdslb.log
    ! log_async_mode    on
}

! netif config
netif_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 config
timer_defs {
    # cpu job loops to schedule dpdk timer management
    schedule_interval    500
}

! hdslb neighbor config
neigh_defs {
    <init> unres_queue_length  128
    <init> timeout             60
}

! hdslb ipv4 config
ipv4_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 config
ipv6_defs {
    disable                     off
    forwarding                  off
    route6 {
        <init> method           hlist
        recycle_time            10
    }
}

! control plane config
ctrl_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 config
ipvs_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 config
sa_pool {
    pool_hash_size   16
}

启动 HDSLB-DPVS

$ cd hdslb/
$ ./bin/hdslb
current thread affinity is set to F
EAL: Detected 4 lcore(s)
EAL: Detected 1 NUMA nodes
EAL: Multi-process socket /var/run/dpdk/rte/mp_socket
EAL: Selected IOVA mode 'PA'
EAL: Probing VFIO support...
EAL: VFIO support initialized
EAL:   Invalid NUMA socket, default to 0
EAL: Probe PCI driver: net_virtio (1af4:1000) device: 0000:01:00.0 (socket 0)
EAL:   Invalid NUMA socket, default to 0
EAL: 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 0
EAL: 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 created
DPVS: HDSLB version: , build on 2024.05.24.14:37:02
CFG_FILE: Opening configuration file '/etc/hdslb.conf'.
CFG_FILE: log_level = WARNING
NETIF: dpdk0:rx_queue_number = 3
NETIF: dpdk1:rx_queue_number = 3
NETIF: worker cpu1:dpdk0 rx_queue_id += 0
NETIF: worker cpu1:dpdk0 tx_queue_id += 0
NETIF: worker cpu1:dpdk1 rx_queue_id += 0
NETIF: worker cpu1:dpdk1 tx_queue_id += 0
NETIF: worker cpu2:dpdk0 rx_queue_id += 1
NETIF: worker cpu2:dpdk0 tx_queue_id += 1
NETIF: worker cpu2:dpdk1 rx_queue_id += 1
NETIF: worker cpu2:dpdk1 tx_queue_id += 1
NETIF: worker cpu3:dpdk0 rx_queue_id += 2
NETIF: worker cpu3:dpdk0 tx_queue_id += 2
NETIF: worker cpu3:dpdk1 rx_queue_id += 2
NETIF: worker cpu3:dpdk1 tx_queue_id += 2
Kni: kni_add_dev: fail to set mac FA:27:00:00:0A:02 for dpdk0.kni: Timer expired
Kni: 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 show
1: 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_CSUM
2: 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 a
1: 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 forever
2: 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 forever
71: 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:ff
72: 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 show
inet 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 auto
inet 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 auto
inet 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 -Ln
IP Virtual Server version 0.0.0 (size=0)
Prot LocalAddress:Port Scheduler Flags
  -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
TCP  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 denied
make[1]: *** [Makefile:29: keepalived_conf] Error 126
make[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 expired
Kni: kni_add_dev: fail to set mac FA:27:00:00:00:E1 for dpdk1.kni: Timer expired
IPSET: ipset_init: lcore 3: nothing to do.
IPVS: dp_vs_conn_init: lcore 3: nothing to do.
IPVS: fail to init synproxy: no memory
Segmentation 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 expired
Kni: kni_add_dev: fail to set mac FA:27:00:00:0B:F6 for dpdk1.kni: Timer expired
Ethdev 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 dpdk0
EAL: 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 expired
Kni: kni_add_dev: fail to set mac FA:27:00:00:0B:F6 for dpdk1.kni: Timer expired
Ethdev port_id=0 invalid rss_hf: 0x3afbc, valid value: 0x0
NETIF: netif_port_start: fail to config dpdk0
EAL: 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 expired
Kni: kni_add_dev: fail to set mac FA:27:00:00:0B:F6 for dpdk1.kni: Timer expired
NETIF: multicast address add failed for device dpdk0
EAL: 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 的高级特性、软件架构分析和代码解读。敬请继续期待。:)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/646629.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TCP/IP协议(一)

一.报文和协议 协议有什么作用&#xff1f;协议定义通信实体间所交换报文的格式和次序&#xff0c;以及在报文发送和/或接收或者其他事件方面所采取的行动(响应)。 什么是报文&#xff1f;指在网络中传输的数据单元&#xff0c;网络通讯的基本单位。&#xff08;HTTP报文、TCP报…

【C语言】10.C语言指针(1)

文章目录 1.内存和地址1.1 内存1.2 究竟该如何理解编址 2.指针变量和地址2.1 取地址操作符&#xff08;&&#xff09;2.2 指针变量和解引⽤操作符&#xff08;*&#xff09;2.2.1 指针变量2.2.2 如何拆解指针类型2.2.3 解引⽤操作符 2.3 指针变量的⼤⼩ 3.指针变量类型的意…

中科蓝讯AB32VG1中文寄存器说明GPIO端口操作

1 GPIO管理 1.1 GPIO通用控制寄存器 寄存器 1- 1 GPIOA&#xff1a;端口 A 数据寄存器 位寄存器名模式缺省描述31:8---未使用7:0GPIOA写0x00PAx 数据。当 PAx 用作 GPIO 时有效 0&#xff1a;读取时PAx为输入低电平状态&#xff0c;写入时PAx为输出低电平; 1&#xff1a;PAx…

中间件-------RabbitMQ

同步和异步 异步调用 MQ MQ优势&#xff1a;①服务解耦 ②异步调用 ③流量削峰 结构 消息模型 RabbitMQ入门案例&#xff0c;实现消息发送和消息接收 生产者&#xff1a; public class PublisherTest {Testpublic void testSendMessage() throws IOException, TimeoutExce…

【Text2SQL 论文】SeaD:使用 Schema-aware 去噪训练的 end2end 的 Text2SQL

论文&#xff1a;SeaD: End-to-end Text-to-SQL Generation with Schema-aware Denoising ⭐⭐ NAACL 2022, arXiv:2105.07911 本论文提出 SeaD 模型&#xff0c;使用 schema-aware 的去噪方法来训练一个 end2end、seq2seq 的 Transformer 模型来实现 Text2SQL。 一、论文速读…

[vue error] vue3中使用同名简写报错 ‘v-bind‘ directives require an attribute value

错误详情 错误信息 ‘v-bind’ directives require an attribute value.eslintvue/valid-v-bind 错误原因 默认情况下&#xff0c;ESLint 将同名缩写视为错误。此外&#xff0c;Volar 扩展可能需要更新以支持 Vue 3.4 中的新语法。 解决方案 更新 Volar 扩展 安装或更新 …

Springboot集成GRPC

Springboot集成GRPC 一、springboot版本二、GRPC的pom依赖2.1 服务端2.2 客户端3.构建依赖 三、配置文件服务端客户端 四、 demo4.1 编写proto文件4.2 生成文件4.3 服务端重写方法4.4 客户端调用该方法 五、测试 一、springboot版本 <groupId>org.springframework.boot&l…

YOLOv8_pose预测流程-原理解析[关键点检测理论篇]

YOLOv8_seg的网络结构图在博客YOLOv8网络结构介绍_CSDN博客已经更新了,由网络结构图可以看到相对于目标检测网络,实例分割网络只是在Head层不相同,如下图所示,在每个特征层中增加了KeyPoint分支(浅绿色),通过两个卷积组和一个Conv卷积得到得到通道数为51的特征图,51表示…

自动驾驶技术现状与需求分析

随着科技的不断进步和智能化浪潮的席卷&#xff0c;自动驾驶技术已成为当今交通领域的热点话题。本文旨在深入探讨自动驾驶技术的当前发展状况&#xff0c;并对其未来的市场需求进行细致分析。首先&#xff0c;我们将回顾自动驾驶技术的起源、发展历程以及当前的技术水平&#…

信息学奥赛初赛天天练-12-数论-整除问题

更多资源请关注纽扣编程微信公众号 整除的性质 1 整除性 若 &#x1d44e; 和 &#x1d44f; 都为整数&#xff0c; &#x1d44e; 整除 &#x1d44f; 是指 &#x1d44f; 是 &#x1d44e; 的倍数&#xff0c;&#x1d44e; 是 &#x1d44f; 的约数&#xff08;或者叫 因…

贪心题目总结

1. 最长递增子序列 我们来看一下我们的贪心策略体现在哪里&#xff1f;&#xff1f;&#xff1f; 我们来总结一下&#xff1a; 我们在考虑最长递增子序列的长度的时候&#xff0c;其实并不关心这个序列长什么样子,我们只是关心最后一个元素是谁。这样新来一个元素之后&#xf…

C++编程揭秘:虚表机制与ABI兼容性的实例剖析

前言&#xff1a; 假设你的应用程序引用的一个库某天更新了&#xff0c;虽然 API 和调用方式基本没变&#xff0c;但你需要重新编译你的应用程序才能使用这个库&#xff0c;那么一般说这个库是源码兼容&#xff08;Source compatible&#xff09;&#xff1b;反之&#xff0c;如…

CAN总线简介

1. CAN总线概述 1.1 CAN定义与历史背景 CAN&#xff0c;全称为Controller Area Network&#xff0c;是一种基于消息广播的串行通信协议。它最初由德国Bosch公司在1983年为汽车行业开发&#xff0c;目的是实现汽车内部电子控制单元&#xff08;ECUs&#xff09;之间的可靠通信。…

批量漏洞挖掘思路小结

漏洞挖掘是指对应用程序中未知漏洞的探索&#xff0c;通过综合应用各种技术和工具&#xff0c;尽可能地找出其中的潜在漏洞。一般情况下漏洞挖掘针对单一的应用系统&#xff0c;通过端口扫描、目录扫描、文件扫描等方式对其安全性进行评估&#xff0c;而本文主要针对Nday和1day…

软考结束。有什么要说的

1. 竟然是机试&#xff0c;出乎我意料。是 考试机构觉得笔试成本高了么。这次的考试是机试&#xff0c;相比以往有所不一样。感言是不是以后都会在固定地点考试也说不准。 2. 遇到年轻人。 这次旁边的一个女同学第一次参加&#xff0c;还像我询问了一些关于软考的事。我是有…

【设计模式】JAVA Design Patterns——Command(事务模式)

&#x1f50d;目的 将请求封装为对象&#xff0c;从而使你可以将具有不同请求的客户端参数化&#xff0c;队列或记录请求&#xff0c;并且支持可撤销操作。 &#x1f50d;解释 真实世界例子 有一个巫师在地精上施放咒语。咒语在地精上一一执行。第一个咒语使地精缩小&#xff0…

从零实现Llama3中文版

1.前言 一个月前&#xff0c;Meta 发布了开源大模型 llama3 系列&#xff0c;在多个关键基准测试中优于业界 SOTA 模型&#xff0c;并在代码生成任务上全面领先。 此后&#xff0c;开发者们便开始了本地部署和实现&#xff0c;比如 llama3 的中文实现、llama3 的纯 NumPy 实现…

06中间件RTOS/CP

Autosar CP 操作系统详解-CSDN博客 1. 什么是RTOS &#xff1f; RTOS&#xff0c;英文全称是 Real-time Operation System&#xff0c;中文就是 实时操作系统&#xff0c;又称及时操作系统。 实时操作系统&#xff0c;是指当外界事件或数据产生时&#xff0c;能够接受并以足…

【HMGD】STM32/GD32 CAN通信

各种通信协议速度分析 协议最高速度(btis/s)I2C400KCAN1MCAN-FD5M48510MSPI36M CAN协议图和通信帧 CubeMX CAN配置说明 CAN通信波特率 APB1频率 / 分频系数 /&#xff08;BS1 BS2 同步通信段&#xff09;* 1000 ​ 42 / 1 / (111) * 1000 ​ 14,000 KHz ​ 1400000…

【Java面试】二、Redis篇(中)

文章目录 1、Redis持久化1.1 RDB1.2 AOF1.3 RDB与AOF的对比 2、数据过期策略&#xff08;删除策略&#xff09;2.1 惰性删除2.2 定期删除 3、数据淘汰策略4、主从复制4.1 主从全量同步4.2 增量同步 5、哨兵模式5.1 服务状态监控5.2 哨兵选主规则5.3 哨兵模式下&#xff0c;Redi…