LVS-Ip Tunnel模式應用(轉)

一、什麼是Ip Tunnel模式

 Ip Tunnel,又叫IP隧道,顧名思義,LVS通過在IP數據包外面再封裝了一層Ip Tunnel 頭部,將數據包的源地址改寫爲LVS自身的物理地址,目的地址改寫爲RS的物理地址,從而實現跨網段訪問RS。整個過程看起來好像LVS和RS之間有一條隧道,數據包通過這條虛擬的隧道進行傳輸。
如下圖所示:

 

Ip Tunnel封裝

 

 Ip Tunnel模式下,客戶端的請求包到達負載均衡器的虛擬服務IP端口後,負載均衡器不會改寫請求包的IP和端口,但是會在數據包IP層外面再封裝一個IP層,然後將數據包轉發;真實服務器收到請求後,會先將外面封裝的Ip Tunnel頭去掉,然後處理裏面實際的請求報文;與DR模式類似,響應包也不再經過LVS,而是直接返回給客戶端。所以Ip Tunnel模式的轉發效率雖然弱於DR,但是強於NAT。

二、爲什麼要用Ip Tunnel模式

 既然Ip Tunnel模式的性能比不上DR,那爲什麼還要用它呢? 因爲它可以跨網段轉發!
 Ip Tunnel模式最大的優點就在於它可以跨網段轉發,沒有DR和NAT模式的組網限制。這在部署上帶來的很大的靈活性,甚至還可以跨機房轉發,不過不建議這樣使用,一是會帶來跨機房間的流量,提高了成本;二是跨機房轉發必然會要在RS機房上綁定LVS機房的VIP,這有可能會被運營商的防火牆認爲是IP僞造請求而攔截。

三、如何配置Ip Tunnel模式

【LVS配置】

  1. 使用ipvsadm配置

 

  ipvsadm -A -t vip:port -s rr
  ipvsadm -a -t vip:port -r rip -i 
  1. 使用Keepalived配置
    推薦使用Keepalived管理LVS。Keepalived提供配置文件keepalived.conf,可以很方便的配置LVS,並且提供了健康檢查功能。

 

virtual_server vip port {
    delay_loop 6
    lb_algo rr
    lb_kind TUN          //與DR模式唯一的區別就是這裏配置爲TUN
#    persistence_timeout 50
    protocol TCP

    real_server rip port {
        weight 100
        TCP_CHECK {
            connect_timeout 3
            retry 3
            delay_before_retry 3
        }
    }
}

 注意這裏只寫了與DR模式配置不一樣的地方,lvs上配置vip之類的就沒寫了。

【RS配置】

  1. 加載ipip模塊。

 

modprobe ipip
  1. 啓動tunl0虛擬網卡

 

ifconfig tunl0 up
  1. 將vip綁定在tunl0網卡上。(注意這裏也是與DR模式不同的地方,DR模式是將vip綁在LO網卡)

 

ip addr add vip dev tunl0
  1. 設置內核參數

 

echo "0" > /proc/sys/net/ipv4/ip_forward
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "0" > /proc/sys/net/ipv4/conf/all/rp_filter
echo "0" > /proc/sys/net/ipv4/conf/tunl0/rp_filter

 注意Ip Tunnel模式下需要將RS上的rp_filter參數配爲0,否則無法正常工作,因爲RS是在物理網卡收到請求,但是VIP是綁在虛擬網卡tunl0上的。

四、Ip Tunnel模式需要注意的地方

【Ip Tunnel模式存在的問題】

 Ip Tunnel模式下,LVS會在數據報文原有的IP頭部上再封裝一層IP頭,封裝層IP頭的源IP是LVS節點的物理IP,目的IP是RS的物理IP,相當於原有的數據報文是在一層封裝的隧道中傳輸。
 這樣可以解決跨網段轉發的問題,但是會帶來一個新的問題:
 每個數據包都要封裝一個新的20字節的IP頭,如果LVS上收到的數據包就已經達到了Ethernet幀的最大值1514(MTU1500+幀頭14),這時候封裝層的IP頭就無法加進去。如果數據報文IP頭中設置了DF標誌位(Don't Fragment),這時候LVS就無法正常轉發該報文。而是會返回一個Type=3,Code=4的ICMP報文給客戶端,通知客戶端目的地不可達,需要分片,並且在通知報文中指定了本端的MTU爲1480。如果客戶端支持PMTUD協議,那麼客戶端會根據ICMP中通知的MTU值重新計算合適的MSS,對要發送的數據進行分片後再重傳給LVS節點。
 下圖是TUN模式下LVS上的抓包,可以看到一開始LVS收到的數據包的data長度爲1460,加上20字節TCP頭,加上20字節IP頭,已經達到MTU1500了(抓包大小爲1514是算上了14字節的Ethernet幀頭)。

 

數據長度爲1460

 

 這時候LVS無法轉發,通過ICMP報文通知客戶端分片後重傳。

 

ICMP通知重傳

 

告知本端MTU爲1480


 下圖可以看到重傳後的數據報文中data長度變成了1440,剩餘的data位於另外的分片中。1440加上20字節TCP頭,加上20字節IP頭剛好等於ICMP報文中通知的MTU值1480。此時LVS在1480的基礎上再插入20字節的封裝層的IP頭,剛好等於物理網卡的MTU值1500。這時候IP TUNNEL模式就可以正常轉發了。

數據長度爲1440


 出現這個問題的原因在於IP TUNNEL模式下,LVS需要在源數據報文中再插入20字節的封裝層IP頭,所以它將自身的MTU值降到了1480。 這個情況下,LVS對每個大包(超過1480)的包都通過ICMP消息通知客戶端分片。這依賴於客戶端支持PMTUD,並且還依賴於ICMP通知能正常返回到客戶端。因爲在實際情況下,ICMP消息在返回客戶端的過程中需要經過多跳公網路由,在中間很可能會被攔截過濾掉,這時客戶端無法收到LVS返回的ICMP通知,就無法正常的分片重傳了,導致LVS轉發失敗。

【解決方法】

 可以通過減少RS側的MSS值,比如調到1400。這樣客戶端在和RS三次握手協商MSS的時候,就會使用修改後的MSS值。這樣客戶端網卡在對數據包進行分片時就會減小單個請求中的data大小,確保LVS上收到的請求大小不會超過1480,從而不會觸發到上述的問題。
 iptables配置方法如下,實際情況中可以根據需求指定規則所要匹配的ip地址,這樣可以減小配置修改的影響範圍。

 

iptables -A OUTPUT -s xxx -p tcp --tcp-flags ALL SYN,ACK -j TCPMSS --set-mss 1400

 下面是修改後的客戶端上的抓包結果:

 

MSS修改爲1400

 

 從上圖可以看到客戶端在三次握手過程中收到的RS溝通的MSS值爲修改後的值1400。
(注意wireshark中之所以能抓到超過1514字節的包,是因爲目前大部分機器上都是開啓了TSO/GSO的,TCP分片的工作下放給了網卡驅動去做;而wireshark抓到的是網卡緩衝區中的數據,還沒有進行分片,所以有可能會看到大於1514的包;但是在真正發送出去的時候網卡驅動會根據MSS對TCP報文進行分片;可以對比服務端收到的抓包,服務端上收到的包就不會超過1514字節了)
 下面是LVS上的抓包結果:

 

MSS=1400


 LVS上收到來自客戶端的數據包分片中的data長度也變成了1400,這樣LVS就可以正常插入封裝層IP頭進行轉發了。
 下圖可以看到插入封裝頭後,數據包裏面有兩層IP頭。

兩層IP頭

 

 下圖展示的就是LVS收到No. 1442的請求包,大小爲1454字節;插入20字節的封裝頭後,數據包變爲1474字節,然後轉發給RS。

 

Ip Tunnel轉發



作者:Mr蘿蔔
鏈接:https://www.jianshu.com/p/11ee89c54449
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章