1. 程式人生 > >LVS下的NAT模型與DR模型實戰

LVS下的NAT模型與DR模型實戰

LVS是工作在四層的高效能負載均衡伺服器,由於工作在TCP/IP層並不涉及到使用者態,擺脫了套接字65535數量的限制,所以效能十分強悍,當然優秀的背後少不了我們國人章文嵩的付出,感謝開源如此優秀的作品。

LVS 是工作在核心netfilter的INPUT鏈路上的一組ipvs框架,他的使用有點類似於配置netfilter實現防火牆過濾需要藉助iptables這組工具,當然LVS也是如此,只提供了介面,如果想要配置ipvs需要首先安裝ipvsadm這組工具,ipvsadm在base源中就有提供

在開始之前首先判斷的系統是否支援ipvs,最單粗暴的辦法

[[email protected]
~]# grep -i "ipvs" /boot/config-3.10.0-327.el7.x86_64 CONFIG_NETFILTER_XT_MATCH_IPVS=m # IPVS transport protocol load balancing support # IPVS scheduler # IPVS SH scheduler # IPVS application helper [[email protected] ~]#

在開始設計負載均衡之前我們首先考慮以下四點?

是否需要會話保持

如果設計的叢集牽扯到會話保持那麼在lvs的排程演算法上可能需要有所選擇
方式一:排程演算法控制
採用:SH,LBLC,LBLCR進行控制
方式二:叢集引數控制*
採用:ipvsadm -A|E -t|u|f service-address [-s scheduler] [-p [timeout]]
需要注意的是任何形式的會話保持策略都有損負載均衡叢集的公平性

-

是否需要共享儲存

這個是任何的叢集服務幾乎都要考慮的問題,檔案一致性,不過這個問題似乎也不難解決,基礎的NFS可以解決這種問題,或者任何NAS服務都可以作為解決方案,需要注意的是業務場景以及業務需求進行決定,一般分為兩種形式
1、類主從(rsync+inotify)
2、分散式檔案系統

-

服務是否需要藉助防火牆標記實現

如果你的服務比如nginx牽扯到80以及443的rewrite跳轉,那麼當80rewirte之後意味著將重新進行請求,我們希望他跳轉443時仍然是同一臺伺服器,這個時候就需要藉助iptables在prerouting鏈路上將2種服務封裝為1種標記,我們根據標記進行處理

打標記方法(在Director主機):iptables -t mangle -A PREROUTING -d $vip -p $proto --dport $port -j MARK --set-mark NUMBER

健康狀態檢查如何實現

由於LVS本身四層的特性決定了不具備高等協議http,https等7層協議的健康探測能力,所以如果一旦RS種一臺服務出現了宕機,ipvs規則並不能實現自動移除,所以需要一種工作在七層或者說使用者態上的守護程序臺實時進行探測服務可用性,如果出現異常則儘快將其從ipvs列表中移除,當恢復時則自動新增,當全部宕機時提供sorryserver的功能
方案一:keepalived、ldirectord、corosync,推薦本方法
方案二:自行shell指令碼實現,不推薦此方法,對資源消耗太大

排程演算法的選擇

ipvs scheduler:根據其排程時是否考慮各RS當前的負載狀態,可分為靜態方法和動態方法兩種:

  • 靜態方法:僅根據演算法本身進行排程;
    RR:roundrobin,輪詢;
    WRR:Weighted RR,加權輪詢;
    SH:Source Hashing,實現session sticky,源IP地址hash;將來自於同一個IP地址的請求始終發往第一次挑中的RS,從而實現會話繫結;
    DH:Destination Hashing;目標地址雜湊,將發往同一個目標地址的請求始終轉發至第一次挑中的RS,典型使用場景是正向代理快取場景中的負載均衡;

  • 動態方法:主要根據每RS當前的負載狀態及排程演算法進行排程;
    LC:least connections 最少連線數, Overhead=activeconns256+inactiveconns 活動連線數256+非活動連線數 非活動連線數對系統消耗非常低,幾萬個也就是幾兆記憶體,一般非活動連線數可以忽略不計
    WLC:Weighted LC 加權最少連線數,Overhead=(activeconns256+inactiveconns)/weight 活動連線數256+非活動連線數/權重
    SED:Shortest Expection Delay 最短的預期延遲,Overhead=(activeconns+1)*256/weight 同等條件下當前伺服器連線數為0時,演算法預製1個連結數,0+1除以權重值(這裡為了方便不乘256),所以權重值越大,效能越高,得到的結果越小,越優先提供服務
    NQ:Never Queue 從不排隊,當伺服器之間權重值相差較大時,A:1 B:10意味著SED下優先給10個請求到B伺服器,A則在10個請求之前一直閒置,NQ的出現是指每臺伺服器按照權重先負載起來,不至於一直工作到B不能工作為止

           LBLC:Locality-Based LC,動態的DH演算法,也就是最少連線的目標地址hash演算法;
           LBLCR:LBLC with Replication,帶複製功能的LBLC,通過動態的DH演算法訪問到B,使用者的請求在A,B則向A請求,假如A伺服器承載了90%的活躍,B伺服器承載了10%活躍,A將一部分活躍通過快取項的複製功能複製到B,同時在進行請求;
  • NAT拓樸設計:

Useragent Director RS1 RS2
CIP:172.16. 3. 93 VIP:172.16.3.181 DIP:192.168.1.254 RIP:192.168.1.11 RIP:192.168.1.12

配置資訊:

Useragent:
[[email protected] ~]# ifconfig eno16777736 172.16.3.93 netmask 255.255.255.0 up      ##配置eno16777736
Director配置:
[[email protected] ~]# ifconfig eno16777736 172.16.3.181 netmask 255.255.255.0 up      ##配置eno16777736為172.16.3.181 ,臨時生效重啟失效,建議修改配置檔案
[[email protected] ~]# ifconfig eno33554992 192.168.1.254 netmask 255.255.255.0 up
[[email protected] ~]# iptables -F     ##清空規則防止iptables的input鏈對ipvs產生影響
[[email protected] ~]# ipvsadm -A -t 172.16.3.181:80 -s wrr    ##新增叢集服務,-t 指定tcp協議,-s 指定排程策略,這裡為加權輪詢
[[email protected] ~]# ipvsadm -a -t 172.16.3.181:80 -r 192.168.1.11:80 -m -w 1  ## -m 指的是nat模型,-w 配置權重值
[[email protected] ~]# ipvsadm -a -t 172.16.3.181:80 -r 192.168.1.12:80 -m -w 2
[[email protected] ~]# ipvsadm-save -n > /etc/sysconfig/ipvsadm         ##備份ipvs配置
[[email protected] ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf      ##開啟ipv4核心轉發
[[email protected] ~]# sysctl -p

RS1配置:
[[email protected] ~]#  ifconfig eno16777736 192.168.1.11 netmask 255.255.255.0 up
[[email protected] ~]#  route add default gw 192.168.1.254
[[email protected] ~]# yum install nginx -y;syatemctl start nginx;systemctl enable nginx
[[email protected] ~]# echo "<h1>R1,192.168.1.11</h1>" > /usr/share/nginx/html/index.html

RS2配置:
[[email protected] ~]#  ifconfig eno16777736 192.168.1.12 netmask 255.255.255.0 up
[[email protected] ~]#  route add default gw 192.168.1.254
[[email protected] ~]# yum install nginx -y;syatemctl start nginx;systemctl enable nginx
[[email protected] ~]# echo "<h1>R1,192.168.1.12</h1>" > /usr/share/nginx/html/index.html

測試:
由於沒有配置會話保持的情況下,根據wlc的特性以及我們分配的權重值得到以下結果:
[[email protected] ~]# for k in {1..10};do curl 172.16.3.181:80;done
<h1>R2,192.168.1.12</h1>
<h1>R1,192.168.1.11</h1>
<h1>R2,192.168.1.12</h1>
<h1>R2,192.168.1.12</h1>
<h1>R1,192.168.1.11</h1>
<h1>R2,192.168.1.12</h1>
<h1>R2,192.168.1.12</h1>
<h1>R1,192.168.1.11</h1>
<h1>R2,192.168.1.12</h1>
<h1>R2,192.168.1.12</h1>

DR模型處理流程:
1、當用戶通過公網訪問請求到達伺服器網路時,報文結構是【CIP+port|VIP+port】,由於路由器末梢區域介面和VIP工作在同一網路,第一次路由器不知道VIP的IP地址
2、路由器發出ARP廣播請求問,誰是VIP,這個過程是ARP廣播通告(arpannounce),而DR收到請求之後將會進行ARP響應(arpignore),並提供自己的MAC。此時其他配置了VIP的RS伺服器由於限制了arpannounce和arpignore則無法響應,所以只有DR能響應自己的MAC
3、當路由器收到來自DR的MAC後,在原來的報文基礎上新增【源MAC(路由器MAC)|目標MAC(VIP的Mac)】+【CIP+port|VIP+port】被交換機根據MAC交換送往DR
4、當DR收到後拆分MAC報文後報文得到【CIP+port|VIP+port】,到達防火牆input鏈上的ipvs匹配到port是叢集服務埠,則將報文修改為【源MAC(VIP的Mac)|目標MAC(RS1的Mac)】【CIP+port|VIP+port】進行交換機交換到RS1
5、當RS1收到交換機的資料包拆分得到【CIP+port|VIP+port】,發現目標IP是本機的lo:0的VIP,自己無法處理,必須通過lo:0的vip來處理(配置route add -h $vip dev lo:0的形式指定),當lo:0收到後,得到port,交給程序進行處理,然後【VIP+port|CIP+port】交給外層eno網絡卡進行返回

6、eno外層網絡卡收到後封裝【源MAC(RS的Mac)|目標MAC(路由的Mac)】【VIP+port|CIP+port】通過路由器一直送達公司外層路由器...然後通過公網返回給使用者

DR拓樸設計:

Useragent Director RS1 RS2
CIP:172.16. 3. 93 DIP:172.16.3.181 VIP:172.16.3.99 RIP:172.16.3.87 VIP:172.16.3.99 RIP:172.16.3.89 VIP:172.16.3.99

配置資訊:

Useragent:
[[email protected] ~]# ifconfig eno16777736
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.3.93  netmask 255.255.255.0  broadcast 172.16.3.255

Director配置:
[[email protected] ~]# yum install ipvsadm -y
[[email protected] ~]# ifconfig eno16777736:0 172.16.3.99 netmask 255.255.255.255 broadcast 172.16.3.99 up
[[email protected] ~]# iptables -F       ##清空規則防止iptables的input鏈對ipvs產生影響
[[email protected] ~]# ipvsadm -A -t 172.16.3.99:80 -s wrr     ##新增叢集服務,-t 指定tcp協議,-s 指定排程策略,這裡為加權輪詢
[[email protected] ~]# ipvsadm -a -t 172.16.3.99:80 -r 172.16.3.87:80 -g -w 1     ##為172.16.3.99:80叢集服務新增RS,-g 指定DR模型,-w指定權重
[[email protected] ~]# ipvsadm -a -t 172.16.3.99:80 -r 172.16.3.89:80 -g -w 2
[[email protected] ~]# ipvsadm-save -n > /etc/sysconfig/ipvsadm      ##儲存策略到檔案,便於下次恢復
[[email protected] ~]# ifconfig 
eno16777736: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.3.181  netmask 255.255.255.0  broadcast 172.16.3.255
eno16777736:0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
        inet 172.16.3.99  netmask 255.255.255.255  broadcast 172.16.3.99

RS1配置:

[[email protected] ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore    ##僅在請求的目標IP配置在本地主機的接收到請求報文介面上時,才給予響應;
[[email protected] ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[[email protected] ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce    ##必須避免向非本網路通告;
[[email protected] ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[[email protected] ~]# ifconfig lo:0 172.16.3.99 netmask 255.255.255.0 broadcast 172.16.3.99 up
[[email protected] ~]# route add -host 172.16.3.99 dev lo:0     ##當收到目標ip為172.16.3.99的請求丟給lo:0進行處理
[[email protected] ~]# yum install nginx -y;syatemctl start nginx;systemctl enable nginx
[[email protected] ~]# echo "<h1>R1,172.16.3.87</h1>" > /usr/share/nginx/html/index.html

RS2配置:
[[email protected] ~]# echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
[[email protected] ~]# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
[[email protected] ~]# echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
[[email protected] ~]# echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce
[[email protected] ~]# ifconfig lo:0 172.16.3.99 netmask 255.255.255.0 broadcast 172.16.3.99 up
[[email protected] ~]# route add -host 172.16.3.99 dev lo:0
[[email protected] ~]# yum install nginx -y;syatemctl start nginx;systemctl enable nginx
[[email protected] ~]# echo "<h1>R2,172.16.3.89</h1>" > /usr/share/nginx/html/index.html

測試結果:
由於沒有配置會話保持的情況下,根據wlc的特性以及我們分配的權重值得到以下結果:
[[email protected] ~]# for k in {1..10};do curl 172.16.3.99:80;done
<h1>R2,172.16.3.89</h1>
<h1>R2,172.16.3.89</h1>
<h1>R1,172.16.3.87</h1>
<h1>R2,172.16.3.89</h1>
<h1>R2,172.16.3.89</h1>
<h1>R1,172.16.3.87</h1>
<h1>R2,172.16.3.89</h1>
<h1>R2,172.16.3.89</h1>
<h1>R1,172.16.3.87</h1>
<h1>R2,172.16.3.89</h1>
[[email protected] ~]# 

對於DR模式的配置我們可以藉助指令碼很方面的實現:
RS的指令碼配置:

#!/bin/bash
#
vip='172.16.3.99'
mask='255.255.255.255'

case $1 in
start)
    echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore
    echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce
    echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce

    ifconfig lo:0 $vip netmask $mask broadcast $vip up
    route add -host $vip dev lo:0
    ;;
stop)
    ifconfig lo:0 down

    echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore
    echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore
    echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce
    echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce

    ;;
*) 
    echo "Usage $(basename $0) start|stop"
    exit 1
    ;;
esac    

Director的指令碼配置:

#!/bin/bash
#
vip='172.16.3.99'
iface='eno16777736:0'
mask='255.255.255.255'
port='80'
rs1='172.16.3.87'
rs2='172.16.3.89'
scheduler='wrr'
type='-g'

case $1 in
start)
    ifconfig $iface $vip netmask $mask broadcast $vip up
    iptables -F

    ipvsadm -A -t ${vip}:${port} -s $scheduler
    ipvsadm -a -t ${vip}:${port} -r ${rs1} $type -w 1
    ipvsadm -a -t ${vip}:${port} -r ${rs2} $type -w 1
    ;;
stop)
    ipvsadm -C
    ifconfig $iface down
    ;;
*)
    echo "Usage $(basename $0) start|stop"
    exit 1
    ;;
esac