LVS是Linux Virtual Server的簡稱,也就是Linux虛擬服務器, 是一個由章文嵩博士發起的自由軟件項目,它的官方站點是www.linuxvirtualserver.org。
現在LVS已經是Linux標準內核的一部分,在Linux2.4內核以前,使用LVS時必須要重新編譯內核以支持LVS功能模塊,但是從Linux2.4內核以後,已經完全內置了LVS的各個功能模塊,無需給內核打任何補丁,可以直接使用LVS提供的各種功能。
LVS主要用於服務器集羣的負載均衡。其優點有:
#工作在網絡層,可以實現高性能,高可用的服務器集羣技術。 #廉價,可把許多低性能的服務器組合在一起形成一個超級服務器。 #易用,配置非常簡單,且有多種負載均衡的方法。 #穩定可靠,即使在集羣的服務器中某臺服務器無法正常工作,也不影響整體效果。 #可擴展性也非常好。
安裝配置
linux內核2.4版本以上的基本都支持LVS,要使用lvs,只需要再安裝一個lvs的管理工具:ipvsadm
yum install ipvsadm
ipvsadm用法
其實LVS的本身跟iptables很相似,而且連命令的使用格式都很相似,其實LVS是根據iptables的框架開發的,那麼LVS的本身分成了兩個部分:
第一部分是工作在內核空間的一個IPVS的模塊,其實LVS的功能都是IPVS模塊實現的,
第二部分是工作在用戶空間的一個用來定義集羣服務的一個工具ipvsadm, 這個工具的主要作用是將管理員定義的集羣服務列表傳送給工作在內核空間中的IPVS模塊,下面來簡單的介紹下ipvsadm命令的用法
ipvsadm組件定義規則的格式:
#virtual-service-address:是指虛擬服務器的ip 地址 #real-service-address:是指真實服務器的ip 地址 #scheduler:調度方法 #ipvsadm 的用法和格式如下: ipvsadm -A|E -t|u|f virutal-service-address:port [-s scheduler] [-p[timeout]] [-M netmask] ipvsadm -D -t|u|f virtual-service-address ipvsadm -C ipvsadm -R ipvsadm -S [-n] ipvsadm -a|e -t|u|f service-address:port -r real-server-address:port [-g|i|m] [-w weight] ipvsadm -d -t|u|f service-address -r server-address ipvsadm -L|l [options] ipvsadm -Z [-t|u|f service-address] ipvsadm --set tcp tcpfin udp ipvsadm --start-daemon state [--mcast-interface interface] ipvsadm --stop-daemon ipvsadm -h #命令選項解釋:有兩種命令選項格式,長的和短的,具有相同的意思。在實際使用時,兩種都可以。 -A --add-service #在內核的虛擬服務器表中添加一條新的虛擬服務器記錄。也就是增加一臺新的虛擬服務器。 -E --edit-service #編輯內核虛擬服務器表中的一條虛擬服務器記錄。 -D --delete-service #刪除內核虛擬服務器表中的一條虛擬服務器記錄。 -C --clear #清除內核虛擬服務器表中的所有記錄。 -R --restore #恢復虛擬服務器規則 -S --save #保存虛擬服務器規則,輸出爲-R 選項可讀的格式 -a --add-server #在內核虛擬服務器表的一條記錄裏添加一條新的真實服務器記錄。也就是在一個虛擬服務器中增加一臺新的真實服務器 -e --edit-server #編輯一條虛擬服務器記錄中的某條真實服務器記錄 -d --delete-server #刪除一條虛擬服務器記錄中的某條真實服務器記錄 -L|-l --list #顯示內核虛擬服務器表 -Z --zero #虛擬服務表計數器清零(清空當前的連接數量等) --set tcp tcpfin udp #設置連接超時值 --start-daemon #啓動同步守護進程。他後面可以是master 或backup,用來說明LVS Router 是master 或是backup。在這個功能上也可以採用keepalived 的VRRP 功能。 --stop-daemon #停止同步守護進程 -h --help #顯示幫助信息 #其他的選項: -t --tcp-service service-address #說明虛擬服務器提供的是tcp 的服務[vip:port] or [real-server-ip:port] -u --udp-service service-address #說明虛擬服務器提供的是udp 的服務[vip:port] or [real-server-ip:port] -f --fwmark-service fwmark #說明是經過iptables 標記過的服務類型。 -s --scheduler scheduler #使用的調度算法,有這樣幾個選項rr|wrr|lc|wlc|lblc|lblcr|dh|sh|sed|nq,默認的調度算法是: wlc. -p --persistent [timeout] #持久穩固的服務。這個選項的意思是來自同一個客戶的多次請求,將被同一臺真實的服務器處理。timeout 的默認值爲300 秒。 -M --netmask #子網掩碼 -r --real-server server-address #真實的服務器[Real-Server:port] -g --gatewaying 指定LVS 的工作模式爲直接路由模式(也是LVS 默認的模式) -i --ipip #指定LVS 的工作模式爲隧道模式 -m --masquerading #指定LVS 的工作模式爲NAT 模式 -w --weight weight #真實服務器的權值 --mcast-interface interface #指定組播的同步接口 -c --connection #顯示LVS 目前的連接 如:ipvsadm -L -c --timeout #顯示tcp tcpfin udp 的timeout 值 如:ipvsadm -L --timeout --daemon #顯示同步守護進程狀態 --stats #顯示統計信息 --rate #顯示速率信息 --sort #對虛擬服務器和真實服務器排序輸出 --numeric -n #輸出IP 地址和端口的數字形式 ipvsadm命令方法
LVS的10種調度算法
lvs調度算法(不區分大小寫)可以分爲兩大類:
1.Fixed Scheduling Method 靜態調服方法 RR #輪詢 #調度器通過"輪叫"調度算法將外部請求按順序輪流分配到集羣中的真實服務器上,它均等地對待每一臺服務器,而不管服務器上實際的連接數和系統負載。 WRR #加權輪詢 #調度器通過"加權輪叫"調度算法根據真實服務器的不同處理能力來調度訪問請求。 這樣可以保證處理能力強的服務器處理更多的訪問流量。調度器 可以自動問詢真實服務器的負載情況,並動態地調整其權值。 DH #目標地址hash #算法也是針對目標IP地址的負載均衡,但它是一種靜態映射算法,通過一個散列(Hash)函數將一個目標IP地址映射到一臺服務器。 #目標地址散列調度算法先根據請求的目標IP地址,作爲散列鍵(Hash Key)從靜態分配的散列表找出對應的服務器,若該服務器是可用的且未超載,將請求發送到該服務器,否則返回空。 SH #源地址hash #算法正好與目標地址散列調度算法相反,它根據請求的源IP地址,作爲散列鍵(Hash Key)從靜態分配的散列表找出對應的服務器,若該服務器是 可用的且未超載,將請求發送到該服務器,否則返回空。 #它採用的散列函數與目標地址散列調度算法的相同。除了將請求的目標IP地址換成請求的源IP地址外,它的算法流程與目標地址散列調度算法的基本相似。在實際應用中,源地址散列調度和目標地址散列調度可以結合使用在防火牆集羣中,它們可以保證整個系統的唯一出入口。 2.Dynamic Scheduling Method 動態調服方法 LC #最少連接 #調度器通過"最少連接"調度算法動態地將網絡請求調度到已建立的鏈接數最少的服務器上。 如果集羣系統的真實服務器具有相近的系統性能,採用"最小連接"調度算法可以較好地均衡負載。 WLC #加權最少連接 #在集羣系統中的服務器性能差異較大的情況下,調度器採用"加權最少鏈接"調度算法優化負載均衡性能,具有較高權值的服務器將承受較大比例的活動連接負載。調度器可以自動問詢真實服務器的負載情況,並動態地調整其權值。 SED #最少期望延遲 #基於wlc算法,舉例說明:ABC三臺機器分別權重123,連接數也分別是123,name如果使用WLC算法的話一個新請求 進入時他可能會分給ABC中任意一個,使用SED算法後會進行這樣一個運算 #A:(1+1)/2 #B:(1+2)/2 #C:(1+3)/3 #根據運算結果,把連接交給C NQ #從不排隊調度方法 #無需列隊,如果有臺realserver的連接數=0 就直接分配過去,不需要進行sed運算. LBLC #基於本地的最少連接 # "基於局部性的最少鏈接" 調度算法是針對目標IP地址的負載均衡,目前主要用於Cache集羣系統。 #該算法根據請求的目標IP地址找出該 目標IP地址最近使用的服務器,若該服務器 是可用的且沒有超載,將請求發送到該服務器; #若服務器不存在,或者該服務器超載且有服務器處於一半的工作負載,則用"最少鏈接"的原則選出一個可用的服務器,將請求發送到該服務器。 LBLCR #帶複製的基於本地的最少連接 #"帶複製的基於局部性最少鏈接"調度算法也是針對目標IP地址的負載均衡,目前主要用於Cache集羣系統。 #它與LBLC算法的不同 之處是它要維護從一個 目標IP地址到一組服務器的映射,而LBLC算法維護從一個目標IP地址到一臺服務器的映射。 #該算法根據請求的目標IP地址找出該目標IP地址對應的服務器組,按"最小連接"原則從服務器組中選出一臺服務器, #若服務器沒有超載,將請求發送到該服務器;若服務器超載,則按"最小連接"原則從這個集羣中選出一 臺服務器 ,將該服務器加入到服務器組中,將請求發送到該服務器。同時,當該服務器組有一段時間沒有被修改, 將最忙的服務器從服務器組中刪除,以降低複製的程度。 lvs調度算法
LVS三種工作模式:NAT(地址轉換)、DR(直接路由)、TUN(隧道)
LVS-NAT:地址轉換
架構圖:
工作方式:
NAT模型其實就是通過網絡地址轉換來實現負載均衡的。下面是它的流程:
1.用戶請求VIP(也可以說是CIP請求VIP) 2,Director Server 收到用戶的請求後,發現源地址爲CIP請求的目標地址爲VIP,那麼Director Server會認爲用戶請求的是一個集羣服務,那麼Director Server 會根據此前設定好的調度算法將用戶請求負載給某臺Real Server。 假如說此時Director Server 根據調度的結果會將請求分攤到RealServer1上去,那麼Director Server 會將用戶的請求報文中的目標地址,從原來的VIP改爲RealServer1的IP,然後再轉發給RealServer1 3,此時RealServer1收到一個源地址爲CIP目標地址爲自己的請求,那麼RealServer1處理好請求後會將一個源地址爲自己目標地址爲CIP的數據包通過Director Server 發出去, 4.當Driector Server收到一個源地址爲RealServer1 的IP 目標地址爲CIP的數據包,此時Driector Server 會將源地址修改爲VIP,然後再將數據包發送給用戶
LVS-NAT的性能瓶頸:
在LVS/NAT的集羣系統中,請求和響應的數據報文都需要通過負載調度器(Director),當真實服務器(RealServer)的數目在10臺和20臺之間時,負載調度器(Director)將成爲整個集羣系統的新瓶頸。
大多數Internet服務都有這樣的特點:請求報文較短而響應報文往往包含大量的數據。如果能將請求和響應分開處理,即在負載調度器(Director)中只負責調度請求而響應直接(RealServer)返回給客戶,將極大地提高整個集羣系統的吞吐量。
部署
在RealServer上部署httpd服務並測試
#安裝httpd服務,創建httpd測試頁面,啓動httpd服務 [root@web1 ~]# yum -y install httpd [root@web1 ~]# service httpd start [root@web1 ~]# echo "RS1-web1 Allentuns.com" > /var/www/html/index.html [root@web2 ~]# yum -y install httpd [root@web2 ~]# echo "RS2-web2 Allentuns.com" > /var/www/html/index.html [root@web2 ~]# service httpd start #測試httpd服務是否OK! [root@web1 ~]# curl http://localhost RS1-web1 Allentuns.com [root@web1 ~]# curl http://172.16.100.11 RS2-web2 Allentuns.com
在Director上部署ipvs服務並測試
添加集羣服務
[root@LVS ~]# ipvsadm -A -t 192.168.0.200:80 -s rr #定義一個集羣服務 [root@LVS ~]# ipvsadm -a -t 192.168.0.200:80 -r 172.16.100.10 -m #添加RealServer並指派調度算法爲NAT [root@LVS ~]# ipvsadm -a -t 192.168.0.200:80 -r 172.16.100.11 -m #添加RealServer並指派調度算法爲NAT [root@LVS ~]# ipvsadm -L -n #查看ipvs定義的規則列表 IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.0.200:80 rr -> 172.16.100.10:80 Masq 1 0 0 -> 172.16.100.11:80 Masq 1 0 0 [root@LVS ~]# cat /proc/sys/net/ipv4/ip_forward #查看Linux是否開啓路由轉發功能 0 [root@LVS ~]# echo 1 > /proc/sys/net/ipv4/ip_forward #啓動Linux的路由轉發功能 [root@LVS ~]# cat /proc/sys/net/ipv4/ip_forward 1
測試訪問http頁面
[root@LVS ~]# curl http://192.168.0.200/index.html RS2-web2 Allentuns.com #第一次是web2 [root@LVS ~]# curl http://192.168.0.200/index.html RS1-web1 Allentuns.com #第二次是web1 [root@LVS ~]# curl http://192.168.0.200/index.html RS2-web2 Allentuns.com #第三次是web1 [root@LVS ~]# curl http://192.168.0.200/index.html RS1-web1 Allentuns.com #第四次是web2
更改LVS的調度算法並壓力測試,查看結果
[root@LVS ~]# ipvsadm -E -t 192.168.0.200:80 -s wrr [root@LVS ~]# ipvsadm -e -t 192.168.0.200:80 -r 172.16.100.10 -m -w 3 [root@LVS ~]# ipvsadm -e -t 192.168.0.200:80 -r 172.16.100.11 -m -w 1 [root@LVS ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.0.200:80 wrr -> 172.16.100.10:80 Masq 3 0 2 -> 172.16.100.11:80 Masq 1 0 2 [root@LVS ~]# curl http://192.168.0.200/index.html RS1-web1 Allentuns.com [root@LVS ~]# curl http://192.168.0.200/index.html RS1-web1 Allentuns.com [root@LVS ~]# curl http://192.168.0.200/index.html RS1-web1 Allentuns.com [root@LVS ~]# curl http://192.168.0.200/index.html RS2-web2 Allentuns.com [root@LVS ~]# curl http://192.168.0.200/index.html RS1-web1 Allentuns.com
永久保存LVS規則並恢復
#第一種方法: [root@LVS ~]# service ipvsadm save ipvsadm: Saving IPVS table to /etc/sysconfig/ipvsadm: [確定] #第二種方法: [root@LVS ~]# ipvsadm -S > /etc/sysconfig/ipvsadm.s1
模擬清空ipvsadm規則來恢復
[root@LVS ~]# ipvsadm -C [root@LVS ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn [root@LVS ~]# ipvsadm -R < /etc/sysconfig/ipvsadm.s1 [root@LVS ~]# ipvsadm -L -n IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 192.168.0.200:80 wrr -> 172.16.100.10:80 Masq 3 0 0 -> 172.16.100.11:80 Masq 1 0 0
腳本
LVS-NAT服務控制腳本部署在Director上
#!/bin/bash # # chkconfig: - 88 12 # description: LVS script for VS/NAT # . /etc/rc.d/init.d/functions # VIP=192.168.0.200 DIP=172.16.100.1 RIP1=172.16.100.10 RIP2=172.16.100.11 # case "$1" in start) # /sbin/ifconfig eth1:0 $VIP netmask 255.255.255.0 up # Since this is the Director we must be able to forward packets echo 1 > /proc/sys/net/ipv4/ip_forward # Clear all iptables rules. /sbin/iptables -F # Reset iptables counters. /sbin/iptables -Z # Clear all ipvsadm rules/services. /sbin/ipvsadm -C # Add an IP virtual service for VIP 192.168.0.219 port 80 # In this recipe, we will use the round-robin scheduling method. # In production, however, you should use a weighted, dynamic scheduling method. /sbin/ipvsadm -A -t $VIP:80 -s rr # Now direct packets for this VIP to # the real server IP (RIP) inside the cluster /sbin/ipvsadm -a -t $VIP:80 -r $RIP1 -m /sbin/ipvsadm -a -t $VIP:80 -r $RIP2 -m /bin/touch /var/lock/subsys/ipvsadm.lock ;; stop) # Stop forwarding packets echo 0 > /proc/sys/net/ipv4/ip_forward # Reset ipvsadm /sbin/ipvsadm -C # Bring down the VIP interface ifconfig eth1:0 down rm -rf /var/lock/subsys/ipvsadm.lock ;; status) [ -e /var/lock/subsys/ipvsadm.lock ] && echo "ipvs is running..." || echo "ipvsadm is stopped..." ;; *) echo "Usage: $0 {start|stop}" ;; esac lvs-nat-director.sh
分享LVS-NAT一鍵安裝腳本
#!/bin/bash # # 一鍵安裝lvs-nat腳本,需要注意的是主機名成和ip的變化稍作修改就可以了 HOSTNAME=`hostname` Director='LVS' VIP="192.168.0.200" RIP1="172.16.100.10" RIP2="172.16.100.11" RealServer1="web1" RealServer2="web2" Httpd_config="/etc/httpd/conf/httpd.conf" #Director Server Install configure ipvsadm if [ "$HOSTNAME" = "$Director" ];then ipvsadm -C yum -y remove ipvsadm yum -y install ipvsadm /sbin/ipvsadm -A -t $VIP:80 -s rr /sbin/ipvsadm -a -t $VIP:80 -r $RIP1 -m /sbin/ipvsadm -a -t $VIP:80 -r $RIP2 -m echo 1 > /proc/sys/net/ipv4/ip_forward echo "========================================================" echo "Install $Director sucess Tel:13260071987 Qq:467754239" echo "========================================================" fi #RealServer Install htpd if [ "$HOSTNAME" = "$RealServer1" ];then yum -y remove httpd rm -rf /var/www/html/index.html yum -y install httpd echo "web1 Allentuns.com" > /var/www/html/index.html sed -i '/#ServerName www.example.com:80/a\ServerName localhost:80' $Httpd_config service httpd start echo "========================================================" echo "Install $RealServer1 success Tel:13260071987 Qq:467754239" echo "========================================================" fi if [ "$HOSTNAME" = "$RealServer2" ];then yum -y remove httpd rm -rf /var/www/html/index.html yum -y install httpd echo "web2 Allentuns.com" > /var/www/html/index.html sed -i '/#ServerName www.example.com:80/a\ServerName localhost:80' $Httpd_config service httpd start echo "Install $RealServer2" echo "=========================================================" echo "Install $RealServer1 success Tel:13260071987 Qq:467754239" echo "=========================================================" fi lvs-nat-install
LVS-DR:直接路由
架構圖:
工作方式:
上面說了NAT模型的實現方式,那麼NAT模型有個缺陷,因爲進出的每個數據包都要經過Director Server,當集羣系統負載過大的時候Director Server將會成爲整個集羣系統的瓶頸,
那麼DR模型就避免了這樣的情況發生,DR模型在只有請求的時候纔會經過Director Server, 迴應的數據包由Real Server 直接響應用戶不需要經過Director Server,其實三種模型中最常用的也就是DR模型了。
下面是它的工作流程:
1, 首先用戶用CIP請求VIP 2, 根據上圖可以看到,不管是Director Server還是Real Server上都需要配置VIP,那麼當用戶請求到達我們的集羣網絡的前端路由器的時候,請求數據包的源地址爲CIP目標地址爲VIP, 此時路由器會發廣播問誰是VIP,那麼我們集羣中所有的節點都配置有VIP,此時誰先響應路由器那麼路由器就會將用戶請求發給誰,這樣一來我們的集羣系統是不是沒有意義了, 那我們可以在網關路由器上配置靜態路由指定VIP就是Director Server,或者使用一種機制不讓Real Server 接收來自網絡中的ARP地址解析請求,這樣一來用戶的請求數據包都會經過Director Servrer 3,當Director Server收到用戶的請求後根據此前設定好的調度算法結果來確定將請求負載到某臺Real Server上去,假如說此時根據調度算法的結果,會將請求負載到RealServer 1上面去, 此時Director Server 會將數據幀中的目標MAC地址修改爲Real Server1的MAC地址,然後再將數據幀發送出去 4,當Real Server1 收到一個源地址爲CIP目標地址爲VIP的數據包時,Real Server1發現目標地址爲VIP,而VIP是自己,於是接受數據包並給予處理,當Real Server1處理完請求後, 會將一個源地址爲VIP目標地址爲CIP的數據包發出去,此時的響應請求就不會再經過Director Server了,而是直接響應給用戶。
編輯DR有三種方式(目的是讓用戶請求的數據都通過Director Server)
第一種方式:在路由器上明顯說明vip對應的地址一定是Director上的MAC,只要綁定,以後再跟vip通信也不用再請求了,這個綁定是靜態的,所以它也不會失效,也不會再次發起請求,但是有個前提,我們的路由設備必須有操作權限能夠綁定MAC地址,萬一這個路由器是運行商操作的,我們沒法操作怎麼辦?第一種方式固然很簡便,但未必可行。
第二種方式:在給別主機上(例如:紅帽)它們引進的有一種程序arptables,它有點類似於iptables,它肯定是基於arp或基於MAC做訪問控制的,很顯然我們只需要在每一個real server上定義arptables規則,如果用戶arp廣播請求的目標地址是本機的vip則不予相應,或者說相應的報文不讓出去,很顯然網關(gateway)是接受不到的,也就是director相應的報文才能到達gateway,這個也行。第二種方式我們可以基於arptables。
第三種方式:在相對較新的版本中新增了兩個內核參數(kernelparameter),第一個是arp_ignore定義接受到ARP請求時的相應級別;第二個是arp_announce定義將自己地址向外通告是的通告級別。【提示:很顯然我們現在的系統一般在內核中都是支持這些參數的,我們用參數的方式進行調整更具有樸實性,它還不依賴於額外的條件,像arptables,也不依賴外在路由配置的設置,反而通常我們使用的是第三種配置】
arp_ignore:定義接受到ARP請求時的相應級別
0:只要本地配置的有相應地址,就給予響應。 1:僅在請求的目標地址配置請求到達的接口上的時候,纔給予響應(當別人的arp請求過來的時候,如果接收的設備上面沒有這個ip,就不響應,默認是0,只要這臺機器上面任何一個設備上面有這個ip,就響應arp請求,併發送MAC地址應答。) 2:只回答目標IP地址是來訪網絡接口本地地址的ARP查詢請求,且來訪IP必須在該網絡接口的子網段內 3:不迴應該網絡界面的arp請求,而只對設置的唯一和連接地址做出迴應 4-7:保留未使用 8:不迴應所有(本地地址)的arp查詢
arp_announce:定義將自己地址向外通告是的通告級別;
0: 將本地任何接口上的任何地址向外通告 1:試圖僅想目標網絡通告與其網絡匹配的地址 2:僅向與本地藉口上地址匹配的網絡進行通告
部署
在Real Server1 和Real Server2上做以下配置
# echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore # echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce # echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore # echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce #以上命令需填加到/etc/rc.local文件中讓其開機自動生效 # vim /etc/sysconfig/network-scripts/ifcfg-lo:0 內容如下 DEVICE=lo:0 IPADDR=172.16.100.100 NETMASK=255.255.255.255 BROADCAST=172.16.100.100 ONBOOT=yes NAME=loopback # ifdown lo:0 # ifup lo:0 # route add -host 172.16.100.100 dev lo:0 # echo "route add -host 172.16.100.100 dev lo:0" >> /etc/rc.local
在Director Server上做以下配置
# vim /etc/sysconfig/network-scripts/ifcfg-eth2:0 內容如下 DEVICE=eth2:0 IPADDR=172.16.100.100 NETMASK=255.255.255.255 BROADCAST=172.16.100.100 ONBOOT=yes # ifdown eth2:0 #命令 # ifup eth2:20 # route add -host 172.16.100.100 dev eth2:0 # echo "route add -host 172.16.100.100 dev eth2:0" >> /etc/rc.local # echo "1" > /proc/sys/net/ipv4/ip_forward # echo "echo "1" > /proc/sys/net/ipv4/ip_forward" >> /etc/rc.local # ipvsadm -A -t 172.16.100.100:80 -s wlc # ipvsadm -a -t 172.16.100.100:80 -r 172.16.100.10 -g -w 2 # ipvsadm -a -t 172.16.100.100:80 -r 172.16.100.11 -g -w 1
腳本
Director腳本
#!/bin/bash # # LVS script for VS/DR # . /etc/rc.d/init.d/functions # VIP=172.16.100.100 RIP1=172.16.100.10 RIP2=172.16.100.11 PORT=80 # case "$1" in start) /sbin/ifconfig eth2:0 $VIP broadcast $VIP netmask 255.255.255.255 up /sbin/route add -host $VIP dev eth2:0 # Since this is the Director we must be able to forward packets echo 1 > /proc/sys/net/ipv4/ip_forward # Clear all iptables rules. /sbin/iptables -F # Reset iptables counters. /sbin/iptables -Z # Clear all ipvsadm rules/services. /sbin/ipvsadm -C # Add an IP virtual service for VIP 192.168.0.219 port 80 # In this recipe, we will use the round-robin scheduling method. # In production, however, you should use a weighted, dynamic scheduling method. /sbin/ipvsadm -A -t $VIP:80 -s wlc # Now direct packets for this VIP to # the real server IP (RIP) inside the cluster /sbin/ipvsadm -a -t $VIP:80 -r $RIP1 -g -w 1 /sbin/ipvsadm -a -t $VIP:80 -r $RIP2 -g -w 2 /bin/touch /var/lock/subsys/ipvsadm &> /dev/null ;; stop) # Stop forwarding packets echo 0 > /proc/sys/net/ipv4/ip_forward # Reset ipvsadm /sbin/ipvsadm -C # Bring down the VIP interface /sbin/ifconfig eth2:0 down /sbin/route del $VIP /bin/rm -f /var/lock/subsys/ipvsadm echo "ipvs is stopped..." ;; status) if [ ! -e /var/lock/subsys/ipvsadm ]; then echo "ipvsadm is stopped ..." else echo "ipvs is running ..." ipvsadm -L -n fi ;; *) echo "Usage: $0 {start|stop|status}" ;; esac Director.sh
RealServer腳本
#!/bin/bash # # Script to start LVS DR real server. # description: LVS DR real server # . /etc/rc.d/init.d/functions VIP=172.16.100.100 host=`/bin/hostname` case "$1" in start) # Start LVS-DR real server on this machine. /sbin/ifconfig lo down /sbin/ifconfig lo up echo 1 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/lo/arp_announce echo 1 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 2 > /proc/sys/net/ipv4/conf/all/arp_announce /sbin/ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up /sbin/route add -host $VIP dev lo:0 ;; stop) # Stop LVS-DR real server loopback device(s). /sbin/ifconfig lo:0 down echo 0 > /proc/sys/net/ipv4/conf/lo/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/lo/arp_announce echo 0 > /proc/sys/net/ipv4/conf/all/arp_ignore echo 0 > /proc/sys/net/ipv4/conf/all/arp_announce ;; status) # Status of LVS-DR real server. islothere=`/sbin/ifconfig lo:0 | grep $VIP` isrothere=`netstat -rn | grep "lo:0" | grep $VIP` if [ ! "$islothere" -o ! "isrothere" ];then # Either the route or the lo:0 device # not found. echo "LVS-DR real server Stopped." else echo "LVS-DR real server Running." fi ;; *) # Invalid entry. echo "$0: Usage: $0 {start|status|stop}" exit 1 ;; esac RealServer.sh
LVS-TUN:隧道
架構圖:
工作方式:
TUN的工作機制跟DR一樣,只不過在轉發的時候,它需要重新包裝IP報文。這裏的real server(圖中爲RIP)離得都比較遠。
用戶請求以後,到director上的VIP上,它跟DR模型一樣,每個realserver上既有RIP又有VIP,Director就挑選一個real server進行響應,但director和real server並不在同一個網絡上,這時候就用到隧道了,Director進行轉發的時候,一定要記得CIP和VIP不能動。
我們轉發是這樣的,讓它的CIP和VIP不動,在它上面再加一個IP首部,再加的IP首部源地址是DIP,目標地址的RIP的IP地址。收到報文的RIP,拆掉報文以後發現了裏面還有一個封裝,它就知道了,這就是隧道。
其實數據轉發原理和DR是一樣的,不過這個我個人認爲主要是位於不同位置(不同機房);LB是通過隧道進行了信息傳輸,雖然增加了負載,可是因爲地理位置不同的優勢,還是可以參考的一種方案;
優點:負載均衡器只負責將請求包分發給物理服務器,而物理服務器將應答包直接發給用戶。所以,負載均衡器能處理很巨大的請求量,這種方式,一臺負載均衡能爲超過100臺的物理服務器服務,負載均衡器不再是系統的瓶頸。 使用VS-TUN方式,如果你的負載均衡器擁有100M的全雙工網卡的話,就能使得整個Virtual Server能達到1G的吞吐量。 不足:但是,這種方式需要所有的服務器支持"IP Tunneling"(IP Encapsulation)協議;
LVS的健康狀態檢查
在LVS模型中,director不負責檢查RS的健康狀況,這就使得當有的RS出故障了,director還會將服務請求派發至此服務器,這種情況對用戶、企業都是很不爽的,哪個用戶倒黴說不定就遇到類似了。
爲了讓Director更人性化、可靠還要給director提供健康檢查功能;如何實現?Director沒有自帶檢查工具,只有手動編寫腳本給director實現健康狀態檢查功能!
#!/bin/bash # VIP=172.16.100.100 CPORT=80 FAIL_BACK=127.0.0.1 RS=("172.16.100.10" "172.16.100.11") declare -a RSSTATUS RW=("2" "1") RPORT=80 TYPE=g CHKLOOP=3 LOG=/var/log/ipvsmonitor.log addrs() { ipvsadm -a -t $VIP:$CPORT -r $1:$RPORT -$TYPE -w $2 [ $? -eq 0 ] && return 0 || return 1 } delrs() { ipvsadm -d -t $VIP:$CPORT -r $1:$RPORT [ $? -eq 0 ] && return 0 || return 1 } checkrs() { local I=1 while [ $I -le $CHKLOOP ]; do if curl --connect-timeout 1 http://$1 &> /dev/null; then return 0 fi let I++ done return 1 } initstatus() { local I local COUNT=0; for I in ${RS[*]}; do if ipvsadm -L -n | grep "$I:$RPORT" && > /dev/null ; then RSSTATUS[$COUNT]=1 else RSSTATUS[$COUNT]=0 A++ Dir[0]=$A fi let COUNT++ done } initstatus while :; do let COUNT=0 for I in ${RS[*]}; do if checkrs $I; then if [ ${RSSTATUS[$COUNT]} -eq 0 ]; then addrs $I ${RW[$COUNT]} [ $? -eq 0 ] && RSSTATUS[$COUNT]=1 && echo "`date +'%F %H:%M:%S'`, $I is back." >> $LOG fi else if [ ${RSSTATUS[$COUNT]} -eq 1 ]; then delrs $I [ $? -eq 0 ] && RSSTATUS[$COUNT]=0 && echo "`date +'%F %H:%M:%S'`, $I is gone." >> $LOG fi fi let COUNT++ done sleep 5 done check-lvs-health.sh