版權聲明:本文為CSDN博主「程序員肖邦」的原創文章,遵循 CC 4.0 BY 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/liwei0526vip/article/details/103104496
一、實驗環境說明
我們知道 LVS 工作模式有 DR、NAT、Tunnel 模式,這篇文章中會針對每個模式進行實踐操作,通過實驗來更深入理解工作原理。我們需要至少 4 台服務器來進行模擬實驗。
操作系統 CentOS release 6.5 (Final)
內核版本 2.6.32-754.15.3.el6.x86_64
相關服務器
- 1 台客戶端服務器
- 1 台負載均衡服務器
- 2 台后端真實服務器(模擬負載均衡調度)
注:為了簡單,我的幾台服務器都是在都一個二層網絡,如果有條件的話可以模擬更逼真一些。
注:虛擬機也可以,另外如果資源緊張的話,三台服務器也可(RS一台)
二、LVS 相關組件
在進行試驗操作之前,有必要先簡單
- IPVS。LVS 是基於內核態的 netfilter 框架實現的 IPVS 功能,工作在內核態。那么用戶是如何配置 VIP 等相關信息並傳遞到 IPVS 呢,就需要用到了 ipvsadm 工具。
- ipvsadm 工具。ipvsadm 是 LVS 用戶態的配套工具,可以實現 VIP 和 RS 的增刪改查功能。它是基於 netlink 或 raw socket 方式與內核 LVS 進行通信的,如果 LVS 類比於 netfilter,那么 ipvsadm 就是類似 iptables 工具的地位。
- keepalived。ipvsadm 是一個命令行工具,如果 LVS 需要配置的業務非常復雜,ipvadm 就很不方便了。keepalived 最早就是為了 LVS 而生的,非官方開發的,它提供了配置文件的形式配置管理(持久化),服務的增刪改查,操作非常方便。另外,keepalived 支持配置虛擬的 VIP,能夠實現 LVS 的高可用,實際生產環境中一般離不開它。
雖然 keepalived 使用起來非常方便,不過在實驗環境中為了簡化步驟,也能夠更清楚的理解操作步驟和原理,所有的操作都是用 ipvsadm 命令來進行的。后邊也會簡單介紹使用 keepalived 進行 LVS 服務的操作管理。
三、DR 模式操作實踐
(一)實驗環境
客戶端:10.211.102.46
負載均衡:VIP=10.211.102.47 DIP=172.16.100.10
后端1:172.16.100.20
后端2:172.16.100.30
(二)負載均衡服務器配置
安裝 ipvsadm 工具
$ yum install ipvsadm
配置vip服務
$ vim lvs_dr.sh # 內容如下: vip=10.211.102.47 rs1=172.16.100.20 rs2=172.16.100.30 /sbin/ipvsadm -C # 清除原有規則 /sbin/ipvsadm -A -t $vip:8088 -s rr # 添加vip:8088的tcp服務 /sbin/ipvsadm -a -t $vip:8088 -r $rs1:8088 -g # 添加rs1服務器 /sbin/ipvsadm -a -t $vip:8088 -r $rs2:8088 -g # 添加rs2服務器 # 執行腳本 $ /bin/bash lvs_dr.sh
查看服務配置情況
$ ipvsadm -ln -t 10.211.102.47:8088 Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.211.102.47:8088 rr -> 172.16.100.20:8088 Route 1 0 0 -> 172.16.100.30:8088 Route 1 0 0
(三)后端服務器配置
后端服務器需要安裝 nginx 服務
# 安裝 nginx 啟動並偵聽 8088 端口 $ yum install nginx # rs 配置 lo 和其它內核參數 $ vim rs_dr.sh # 內容如下: vip=10.211.102.47 ifconfig lo:0 $vip broadcast $vip netmask 255.255.255.255 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
執行腳本:
$ /bin/bash rs_dr.sh $ ifconfig lo:0 # 查看rs的lo:0接口配置信息 lo:0 Link encap:Local Loopback inet addr:10.211.102.47 Mask:255.255.255.255 UP LOOPBACK RUNNING MTU:16436 Metric:1
注:這些步驟需要在兩個 RS 上都進行相關操作。
(四)執行測試
上述所有步驟執行完畢后,如果一切都順利的話,執行測試命令會出現如下結果:
$ curl 10.211.102.47:8088 hello from rs1... $ curl 10.211.102.47:8088 hello from rs2...
實驗成功!兩次請求分別被調度到了兩台的后端服務器上了。感興趣的話,在后端服務器上抓包觀測實際數據包的各個字段是否符合預期。
四、DR 配置信息的含義
通過上述步驟,完成最簡單的 DR 模式配置。在負載均衡服務器上配置的信息容易理解,而在后端服務器上配置了 lo 和內核參數,下邊以問題的方式來解釋清楚這些含義。
為什么需要在 lo 接口配置 vip ?
A:我們知道如果服務器收到的數據包 IP 地址不是本機地址(沒開啟轉發模式),就會丟棄。后端服務器收到 DR 模式的數據包,此時目標 IP 是 VIP,服務器會認為此數據包不是發送給本機的,會丟棄。而我們在 lo 接口上配置 VIP 后,服務器就能夠正常接收此數據包,發送給相應的應用程序了。因此,在 lo 上配置 vip 能夠完成接收數據包並將結果返回給 client。
為什么需要配置 arp_ignore 參數?
A:我們在 lo 上配置了 vip,正常情況下,其它設備發送 vip 的 arp 請求時,除了負載均衡設備會響應 arp 請求之外,后端服務器也會響應 vip 的 arp 請求,這樣請求設備不知道哪個是准確的了,反正就是亂了。我們在參數中配置 arp_ignore=1 之后,后端服務器只會響應目的 IP 地址為接收網卡上的本地地址的 arp 請求。由於 vip 配置了在 lo 上,所以其它接口收到相關的 arp 請求都會忽略掉,這樣保證了 arp 請求正確性。這也說明了為什么 vip 必須配置在 lo 接口上而不是其它接口上了。
為什么需要配置 arp_announce 參數?
當后端服務器向客戶端發送響應數據包時,源地址和目的地址確定,通過目標地址查找路由后,發送網卡也是確認的,也就是源 MAC 地址是確認的,目的 MAC 地址還不確定,需要獲取下一跳 IP 對應的 MAC 地址,就需要發送 arp 請求了。發送的 arp 請求目的 IP 就是下一跳的地址,而源 IP 是什么呢?系統通常默認會取數據包的源 IP 作為 arp 的源 IP。我們認真想一下,源 IP 不就是 VIP 么,假設以 VIP 為源 IP 發送 arp 請求,那下一跳(路由器)學習到的 MAC 地址和 IP 地址對應關系就會錯亂,因為負載均衡設備上的 VIP 對應的 MAC 地址肯定與這個不同,導致整個系統 arp 紊亂。
而我們配置參數 arp_announce=2 后,操作系統在發送 arp 請求選擇源 IP 時,就會忽略數據包的源地址,選擇發送網卡上最合適的本地地址作為 arp 請求的源地址。
五、NAT 模式操作實踐
(一)實驗環境
- 客戶端:10.211.102.46
- 負載均衡:VIP=10.211.102.47 DIP=172.16.100.10
- 后端1:172.16.100.20
- 后端2:172.16.100.30
(二)負載均衡服務器配置
安裝 ipvsadm 並執行相關配置
$ yum install ipvsadm $ vim lvs_nat.sh # 內容如下 echo 1 > /proc/sys/net/ipv4/ip_forward vip=10.211.102.47 rs1=172.16.100.20 rs2=172.16.100.30 /sbin/ipvsadm -C /sbin/ipvsadm -A -t $vip:8088 -s rr /sbin/ipvsadm -a -t $vip:8088 -r $rs1:8088 -m /sbin/ipvsadm -a -t $vip:8088 -r $rs2:8088 -m # 執行腳本 $ /bin/bash lvs_nat.sh
查看服務配置信息
$ ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.211.102.47:8088 rr -> 172.16.100.20:8088 Masq 1 0 0 -> 172.16.100.30:8088 Masq 1 0 0
(三)后端服務器配置
后端服務器安裝和配置如下:
$ yum install nginx # 安裝 nginx,啟動並偵聽 8088 端口 # vim rs_nat.sh # 如下內容 route add default gw 172.16.100.10 dev eth0 # 默認網關配置為負載均衡的 DIP # 執行腳本(兩個rs都需要執行) $ /bin/bash rs_nat.sh
(四)執行測試
上述所有步驟執行完畢后,如果一切都順利的話,執行測試命令會出現如下結果:
$ curl 10.211.102.47:8088 hello from rs1... $ curl 10.211.102.47:8088 hello from rs2...
實驗成功!兩次請求分別被調度到了兩台的后端服務器上了。感興趣的話,在后端服務器上抓包觀測實際數據包的各個字段是否符合預期。
(五)關於后端服務器設置默認網關
在后端服務器為何要設置默認網關指向負載均衡設備?由於 NAT 模式是雙向流量都經過 LVS 設備,所以后端服務器需要將響應報文發送給 LVS 設備,不過此時的數據包目的 IP 是客戶端的 IP,可能是外網的任何一個網段,需要通過設置路由的方式,將數據包轉發給 LVS ,因為不可能窮舉所有的網段地址,所以必須要設置默認的網關來指向 LVS。最后也要強調一下,負載均衡設備需要開啟 ipv4 的 forward 參數。
六、Tunnel 模式操作實踐
(一)實驗環境
- 客戶端:10.211.102.46
- 負載均衡:VIP=10.211.102.47 DIP=172.16.100.10
- 后端1:172.16.100.20 ,注,rs 與 DIP 可以不在一個網段,只要三層通就行。
- 后端2:172.16.100.30
(二)負載均衡服務器配置
安裝 ipvsadm 並執行相關配置
$ yum install ipvsadm $ vim lvs_tunnel.sh # 內容如下 vip=10.211.102.47 rs1=172.16.100.20 rs2=172.16.100.30 /sbin/ipvsadm -C /sbin/ipvsadm -A -t $vip:8088 -s rr /sbin/ipvsadm -a -t $vip:8088 -r $rs1:8088 -i /sbin/ipvsadm -a -t $vip:8088 -r $rs2:8088 -i ## 執行腳本 $ /bin/bash lvs_tunnel.sh
查看服務配置信息
$ ipvsadm -ln IP Virtual Server version 1.2.1 (size=4096) Prot LocalAddress:Port Scheduler Flags -> RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.211.102.47:8088 rr -> 172.16.100.20:8088 Tunnel 1 0 0 -> 172.16.100.30:8088 Tunnel 1 0 0
(三)后端服務器配置
后端服務器安裝和配置如下:
$ yum install nginx # 安裝 nginx,啟動並偵聽 8088 端口 # vim rs_tunnel.sh # 如下內容 vip=10.211.102.47 modprobe ipip ifconfig tunl0 $vip broadcast $vip netmask 255.255.255.255 up echo "0" > /proc/sys/net/ipv4/ip_forward echo "1" >/proc/sys/net/ipv4/conf/all/arp_ignore echo "2" >/proc/sys/net/ipv4/conf/all/arp_announce echo "0" > /proc/sys/net/ipv4/conf/all/rp_filter echo "0" > /proc/sys/net/ipv4/conf/tunl0/rp_filter # 執行腳本(兩個rs都需要執行) $ /bin/bash rs_tunnel.sh
(四)執行測試
上述所有步驟執行完畢后,如果一切都順利的話,執行測試命令會出現如下結果:
$ curl 10.211.102.47:8088 hello from rs1... $ curl 10.211.102.47:8088 hello from rs2...
實驗成功!兩次請求分別被調度到了兩台的后端服務器上了。感興趣的話,在后端服務器上抓包觀測實際數據包的各個字段是否符合預期。
(五)為何設置 rp_filter 參數
為何需要設置 rp_filter 參數?A:默認 rp_filter 參數設置為 1,Linux 會反向校驗源 IP 的路由,如果源和目的 IP 路由出口不是一個網卡,就會被丟棄。因為數據包到后端服務器物理網卡后會被轉發給虛擬網卡 tunl0 接口,這時進入的網卡是 tunl0,而源 IP 的路由出口網卡肯定不是 tunl0,所以數據包會被丟棄。配置 rp_filter 參數為 0,就相當於關閉了這個校驗。
七、使用keepalived配置LVS
上述的所有操作都是通過 ipvsadm 命令來實現的,雖然也能完成相應的功能,但也存在如下的問題:
- 命令行操作和變更,很不方便。
- 配置信息不方便持久化。
- 假設一個 RealServer 宕機或無響應,LVS 仍會將請求轉發至后端,導致業務不可用。
- 存在單點問題,如果 LVS 服務器宕機,則全部服務不可用。
keepalived 本身就是為 LVS 而開發的,能夠優雅的解決上述問題。
(一)實驗環境
- 客戶端:10.211.102.46
- 負載均衡1:VIP=10.211.102.47 DIP=172.16.100.10
- 負載均衡2:VIP=10.211.102.48 DIP=172.16.100.40
- 后端1:172.16.100.20 ,注,rs 與 DIP 可以不在一個網段,只要三層通就行。
- 后端2:172.16.100.30
(二)安裝配置keepalvied
負載均衡設備需要安裝 keepalived 軟件
$ yum install keepalived
keepalived master 配置文件
$ vim /etc/keepalived/keepalived.conf vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 10.211.102.47 } } virtual_server 10.211.102.47 8088 { delay_loop 3 lb_algo wrr lb_kind DR protocol TCP real_server 172.16.100.20 8088 { weight 1 TCP_CHECK { connect_timeout 10 connect_port 8088 } } real_server 172.16.100.30 8088 { weight 1 TCP_CHECK { connect_timeout 10 connect_port 8088 } } }
backup 結點配置文件
# 拷貝主節點的配置文件keepalived.conf,然后修改如下內容: state MASTER -> state BACKUP priority 100 -> priority 90
啟動 keepalvied 軟件
$ service keepalived start
(三)執行測試
- 健康檢查。手動關閉 rs2,執行測試命令,發現 lvs 會一直將請求轉發至 rs1。恢復 rs2,lvs 很快就會感知並將 rs2 加入到集群列表。
- 高可用。手動 stop 掉 lvs1,會發現 vip 漂移到 lvs2 上,執行測試命令,正常工作。
八、LVS 的幾種調度算法
在前邊的一些實驗過程中,會發現 ipvsadm 命令最后邊的 -s rr ,就表示的是調度算法,其中 rr 就是最簡單的輪詢調度算法,下邊先簡單介紹負載均衡 LVS 支持的幾種調度算法。
- 輪詢rr - 這種算法是最簡單的,就是按依次循環的方式將請求調度到不同的服務器上,該算法最大的特點就是簡單。輪詢算法假設所有的服務器處理請求的能力都是一樣的,調度器會將所有的請求平均分配給每個真實服務器,不管后端 RS 配置和處理能力,非常均衡地分發下去。
- 加權輪詢wrr - 這種算法比 rr 的算法多了一個權重的概念,可以給 RS 設置權重,權重越高,那么分發的請求數越多。實際生產環境的服務器配置可能不同,根據服務器配置適當設置權重,可以有效利用服務器資源。
- 最少連接lc - 這個算法會根據后端 RS 的連接數來決定把請求分發給誰,比如 RS1 連接數比 RS2 連接數少,那么請求就優先發給 RS1
- 加權最少鏈接 wlc - 這個算法比 lc 多了一個權重的概念。
- 基於局部性的最少連接調度算法 lblc - 這個算法是請求數據包的目標 IP 地址的一種調度算法,該算法先根據請求的目標 IP 地址尋找最近的該目標 IP 地址所有使用的服務器,如果這台服務器依然可用,並且有能力處理該請求,調度器會盡量選擇相同的服務器,否則會繼續選擇其它可行的服務器。
- 復雜的基於局部性最少的連接算法 lblcr - 記錄的不是要給目標 IP 與一台服務器之間的連接記錄,它會維護一個目標 IP 到一組服務器之間的映射關系,防止單點服務器負載過高。
- 目標地址散列調度算法 dh - 該算法是根據目標 IP 地址通過散列函數將目標 IP 與服務器建立映射關系,出現服務器不可用或負載過高的情況下,發往該目標 IP 的請求會固定發給該服務器。
- 源地址散列調度算法 sh - 與目標地址散列調度算法類似,但它是根據源地址散列算法進行靜態分配固定的服務器資源。
————————————————
