DPVS-FullNAT模式keepalived篇

本文主要介紹基于CentOS7.9系統(tǒng)部署DPVS的FullNAT模式在使用keepalived進(jìn)行主備模式配置高可用集群在線上生產(chǎn)環(huán)境落地實(shí)踐時(shí)遇到的一些問(wèn)題和處理的思路。

文中所有IP地址、主機(jī)名、MAC地址信息均已進(jìn)行脫敏或魔改處理,客戶(hù)端IP使用模擬器生成,但不影響閱讀體驗(yàn)。

1、keepalived架構(gòu)

1.1 單機(jī)架構(gòu)圖

為了方便理解我們可以把上面的架構(gòu)圖分為DPVS網(wǎng)絡(luò)棧、Linux網(wǎng)絡(luò)棧、RS集群和使用者(SA和Users)這四大部分。在Linux網(wǎng)絡(luò)棧中的物理網(wǎng)卡使用eth表示,在DPVS網(wǎng)絡(luò)棧中的物理網(wǎng)卡使用dpdk表示,DPVS網(wǎng)絡(luò)棧中的網(wǎng)卡虛擬到Linux網(wǎng)絡(luò)棧中則使用kni后綴表示,在兩個(gè)網(wǎng)絡(luò)棧中做了bonding的網(wǎng)卡都使用BOND表示。

默認(rèn)情況下,對(duì)于所有的kni網(wǎng)卡來(lái)說(shuō),它們的流量都會(huì)被DPVS程序劫持。

1.2 網(wǎng)卡用途

keepalived雙臂模式架構(gòu)下,每臺(tái)DPVS機(jī)器最少需要三組網(wǎng)卡,bonding可做可不做,不影響該架構(gòu)圖。上圖為做了bonding4的網(wǎng)卡架構(gòu),因此網(wǎng)卡名稱(chēng)使用bond0、1、2來(lái)表示,只要理解清楚每一組網(wǎng)卡的作用,就能很容易理解圖中的架構(gòu)。

  • bond0bond0網(wǎng)卡主要用于運(yùn)維人員管理機(jī)器以及keepalived程序?qū)蠖说腞S節(jié)點(diǎn)進(jìn)行探活

    只存在于Linux網(wǎng)絡(luò)棧中的網(wǎng)卡,因?yàn)镈PVS網(wǎng)絡(luò)棧的網(wǎng)卡(包括其虛擬出的kni網(wǎng)卡)都是隨著DPVS程序的存在而存在的,因此必須有一個(gè)獨(dú)立于DPVS進(jìn)程之外的網(wǎng)卡用于管理機(jī)器(機(jī)器信息監(jiān)控報(bào)警,ssh登錄操作等)。

    keepalived程序?qū)蠖说腞S節(jié)點(diǎn)探活的時(shí)候只能使用Linux網(wǎng)絡(luò)棧,因此在上圖的架構(gòu)中,正好也是使用bond0網(wǎng)卡進(jìn)行探活操作,如果有多個(gè)Linux網(wǎng)絡(luò)棧的內(nèi)網(wǎng)網(wǎng)卡,則根據(jù)Linux系統(tǒng)中的路由來(lái)判斷(單張網(wǎng)卡的時(shí)候也是根據(jù)路由判斷)。

  • bond1.knibond1.kni在上述架構(gòu)正常運(yùn)行的時(shí)候是沒(méi)有任何作用的

    bond1.kni作為DPVS中的bond1網(wǎng)卡在Linux網(wǎng)絡(luò)棧中的虛擬網(wǎng)卡,在定位上和bond0是幾乎完成重合的,因此最好將其關(guān)閉避免對(duì)bond0產(chǎn)生干擾。

    之所以不將其徹底刪除,是因?yàn)楫?dāng)DPVS程序運(yùn)行異?;蛘咝枰獙?duì)bond1抓包的時(shí)候,可以將bond1的流量forward到bond1.kni進(jìn)行操作。

  • bond2.knibond2.kni主要用于刷新VIP的MAC地址

    kni網(wǎng)卡的mac地址和DPVS中的bond網(wǎng)卡的mac地址是一致的,由于我們常用的ping和arping等命令無(wú)法對(duì)DPVS中的網(wǎng)卡操作,因此當(dāng)我們需要發(fā)送garp數(shù)據(jù)包或者是gna數(shù)據(jù)包來(lái)刷新IPv4或者IPv6的VIP地址在交換機(jī)中的MAC地址的時(shí)候,可以通過(guò)DPVS網(wǎng)卡對(duì)應(yīng)的kni網(wǎng)卡來(lái)進(jìn)行操作。

  • bond1:業(yè)務(wù)流量網(wǎng)卡,主要用于加載LIP、與RS建立連接并轉(zhuǎn)發(fā)請(qǐng)求

    local_address_group這個(gè)字段配置的LIP一般就是配置在bond1網(wǎng)卡。

  • bond2:業(yè)務(wù)流量網(wǎng)卡,主要用于加載VIP、與客戶(hù)端建立連接并轉(zhuǎn)發(fā)請(qǐng)求

    dpdk_interface這個(gè)字段就是DPVS定制版的keepalived程序特有的字段,能夠?qū)IP配置到dpvs網(wǎng)卡上。

注意:keepalived主備節(jié)點(diǎn)之間的通信必須使用Linux網(wǎng)絡(luò)棧內(nèi)的網(wǎng)卡,在這個(gè)架構(gòu)中可以是bond0或者是bond2.kni網(wǎng)卡

2、dpdk網(wǎng)卡相關(guān)

2.1 原理分析

DPVS中的網(wǎng)卡命名是按照PCIe編號(hào)的順序來(lái)命名的,使用dpdk-devbind工具我們可以看到網(wǎng)卡對(duì)應(yīng)的PCIe編號(hào)和Linux網(wǎng)絡(luò)棧中的網(wǎng)卡名稱(chēng)。

如果Linux系統(tǒng)的網(wǎng)卡命名是使用eth*的命名方式并且在/etc/udev/rules.d/70-persistent-net.rules文件中固化了MAC地址和網(wǎng)卡名稱(chēng)的對(duì)應(yīng)關(guān)系,那么就需要特別注意PCIe編號(hào)、DPVS網(wǎng)卡名、MAC地址Linux網(wǎng)卡名四者之間的對(duì)應(yīng)關(guān)系。

尤其是當(dāng)機(jī)器存在多個(gè)網(wǎng)段的網(wǎng)卡且做了bonding的時(shí)候,Linux網(wǎng)卡中的eth*和DPVS網(wǎng)卡中的dpdk*并不一定能一一對(duì)應(yīng),此時(shí)最好能修改相關(guān)配置并且讓機(jī)房的同學(xué)調(diào)整網(wǎng)卡接線(當(dāng)然直接在dpvs的配置文件中修改對(duì)應(yīng)的網(wǎng)卡順序也可以)。

2.2 解決方案

下面的案例是一個(gè)僅供參考的比較不容易出問(wèn)題的組合,eth網(wǎng)卡根據(jù)對(duì)應(yīng)的PCIe編號(hào)升序進(jìn)行命名,和dpdk網(wǎng)卡的命名規(guī)則一致,同時(shí)eth[0-3]為內(nèi)網(wǎng)網(wǎng)卡,eth[4-5]為外網(wǎng)網(wǎng)卡,與本文的架構(gòu)圖對(duì)應(yīng),不容易出錯(cuò)。

[root@dpvs dpvs]# dpdk-devbind --status-dev net

Network devices using DPDK-compatible driver
============================================
0000:04:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection 10fb' drv=igb_uio unused=ixgbe
0000:04:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection 10fb' drv=igb_uio unused=ixgbe
0000:82:00.0 'Ethernet 10G 2P X520 Adapter 154d' drv=igb_uio unused=ixgbe
0000:82:00.1 'Ethernet 10G 2P X520 Adapter 154d' drv=igb_uio unused=ixgbe

Network devices using kernel driver
===================================
0000:01:00.0 '82599ES 10-Gigabit SFI/SFP+ Network Connection 10fb' if=eth0 drv=ixgbe unused=igb_uio
0000:01:00.1 '82599ES 10-Gigabit SFI/SFP+ Network Connection 10fb' if=eth1 drv=ixgbe unused=igb_uio


[root@dpvs dpvs]# cat /etc/udev/rules.d/70-persistent-net.rules
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="28:6e:45:c4:0e:48", NAME="eth0"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="28:6e:45:c4:0e:4a", NAME="eth1"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="38:e2:ba:1c:dd:74", NAME="eth2"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="38:e2:ba:1c:dd:76", NAME="eth3"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="b4:45:99:18:6c:5c", NAME="eth4"
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{address}=="b4:45:99:18:6c:5e", NAME="eth5"

[root@dpvs dpvs]# dpip link -v show | grep -A4 dpdk
1: dpdk0: socket 0 mtu 1500 rx-queue 16 tx-queue 16
    UP 10000 Mbps full-duplex auto-nego promisc
    addr 38:E2:BA:1C:DD:74 OF_RX_IP_CSUM OF_TX_IP_CSUM OF_TX_TCP_CSUM OF_TX_UDP_CSUM
    pci_addr                        driver_name
    0000:04:00:0                    net_ixgbe
--
2: dpdk1: socket 0 mtu 1500 rx-queue 16 tx-queue 16
    UP 10000 Mbps full-duplex auto-nego promisc
    addr 38:E2:BA:1C:DD:76 OF_RX_IP_CSUM OF_TX_IP_CSUM OF_TX_TCP_CSUM OF_TX_UDP_CSUM
    pci_addr                        driver_name
    0000:04:00:1                    net_ixgbe
--
3: dpdk2: socket 0 mtu 1500 rx-queue 16 tx-queue 16
    UP 10000 Mbps full-duplex auto-nego promisc
    addr B4:45:99:18:6C:5C OF_RX_IP_CSUM OF_TX_IP_CSUM OF_TX_TCP_CSUM OF_TX_UDP_CSUM
    pci_addr                        driver_name
    0000:82:00:0                    net_ixgbe
--
4: dpdk3: socket 0 mtu 1500 rx-queue 16 tx-queue 16
    UP 10000 Mbps full-duplex auto-nego promisc
    addr B4:45:99:18:6C:5E OF_RX_IP_CSUM OF_TX_IP_CSUM OF_TX_TCP_CSUM OF_TX_UDP_CSUM
    pci_addr                        driver_name
    0000:82:00:1                    net_ixgbe

2.3 抓包排障

正常情況下,DPVS網(wǎng)絡(luò)棧會(huì)劫持對(duì)應(yīng)DPVS網(wǎng)卡的全部流量到DPVS網(wǎng)絡(luò)棧中,因此我們使用tcpdump工具對(duì)相應(yīng)的kni網(wǎng)卡進(jìn)行抓包是沒(méi)辦法抓到相關(guān)的數(shù)據(jù)包的,比較方便的解決方案是使用dpip相關(guān)命令把dpvs網(wǎng)卡的流量forward到對(duì)應(yīng)的kni網(wǎng)卡上,再對(duì)kni網(wǎng)卡進(jìn)行抓包。

dpip link set <port> forward2kni on      # enable forward2kni on <port>
dpip link set <port> forward2kni off     # disable forward2kni on <port>

對(duì)于本文架構(gòu)圖中的dpvs節(jié)點(diǎn),命令中的<port>一般為使用dpip命令查看到的bond1網(wǎng)卡bond2網(wǎng)卡。

也可以查看下面這個(gè)官方的參考鏈接:

https://github.com/iqiyi/dpvs/blob/master/doc/tutorial.md#packet-capture-and-tcpdump

注意:forward2kni操作非常影響性能,請(qǐng)不要在線上服務(wù)節(jié)點(diǎn)進(jìn)行此操作!

3、kni網(wǎng)卡相關(guān)

這里主要承接上面介紹kni網(wǎng)卡的作用以及相關(guān)的一些問(wèn)題和解決思路

3.1 kni網(wǎng)卡的作用

一般來(lái)說(shuō)DPVS的網(wǎng)卡都會(huì)在Linux網(wǎng)絡(luò)棧中虛擬一個(gè)對(duì)應(yīng)的kni網(wǎng)卡,考慮到默認(rèn)情況下,對(duì)于所有的kni網(wǎng)卡來(lái)說(shuō),它們的流量都會(huì)被DPVS程序劫持。在本文的架構(gòu)中,kni網(wǎng)卡的主要作用還是輔助定位故障以及做少量補(bǔ)充工作。

  • 當(dāng)dpvs網(wǎng)卡出現(xiàn)問(wèn)題時(shí),可以把流量forward到kni網(wǎng)卡進(jìn)行DEBUG,當(dāng)VIP出現(xiàn)問(wèn)題的時(shí)候,可以用于刷新VIP的MAC地址
  • kni網(wǎng)卡本身也是一個(gè)虛擬網(wǎng)卡,只是所有流量都被DPVS劫持,可以在DPVS中配置路由放行特定的流量到kni網(wǎng)卡實(shí)現(xiàn)補(bǔ)充工作,如DPVS節(jié)點(diǎn)偶爾需要連接外網(wǎng)的時(shí)候可以通過(guò)bond2.kni放行該外網(wǎng)IP然后訪問(wèn)外網(wǎng)

3.2 kni網(wǎng)卡路由干擾

3.2.1 案例復(fù)現(xiàn)

在本圖的架構(gòu)中,bond1.knibond0網(wǎng)卡在定位上都是屬于內(nèi)網(wǎng)網(wǎng)卡,如果兩個(gè)網(wǎng)卡都是同一個(gè)網(wǎng)段的話,就需要尤其注意內(nèi)網(wǎng)流量進(jìn)出網(wǎng)卡的情況。這里我們使用一臺(tái)虛擬機(jī)進(jìn)行示例:

[root@tiny-centos7 ~]# ip a
...
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:66:3b:08 brd ff:ff:ff:ff:ff:ff
    inet 10.31.100.2/16 brd 10.31.255.255 scope global noprefixroute eth0
       valid_lft forever preferred_lft forever
3: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 52:54:00:47:37:3e brd ff:ff:ff:ff:ff:ff
    inet 10.31.100.22/16 brd 10.31.255.255 scope global noprefixroute eth1
       valid_lft forever preferred_lft forever
...
[root@tiny-centos7 ~]# ip r
...
10.31.0.0/16 dev eth0 proto kernel scope link src 10.31.100.2 metric 100
10.31.0.0/16 dev eth1 proto kernel scope link src 10.31.100.22 metric 101
...

上面的這臺(tái)虛擬機(jī)有兩個(gè)處于10.31.0.0/16網(wǎng)段的網(wǎng)卡,分別是eth0(10.31.100.2)eth1(10.31.100.22),查看路由表的時(shí)候可以看到對(duì)10.31.0.0/16這個(gè)網(wǎng)段有兩條路由分別指向eth0eth1的IP,不同的是兩者的metric。接下來(lái)我們做個(gè)測(cè)試:

首先我們?cè)?code>10.31.100.1這臺(tái)機(jī)器上面ping這臺(tái)虛擬機(jī)的eth1(10.31.100.22),然后直接使用tcpdump進(jìn)行抓包

# 對(duì)eth1(10.31.100.22)網(wǎng)卡進(jìn)行抓包的時(shí)候抓不到對(duì)應(yīng)的icmp包
[root@tiny-centos7 ~]# tcpdump -A -n -vv -i eth1 icmp
tcpdump: listening on eth1, link-type EN10MB (Ethernet), capture size 262144 bytes
^C
0 packets captured
0 packets received by filter
0 packets dropped by kernel

# 接著我們對(duì)eth0(10.31.100.2)網(wǎng)卡進(jìn)行抓包的時(shí)候發(fā)現(xiàn)能夠抓到外部機(jī)器(10.31.100.1)對(duì)eth1(10.31.100.22)網(wǎng)卡的icmp數(shù)據(jù)包
[root@tiny-centos7 ~]# tcpdump -A -n -vv -i eth0 icmp
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 262144 bytes
16:29:44.789831 IP (tos 0x0, ttl 64, id 1197, offset 0, flags [DF], proto ICMP (1), length 84)
    10.31.100.1 > 10.31.100.22: ICMP echo request, id 16846, seq 54, length 64
E..T..@.@.Y.
.d.
.d...VSA..6y2.a....yA...................... !"#$%&'()*+,-./01234567
16:29:44.789898 IP (tos 0x0, ttl 64, id 16187, offset 0, flags [none], proto ICMP (1), length 84)
    10.31.100.22 > 10.31.100.1: ICMP echo reply, id 16846, seq 54, length 64
E..T?;..@._.
.d.
.d...^SA..6y2.a....yA...................... !"#$%&'()*+,-./01234567
16:29:45.813740 IP (tos 0x0, ttl 64, id 1891, offset 0, flags [DF], proto ICMP (1), length 84)
    10.31.100.1 > 10.31.100.22: ICMP echo request, id 16846, seq 55, length 64
E..T.c@.@.V.
.d.

3.2.2 原理分析

到這里我們就可以發(fā)現(xiàn):盡管10.31.100.22是在eth1上面,但是實(shí)際上流量是經(jīng)過(guò)eth0,也就是說(shuō)eth1上面實(shí)際并沒(méi)有流量。這也就很好地對(duì)應(yīng)了路由表中10.31.100.2 metric 100要小于10.31.100.22 metric 101符合metric越小優(yōu)先級(jí)越高的原則。

將上面的情況套用到bond0bond1.kni網(wǎng)卡上,也會(huì)存在相似的問(wèn)題,如果開(kāi)啟了IPv6網(wǎng)絡(luò),還需要考慮是否會(huì)有bond1.kni網(wǎng)卡在IPv6網(wǎng)絡(luò)路由通告下發(fā)默認(rèn)網(wǎng)關(guān)路由。這樣一來(lái)就容易存在路由流量可能走bond0也可能走bond1.kni的問(wèn)題,拋開(kāi)兩者物理網(wǎng)卡和虛擬網(wǎng)卡的性能差距先不談,更重要的是:

  • 默認(rèn)情況下bond1.kni網(wǎng)卡的流量都會(huì)被DPVS程序劫持,所以走bond1.kni網(wǎng)卡的請(qǐng)求都會(huì)不正常;
  • 而恰好RS節(jié)點(diǎn)的探活是通過(guò)Linux網(wǎng)絡(luò)棧實(shí)現(xiàn)的,如果這時(shí)候到RS節(jié)點(diǎn)的路由是走bond1.kni網(wǎng)卡,就會(huì)讓keepalived誤認(rèn)為該后端RS節(jié)點(diǎn)處于不可用狀態(tài),從而將其weight降為0;
  • 如果整個(gè)集群的RS都是如此,就會(huì)導(dǎo)致這個(gè)集群的VIP后無(wú)可用RS(weight均為0),最終的結(jié)果就是請(qǐng)求無(wú)法正常轉(zhuǎn)發(fā)到RS導(dǎo)致服務(wù)徹底不可用。

3.2.3 解決思路

因此在這里最方便的一種解決方案就是直接關(guān)閉bond1.kni,直接禁用,僅當(dāng)需要DEBUG的時(shí)候再啟用,就可以有效地避免這類(lèi)問(wèn)題。

3.3 kni網(wǎng)卡IP不通

3.3.1 原理分析

因?yàn)長(zhǎng)inux網(wǎng)絡(luò)棧中的kni網(wǎng)卡和DPVS網(wǎng)絡(luò)棧中的網(wǎng)卡實(shí)際上對(duì)應(yīng)的是一個(gè)物理網(wǎng)卡(或一組物理網(wǎng)卡),流經(jīng)這個(gè)網(wǎng)卡的網(wǎng)絡(luò)流量只能由一個(gè)網(wǎng)絡(luò)棧處理。默認(rèn)情況下,對(duì)于所有的kni網(wǎng)卡來(lái)說(shuō),它們的流量都會(huì)被DPVS程序劫持。這也就意味著bond2.kni網(wǎng)卡上的IP不僅是無(wú)法ping通,也無(wú)法進(jìn)行其他的正常訪問(wèn)操作。但是DPVS程序支持針對(duì)特定的IP放行相關(guān)的流量到Linux網(wǎng)絡(luò)棧中(通過(guò)kni_host路由實(shí)現(xiàn)),就可以實(shí)現(xiàn)該IP的正常訪問(wèn)。

舉個(gè)例子:一組x520網(wǎng)卡組bonding,在Linux網(wǎng)絡(luò)棧中顯示為bond2.kni,在DPVS網(wǎng)絡(luò)中顯示為bond2,而另外的bond0網(wǎng)卡則只是一個(gè)在linux網(wǎng)絡(luò)棧中的bonding網(wǎng)卡,與DPVS無(wú)關(guān)。我們使用一些簡(jiǎn)單的命令來(lái)進(jìn)行對(duì)比:

使用ethtool工具查看,bond0網(wǎng)卡能正常獲取網(wǎng)卡速率等信息,而kni網(wǎng)卡則完全無(wú)法獲取任何有效信息,同時(shí)在DPVS網(wǎng)絡(luò)棧中使用dpip命令則能夠看到該bond2網(wǎng)卡非常詳細(xì)的物理硬件信息。

使用lspci -nnv命令查看兩組網(wǎng)卡的詳細(xì)信息,我們還可以看到bond0網(wǎng)卡使用的是Linux的網(wǎng)卡驅(qū)動(dòng)ixgbe,而bond2網(wǎng)卡使用的是DPVS的PMDigb_uio。

[root@dpvs dpvs]# ethtool bond0
Settings for bond0:
        Supported ports: [ ]
        Supported link modes:   Not reported
        Supported pause frame use: No
        Supports auto-negotiation: No
        Supported FEC modes: Not reported
        Advertised link modes:  Not reported
        Advertised pause frame use: No
        Advertised auto-negotiation: No
        Advertised FEC modes: Not reported
        Speed: 20000Mb/s
        Duplex: Full
        Port: Other
        PHYAD: 0
        Transceiver: internal
        Auto-negotiation: off
        Link detected: yes
[root@dpvs dpvs]# ethtool bond2.kni
Settings for bond2.kni:
No data available

[root@dpvs dpvs]# dpip -s -v link show bond2
3: bond2: socket 0 mtu 1500 rx-queue 16 tx-queue 16
    UP 20000 Mbps full-duplex auto-nego
    addr 00:1C:34:EE:46:E4
    ipackets            opackets            ibytes              obytes
    15451492            31306               6110603685          4922260
    ierrors             oerrors             imissed             rx_nombuf
    0                   0                   0                   0
    mbuf-avail          mbuf-inuse
    1012315             36260
    pci_addr                        driver_name
                                    net_bonding
    if_index        min_rx_bufsize  max_rx_pktlen   max_mac_addrs
    0               0               15872           16
    max_rx_queues   max_tx_queues   max_hash_addrs  max_vfs
    127             63              0               0
    max_vmdq_pools  rx_ol_capa      tx_ol_capa      reta_size
    0               0x1AE9F         0x2A03F         128
    hash_key_size   flowtype_rss_ol vmdq_que_base   vmdq_que_num
    0               0x38D34         0               0
    rx_desc_max     rx_desc_min     rx_desc_align   vmdq_pool_base
    4096            0               1               0
    tx_desc_max     tx_desc_min     tx_desc_align   speed_capa
    4096            0               1               0
    Queue Configuration:
    rx0-tx0     cpu1-cpu1
    rx1-tx1     cpu2-cpu2
    rx2-tx2     cpu3-cpu3
    rx3-tx3     cpu4-cpu4
    rx4-tx4     cpu5-cpu5
    rx5-tx5     cpu6-cpu6
    rx6-tx6     cpu7-cpu7
    rx7-tx7     cpu8-cpu8
    rx8-tx8     cpu9-cpu9
    rx9-tx9     cpu10-cpu10
    rx10-tx10   cpu11-cpu11
    rx11-tx11   cpu12-cpu12
    rx12-tx12   cpu13-cpu13
    rx13-tx13   cpu14-cpu14
    rx14-tx14   cpu15-cpu15
    rx15-tx15   cpu16-cpu16
    HW mcast list:
        link 33:33:00:00:00:01
        link 33:33:00:00:00:02
        link 01:80:c2:00:00:0e
        link 01:80:c2:00:00:03
        link 01:80:c2:00:00:00
        link 01:00:5e:00:00:01
        link 33:33:ff:bf:43:e4
        
        
        
[root@dpvs dpvs]# lspci -nnv
...

01:00.0 Ethernet controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection [8086:10fb] (rev 01)
...
        Kernel driver in use: ixgbe
        Kernel modules: ixgbe

...

81:00.0 Ethernet controller [0200]: Intel Corporation 82599ES 10-Gigabit SFI/SFP+ Network Connection [8086:10fb] (rev 01)
...
        Kernel driver in use: igb_uio
        Kernel modules: ixgbe

3.3.2 解決思路

如果想要bond2.kni的網(wǎng)卡上面的IP相關(guān)操作正常,可以針對(duì)該IP添加kni_host路由,具體操作如下:

# bond2.kni_ip可以替換為任意的一個(gè)IP
dpip route add <bond2.kni_ip>/32 scope kni_host dev bond2
dpip route del <bond2.kni_ip>/32 scope kni_host dev bond2
# ipv6網(wǎng)絡(luò)操作也是一樣
dpip route -6 add <bond2.kni_ip>/128 scope kni_host dev bond2
dpip route -6 del <bond2.kni_ip>/128 scope kni_host dev bond2

注意:放行的時(shí)候一定要一個(gè)IP一個(gè)IP放行,掩碼一定要是32或者是128,一次批量放行多個(gè)IP會(huì)非常影響性能!

3.4 VIP能ping通但http請(qǐng)求異常

對(duì)于DPVS來(lái)說(shuō),ping請(qǐng)求和http請(qǐng)求的處理邏輯是完全不一樣的。對(duì)于ping請(qǐng)求的icmp和icmpv6數(shù)據(jù)包,都是由DPVS網(wǎng)絡(luò)棧本身來(lái)進(jìn)行處理,并不會(huì)涉及到后面的RS節(jié)點(diǎn)。

能ping通則說(shuō)明DPVS程序工作正常,http請(qǐng)求異常則說(shuō)明后端的RS節(jié)點(diǎn)狀態(tài)異常,也有可能是LIP和RS之間的通信出現(xiàn)了問(wèn)題導(dǎo)致數(shù)據(jù)包無(wú)法順利到達(dá)。

當(dāng)然還有一種可能就是:LIP和RS之間的通信正常,但是用來(lái)RS探活的網(wǎng)卡和RS之間的通信異常導(dǎo)致keepalived進(jìn)程誤認(rèn)為RS節(jié)點(diǎn)出現(xiàn)了問(wèn)題從而將weight降為0。

這種情況的一個(gè)常見(jiàn)案例就是IPv6網(wǎng)絡(luò)下的DPVS節(jié)點(diǎn)和RS節(jié)點(diǎn)跨網(wǎng)段通信,而DPVS節(jié)點(diǎn)上面沒(méi)有添加ipv6的跨網(wǎng)段路由。

4、keepalived相關(guān)

keepalived出現(xiàn)的問(wèn)題主要可以分為兩個(gè)方面:腦裂和主備切換。

4.1 腦裂

一般來(lái)說(shuō),keepalived腦裂的最根本原因就是兩臺(tái)機(jī)器都以為自己是老大(master),造成這種情況的原因主要有兩個(gè):網(wǎng)絡(luò)不通或者配置文件錯(cuò)誤。這兩種故障原因和排查思路在網(wǎng)上很多帖子都十分常見(jiàn),此處不做贅述。比較少見(jiàn)的是一種由于交換機(jī)存在BUG,使得同一個(gè)vlan內(nèi)出現(xiàn)兩組不同的vrrp_instance使用相同的virtual_router_id引發(fā)的腦裂。

4.1.1 交換機(jī)BUG導(dǎo)致腦裂

當(dāng)使用組播通信的時(shí)候,對(duì)于部分有BUG的交換機(jī),不同的vrrp_instance之間如果virtual_router_id一致也有可能會(huì)出現(xiàn)腦裂。注意這里說(shuō)的virtual_router_id一致指的是僅僅virtual_router_id這一個(gè)參數(shù)一樣,就算authentication配置不同的密碼,也是會(huì)收到對(duì)方的組播包,但是只是會(huì)報(bào)錯(cuò)提示received an invalid passwd,并不會(huì)出現(xiàn)腦裂(因?yàn)檫@里是不同的vrrp_instance而不是同一個(gè)vrrp_instance內(nèi)的不同節(jié)點(diǎn))。

一般來(lái)說(shuō)virtual_router_id的范圍是1-255,很明顯這個(gè)變量設(shè)計(jì)之初就是假定一個(gè)vlan內(nèi)的IP數(shù)量不要超過(guò)一個(gè)C,這樣virtual_router_id就可以直接使用IP的最后一截。實(shí)際上如果vlan劃分合理或者規(guī)劃得當(dāng)?shù)脑挷惶菀子龅竭@種問(wèn)題,但是如果機(jī)房網(wǎng)絡(luò)的vlan劃分過(guò)大,又或者是機(jī)房網(wǎng)絡(luò)質(zhì)量差、交換機(jī)老舊的時(shí)候,就需要額外注意virtual_router_id沖突的問(wèn)題。

下面摘錄一段keepalived官網(wǎng)的相關(guān)描述:

arbitrary unique number from 1 to 255 used to differentiate multiple instances of vrrpd running on the same network interface and address family (and hence same socket).

Note: using the same virtual_router_id with the same address family on different interfaces has been known to cause problems with some network switches; if you are experiencing problems with using the same virtual_router_id on different interfaces, but the problems are resolved by not duplicating virtual_router_ids, the your network switches are probably not functioning correctly.

4.1.2 解決思路

組播

keepalived主備節(jié)點(diǎn)之間的通信默認(rèn)情況下是通過(guò)組播來(lái)進(jìn)行的,組播的原理這里不贅述,默認(rèn)情況下不論是IPv4還是IPv6都會(huì)使用一個(gè)組播地址,對(duì)于一些常見(jiàn)的如BGP、VRRP協(xié)議的數(shù)據(jù)包,RFC是有提前定義劃分好相對(duì)應(yīng)的組播地址供其使用,keepalived官方使用的組播地址遵循定義規(guī)范,具體如下:

Multicast Group to use for IPv4 VRRP adverts Defaults to the RFC5798 IANA assigned VRRP multicast address 224.0.0.18 which You typically do not want to change.
vrrp_mcast_group4 224.0.0.18

Multicast Group to use for IPv6 VRRP adverts (default: ff02::12)
vrrp_mcast_group6 ff02::12

如果我們沒(méi)辦法確認(rèn)節(jié)點(diǎn)所處網(wǎng)絡(luò)中是否有使用了該virtual_router_idvrrp_instance,可以嘗試修改組播地址來(lái)避免沖突。

單播

還有一種解決方案就是不使用組播,改為使用單播。單播不僅在網(wǎng)絡(luò)通信質(zhì)量上往往比組播更好,而且也很難出現(xiàn)virtual_router_id沖突的問(wèn)題。同樣的,如果keepalived集群之間出現(xiàn)因?yàn)橹鱾涔?jié)點(diǎn)之間組播通信質(zhì)量差導(dǎo)致頻繁出現(xiàn)主備切換,除了改善節(jié)點(diǎn)之間的通信網(wǎng)絡(luò)質(zhì)量之外,也可以嘗試修改通信方式為單播。

    # ipv4網(wǎng)絡(luò)配置單播
    unicast_src_ip 192.168.229.1
    unicast_peer {
        192.168.229.2
    }
    
    # ipv6網(wǎng)絡(luò)配置單播
    unicast_src_ip 2000::1
    unicast_peer {
        2000::2
    }

上圖中的unicast_src_ip是本機(jī)的IP,而unicast_peer則是對(duì)端的IP,注意這里的unicast_peer是可以有多個(gè)IP的(對(duì)應(yīng)一主一備和一主多備或者多備搶占等情況)。

單播雖然在穩(wěn)定性上的表現(xiàn)更加優(yōu)秀,但是相應(yīng)的配置量也大大增加,需要運(yùn)維同學(xué)在每一組vrrp_instance都增加對(duì)應(yīng)的單播配置,并且主備節(jié)點(diǎn)之間的配置內(nèi)容也不同(一般都是unicast_src_ipunicast_peer對(duì)調(diào))。并且單播相關(guān)配置一旦改錯(cuò)幾乎就會(huì)發(fā)生腦裂,這就對(duì)配置管理檢查和分發(fā)提出了更高的要求。

4.2 主備切換

keepalived主備切換的時(shí)候容易出現(xiàn)的問(wèn)題主要是當(dāng)IP已經(jīng)切換到了另一臺(tái)機(jī)器,但是對(duì)應(yīng)交換機(jī)上面的MAC地址表記錄的VIP對(duì)應(yīng)的MAC地址還沒(méi)有更新。這種情況常見(jiàn)的解決方案就是使用arping(IPv4)操作或者是ping6(IPv6)來(lái)快速手動(dòng)刷新MAC記錄或者是配置keepalived來(lái)自動(dòng)持續(xù)刷新MAC記錄。

4.2.1 手動(dòng)刷新MAC

對(duì)于DPVS程序,刷新IPv4的VIP的MAC地址時(shí),如果VIP和對(duì)應(yīng)的kni網(wǎng)卡上的IP是同一個(gè)網(wǎng)段,則可以直接對(duì)kni網(wǎng)卡使用arping命令來(lái)刷新MAC地址(kni網(wǎng)卡和DPVS網(wǎng)卡的MAC地址一致);但是IPv6網(wǎng)絡(luò)并沒(méi)有arp這個(gè)東西,刷新MAC記錄需要使用ping6命令,而這在DPVS的kni網(wǎng)卡中是行不通的。個(gè)人建議使用python或go之類(lèi)的能夠網(wǎng)絡(luò)編程的語(yǔ)言編寫(xiě)一個(gè)簡(jiǎn)單的程序?qū)崿F(xiàn)發(fā)送gna數(shù)據(jù)包,然后在keepalived中配置腳本當(dāng)進(jìn)入master狀態(tài)的時(shí)候就執(zhí)行腳本刷新MAC地址,即可解決IPv6下VIP切換的MAC地址更新問(wèn)題。

4.2.2 keepalived刷新MAC

還有一種方案就是配置keepalived,讓keepalived自己發(fā)送garp和gna數(shù)據(jù)包,keepalived配置中有比較多的vrrp_garp*相關(guān)的配置可以調(diào)整發(fā)送garp和gna數(shù)據(jù)包的參數(shù)

# 發(fā)送garp/gna數(shù)據(jù)包的間隔。這里是每10秒發(fā)送一輪
vrrp_garp_master_refresh 10
# 每次發(fā)送三個(gè)garp/gna數(shù)據(jù)包
vrrp_garp_master_refresh_repeat 3
# 每個(gè)garp數(shù)據(jù)包的發(fā)送間隔為0.001秒
vrrp_garp_interval 0.001
# 每個(gè)gna數(shù)據(jù)包的發(fā)送間隔為0.001秒
vrrp_gna_interval 0.001

不過(guò)使用keepalived配置還有一個(gè)問(wèn)題:

  • keepalived發(fā)送garp/gna數(shù)據(jù)包的網(wǎng)卡是interface參數(shù)指定的網(wǎng)卡,也就是主備節(jié)點(diǎn)用來(lái)通信的網(wǎng)卡
  • keepalived發(fā)送的garp/gna數(shù)據(jù)包想要生效必須要是VIP所在的DPVS中的網(wǎng)卡或者是對(duì)應(yīng)的kni網(wǎng)卡

因此如果想讓keepalived來(lái)刷新VIP的MAC地址,需要將這個(gè)網(wǎng)卡修改為本文架構(gòu)圖中的bond2.kni網(wǎng)卡,也就是對(duì)應(yīng)雙臂網(wǎng)絡(luò)架構(gòu)模式下的外網(wǎng)網(wǎng)卡,同時(shí)如果使用單播通信的話還需要加上對(duì)應(yīng)節(jié)點(diǎn)的kni_host路由以確保單播能正常通信。

4.2.3 小結(jié)

以上兩種方案各有優(yōu)劣,需要結(jié)合內(nèi)外網(wǎng)網(wǎng)絡(luò)質(zhì)量、使用單播還是多播、網(wǎng)絡(luò)路由配置管理、keepalived文件管理等多個(gè)因素考慮。

5、集群最大連接數(shù)

這部分主要是分析對(duì)比傳統(tǒng)的LVS-DR模式和DPVS-FNAT模式下兩者的最大TCP連接數(shù)性能限制瓶頸。

5.1 LVS-DR模式

首先我們看一下傳統(tǒng)的LVS-DR模式下的連接表

[root@lvs]# ipvsadm -lnc | head | column -t
IPVS  connection  entries
pro   expire      state        source                 virtual            destination
TCP   00:16       FIN_WAIT     44.73.152.152:54300    10.0.96.104:80  192.168.229.111:80
TCP   00:34       FIN_WAIT     225.155.149.221:55182  10.0.96.104:80  192.168.229.117:80
TCP   00:22       ESTABLISHED  99.251.37.22:53601     10.0.96.104:80  192.168.229.116:80
TCP   01:05       FIN_WAIT     107.111.180.141:15997  10.0.96.104:80  192.168.229.117:80
TCP   00:46       FIN_WAIT     44.108.145.205:57801   10.0.96.104:80  192.168.229.116:80
TCP   12:01       ESTABLISHED  236.231.219.215:36811  10.0.96.104:80  192.168.229.111:80
TCP   01:36       FIN_WAIT     91.90.162.249:52287    10.0.96.104:80  192.168.229.116:80
TCP   01:41       FIN_WAIT     85.35.41.0:44148       10.0.96.104:80  192.168.229.112:80

從上面我們可以看出DPVS的連接表和LVS的連接表基本上大同小異,DPVS多了一列CPU核心數(shù)和LIP信息,但是從原理上有著極大的區(qū)別。

以下分析假定其他性能限制條件無(wú)瓶頸

首先對(duì)于LVS-DR模式而言,我們知道Client是直接和RS建立連接的,LVS在此過(guò)程中是只做數(shù)據(jù)包轉(zhuǎn)發(fā)的工作,不涉及建立連接這個(gè)步驟,那么影響連接數(shù)量的就是Protocol、CIP:Port、RIP:Port這五個(gè)變量,也就是常說(shuō)的五元組。

Protocol CIP:Port RIP:Port

考慮到Protocol不是TCP就是UDP,可以將其視為常量,也就是針對(duì)LVS-DR而言:真正影響TCP連接數(shù)的是CIP:Port(RIP:Port往往是固定的),但是由于CIP:Port理論上是可以足夠多的,所以這個(gè)時(shí)候TCP連接數(shù)的最大限制往往是在RS上面,也就是RS的數(shù)量和RS的性能決定了整個(gè)LVS-DR集群的最大TCP連接數(shù)。

5.2 DPVS-FNAT模式

接著我們使用ipvsadm -lnc命令來(lái)查看一下FNAT模式下的Client<-->DPVS<-->RS之間的連接情況:

[root@dpvs dpvs]# ipvsadm -lnc | head
[1]tcp  90s  TCP_EST    197.194.123.33:56058   10.0.96.216:443  192.168.228.1:41136  192.168.229.80:443
[1]tcp  7s   TIME_WAIT  26.251.198.234:21164   10.0.96.216:80   192.168.228.1:44896  192.168.229.89:80
[1]tcp  7s   TIME_WAIT  181.112.211.168:46863  10.0.96.216:80   192.168.228.1:62976  192.168.229.50:80
[1]tcp  90s  TCP_EST    242.73.154.166:9611    10.0.96.216:443  192.168.228.1:29552  192.168.229.87:443
[1]tcp  3s   TCP_CLOSE  173.137.182.178:53264  10.0.96.216:443  192.168.228.1:8512   192.168.229.87:443
[1]tcp  90s  TCP_EST    14.53.6.35:23820       10.0.96.216:443  192.168.228.1:44000  192.168.229.50:443
[1]tcp  3s   TCP_CLOSE  35.13.251.48:15348     10.0.96.216:443  192.168.228.1:16672  192.168.229.79:443
[1]tcp  90s  TCP_EST    249.109.242.104:5566   10.0.96.216:443  192.168.228.1:10112  192.168.229.77:443
[1]tcp  3s   TCP_CLOSE  20.145.41.157:6179     10.0.96.216:443  192.168.228.1:15136  192.168.229.86:443
[1]tcp  90s  TCP_EST    123.34.92.153:15118    10.0.96.216:443  192.168.228.1:9232   192.168.229.87:443
[root@dpvs dpvs]# ipvsadm -lnc | tail
[16]tcp  90s  TCP_EST    89.99.59.41:65197      10.0.96.216:443  192.168.228.1:7023   192.168.229.50:443
[16]tcp  3s   TCP_CLOSE  185.97.221.45:18862    10.0.96.216:443  192.168.228.1:48159  192.168.229.50:443
[16]tcp  90s  TCP_EST    108.240.236.85:64013   10.0.96.216:443  192.168.228.1:49199  192.168.229.50:443
[16]tcp  90s  TCP_EST    85.173.18.255:53586    10.0.96.216:443  192.168.228.1:63007  192.168.229.87:443
[16]tcp  90s  TCP_EST    182.123.32.10:5912     10.0.96.216:443  192.168.228.1:19263  192.168.229.77:443
[16]tcp  90s  TCP_EST    135.35.212.181:51666   10.0.96.216:443  192.168.228.1:22223  192.168.229.88:443
[16]tcp  90s  TCP_EST    134.210.227.47:29393   10.0.96.216:443  192.168.228.1:26975  192.168.229.90:443
[16]tcp  7s   TIME_WAIT  110.140.221.121:54046  10.0.96.216:443  192.168.228.1:5967   192.168.229.84:443
[16]tcp  3s   TCP_CLOSE  123.129.23.120:18550   10.0.96.216:443  192.168.228.1:7567   192.168.229.83:443
[16]tcp  90s  TCP_EST    72.250.60.207:33043    10.0.96.216:443  192.168.228.1:53279  192.168.229.86:443

然后我們逐個(gè)分析這些字段的含義:

  • [1]:這個(gè)數(shù)字表示的是CPU核心數(shù),對(duì)應(yīng)我們?cè)赿pvs.conf中配置的worker cpucpu_id,從這個(gè)字段可以看到每個(gè)DPVS進(jìn)程的worker線程工作的負(fù)載情況

  • tcp:tcp或者udp,對(duì)應(yīng)這一條連接的類(lèi)型,這個(gè)無(wú)需解釋

  • 90s30s、7s、3s:對(duì)應(yīng)這一條連接的時(shí)間

  • CLOSE_WAIT、FIN_WAIT、SYN_RECV、TCP_CLOSETCP_EST、TIME_WAIT:對(duì)應(yīng)這一條tcp連接的狀態(tài)

  • 最后這一組四個(gè)IP+Port的組合就是Client<-->DPVS<-->RS的對(duì)應(yīng)關(guān)系:

    CIP:Port VIP:Port LIP:Port RIP:Port
    

那么對(duì)于DPVS-FNAT模式來(lái)說(shuō),加入了LIP之后變成了四組IP+Port的組合,再加上前面的cpu_idProtocol就是影響連接數(shù)的十元組。

cpu_id Protocol CIP:Port VIP:Port LIP:Port RIP:Port
  • 開(kāi)始分析之前我們需要知道上面的這四組IP+Port的組合實(shí)際上是分為兩個(gè)四元組,即CIP:Port VIP:Port為一個(gè)四元組,LIP:Port RIP:Port為一個(gè)四元組,兩個(gè)四元組之間為一一對(duì)應(yīng)關(guān)系
  • 首先我們還是排除掉ProtocolVIP:PortRIP:Port,因?yàn)檫@三組五個(gè)變量基本也是固定的,可以視為常量
  • 接著是CIP:Port理論上是可以足夠多的,不會(huì)對(duì)我們的集群最大TCP連接數(shù)產(chǎn)生影響
  • 然后是cpu_id,雖然一臺(tái)機(jī)器最多可以有16個(gè)work cpu,但是并不意味著十元組的最大連接數(shù)=除cpu_id外的九元組的最大連接數(shù)*16,DPVS程序會(huì)把cpu_id根據(jù)LIP的端口號(hào)進(jìn)行分配,從而盡可能地把負(fù)載均分到所有的CPU上面。所以這里的cpu_id和LIP的端口號(hào)也是一一對(duì)應(yīng)的關(guān)系
  • 最后是LIP:Port,我們知道一個(gè)IP可以使用的端口數(shù)量最多不超過(guò)65536個(gè),由于RIP:Port是固定的,因此這個(gè)四元組的最大TCP連接數(shù)<=LIP數(shù)量*65536*RIP數(shù)量

又因?yàn)閮蓚€(gè)四元組之間為一一對(duì)應(yīng)關(guān)系,cpu_id和LIP的端口號(hào)也是一一對(duì)應(yīng)的關(guān)系,所以對(duì)于DPVS-FNAT模式來(lái)說(shuō),LIP的數(shù)量往往才是限制整個(gè)集群最大連接數(shù)的關(guān)鍵,如果集群有多連接數(shù)的需求,建議在規(guī)劃之初就要預(yù)留足夠數(shù)量的IP給LIP使用。

這里順便提一下,結(jié)合官方文檔和實(shí)測(cè),x520/82599、x710網(wǎng)卡在使用igb_uio這個(gè)PMD的時(shí)候,在ipv6網(wǎng)絡(luò)下fdir不支持perfect模式,建議使用signature模式,但是注意這個(gè)模式下僅可使用一個(gè)LIP,會(huì)對(duì)集群的最大連接數(shù)有限制。

官方文檔鏈接可以點(diǎn)擊這里查看。

We found there exists some NICs do not (fully) support Flow Control of IPv6 required by IPv6. For example, the rte_flow of 82599 10GE Controller (ixgbe PMD) relies on an old fashion flow type flow director (fdir), which doesn't support IPv6 in its perfect mode, and support only one local IPv4 or IPv6 in its signature mode. DPVS supports the fdir mode config for compatibility.

6、寫(xiě)在最后

DPVS確實(shí)在性能和功能方面都有著非常優(yōu)秀的表現(xiàn),也確實(shí)在落地初期會(huì)踩很多坑,建議多看文檔,多查資料,多看源碼,等到真正用起來(lái)之后也確實(shí)會(huì)給我們帶來(lái)很多的驚喜和收獲。最后順便提一句,如果只想搭建一個(gè)小規(guī)模集群嘗嘗鮮,普通的IPv4網(wǎng)絡(luò)和常見(jiàn)的x520網(wǎng)卡就足夠了,當(dāng)然有條件的同學(xué)可以嘗試使用ECMP架構(gòu)和一些比較好的網(wǎng)卡(如Mellanox)。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容