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

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

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

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

[root@lvs ~]# 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
[root@lvs ~]# 

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

是否需要會話保持

如果設計的集羣牽扯到會話保持那麼在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:
[root@userclient ~]# ifconfig eno16777736 172.16.3.93 netmask 255.255.255.0 up      ##配置eno16777736
Director配置:
[root@lvs ~]# ifconfig eno16777736 172.16.3.181 netmask 255.255.255.0 up      ##配置eno16777736爲172.16.3.181 ,臨時生效重啓失效,建議修改配置文件
[root@lvs ~]# ifconfig eno33554992 192.168.1.254 netmask 255.255.255.0 up
[root@lvs ~]# iptables -F     ##清空規則防止iptables的input鏈對ipvs產生影響
[root@lvs ~]# ipvsadm -A -t 172.16.3.181:80 -s wrr    ##添加集羣服務,-t 指定tcp協議,-s 指定調度策略,這裏爲加權輪詢
[root@lvs ~]# ipvsadm -a -t 172.16.3.181:80 -r 192.168.1.11:80 -m -w 1  ## -m 指的是nat模型,-w 配置權重值
[root@lvs ~]# ipvsadm -a -t 172.16.3.181:80 -r 192.168.1.12:80 -m -w 2
[root@lvs ~]# ipvsadm-save -n > /etc/sysconfig/ipvsadm         ##備份ipvs配置
[root@lvs ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf      ##開啓ipv4核心轉發
[root@lvs ~]# sysctl -p

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

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

測試:
由於沒有配置會話保持的情況下,根據wlc的特性以及我們分配的權重值得到以下結果:
[root@userclient ~]# 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:
[root@userclient ~]# 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配置:
[root@lvs ~]# yum install ipvsadm -y
[root@lvs ~]# ifconfig eno16777736:0 172.16.3.99 netmask 255.255.255.255 broadcast 172.16.3.99 up
[root@lvs ~]# iptables -F       ##清空規則防止iptables的input鏈對ipvs產生影響
[root@lvs ~]# ipvsadm -A -t 172.16.3.99:80 -s wrr     ##添加集羣服務,-t 指定tcp協議,-s 指定調度策略,這裏爲加權輪詢
[root@lvs ~]# 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指定權重
[root@lvs ~]# ipvsadm -a -t 172.16.3.99:80 -r 172.16.3.89:80 -g -w 2
[root@lvs ~]# ipvsadm-save -n > /etc/sysconfig/ipvsadm      ##保存策略到文件,便於下次恢復
[root@lvs ~]# 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配置:

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

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

測試結果:
由於沒有配置會話保持的情況下,根據wlc的特性以及我們分配的權重值得到以下結果:
[root@userclient ~]# 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>
[root@userclient ~]# 

對於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        
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章