:DR模式搭建、高可用與生產級調優(yōu))
1. 為什么今天還要親手搭一套LVS集群——不是為了懷舊而是為了看清流量洪峰的“骨骼”很多人看到“LVS”第一反應是這不早被云廠商的SLB、ALB、CLB全包圓了嗎點幾下控制臺就搞定誰還 ssh 進去敲 ipvsadm這話沒錯但錯在把“能用”和“懂用”混為一談。我去年參與某電商大促保障時監(jiān)控突然報警核心下單接口 P99 延遲從 80ms 暴漲到 2.3s而云負載均衡控制臺顯示一切正常——健康檢查通過、連接數(shù)未超限、帶寬利用率僅 35%。最后排查發(fā)現(xiàn)是云廠商默認開啟的“會話保持Session Stickiness”策略在突發(fā)流量下導致后端節(jié)點負載嚴重傾斜3臺服務器中1臺承載了72%的請求CPU打滿而另外兩臺空閑率超60%。問題根源不在應用層而在負載均衡器對連接狀態(tài)的調度邏輯上。LVS 的價值恰恰在于它把負載均衡這件事“剝得足夠薄”。它不處理 HTTP 頭、不解析 Cookie、不重寫 URL只在 Linux 內核 Netfilter 的 IP 層做連接轉發(fā)決策。這意味著你調一個ipvsadm -Ln就能看到當前所有活躍連接的源IP、目標IP、端口、狀態(tài)、權重、連接數(shù)你改一行ipvsadm -e -t 10.0.1.100:80 -w 3就能實時調整某臺后端的權重你執(zhí)行echo 1 /proc/sys/net/ipv4/ip_forward和iptables -t nat -A POSTROUTING -s 10.0.0.0/16 -d 10.0.0.0/16 -j MASQUERADE就能精準控制數(shù)據(jù)包走向。這種“裸金屬級”的可見性與可控性是任何封裝過深的托管服務都無法提供的。關鍵詞里雖然沒填但標題本身已鎖定三個核心域Linux 網(wǎng)絡棧深度操作能力、高并發(fā)流量分發(fā)原理、生產級容災架構設計思維。這不是教你怎么配個 demo而是帶你親手拆開一臺“流量調度引擎”的外殼看清每個齒輪怎么咬合。接下來要講的每一步配置背后都對應著一個真實線上故障場景的解法。比如 DR 模式里 VIP 必須綁定在 lo 接口而非 eth0這個看似反直覺的操作就是為了繞過 ARP 廣播風暴——當上百臺 LVS 節(jié)點同時響應同一個 VIP 的 ARP 請求時交換機 MAC 表會瞬間溢出整個二層網(wǎng)絡陷入癱瘓。這些細節(jié)不會出現(xiàn)在云控制臺的文檔里但會決定你能否在凌晨三點把系統(tǒng)拉回來。2. LVS 的三種工作模式到底該選哪一種——別被教科書概念繞暈看真實拓撲再決策市面上講 LVS 模式的文章十有八九一上來就列定義“NAT 模式修改目的IP和端口DR 模式只改 MAC 地址TUN 模式加 IP 隧道頭……”聽起來很酷但沒人告訴你在什么物理網(wǎng)絡條件下哪種模式會直接失效我們直接拿三套真實部署環(huán)境來對照環(huán)境類型典型拓撲NAT 模式是否可行DR 模式是否可行TUN 模式是否可行關鍵限制原因同VLAN內網(wǎng)集群如IDC機柜LVSRS都在10.0.1.0/24網(wǎng)段二層互通? 完全可行? 最優(yōu)選擇?? 可行但冗余DR需RS禁ARP響應TUN需額外隧道開銷跨子網(wǎng)混合云LVS在IDCRS在公有云VPCLVS在10.0.1.0/24RS在172.16.0.0/16路由可達? 可行需SNAT? 不可行? 唯一選擇DR要求LVS與RS二層互通跨子網(wǎng)無法滿足容器化微服務集群K8s NodePort暴露LVS作為Ingress入口后端是Pod IP如10.244.1.5?? 可行但性能差? 不可行Pod無lo綁定VIP能力? 主流方案Pod生命周期短lo綁定VIP不可靠提示很多團隊踩坑是因為照搬“DR性能最好”的結論卻忽略了自己網(wǎng)絡環(huán)境根本不支持。比如某公司把LVS部署在阿里云ECS上后端RS也全是ECS但默認VPC網(wǎng)絡是三層轉發(fā)非二層廣播域強行配DR會導致RS收不到LVS發(fā)來的ARP請求VIP永遠無法響應——因為云廠商的虛擬交換機根本不會轉發(fā)目的MAC為VIP的ARP Reply包。我們以最典型的同VLAN內網(wǎng)集群為例重點展開 DR 模式。它之所以成為生產首選核心在于三點性能天花板最高LVS只改MAC頭不碰IP包內容轉發(fā)延遲穩(wěn)定在微秒級RS真實IP可見后端Web服務器日志里直接記錄客戶端真實IP無需X-Forwarded-For解析擴展性極強LVS節(jié)點可水平擴展RS數(shù)量理論上無上限受限于交換機MAC表容量。但DR的代價也很明確RS必須和LVS在同一物理網(wǎng)段且需手動配置ARP抑制。這個“手動”不是可選項而是生死線。下面這段腳本就是我在某金融客戶現(xiàn)場手敲了三遍才確認無誤的RS初始化命令# 在每臺Real Server上執(zhí)行以CentOS 7為例 # 步驟1綁定VIP到lo接口關鍵不能綁eth0 ip addr add 10.0.1.100/32 dev lo label lo:0 # 步驟2禁用lo接口對VIP的ARP響應防止RS搶答ARP請求 echo net.ipv4.conf.lo.arp_ignore 1 /etc/sysctl.conf echo net.ipv4.conf.lo.arp_announce 2 /etc/sysctl.conf sysctl -p # 步驟3確保eth0接口仍能正常響應自身IP的ARP避免斷網(wǎng) echo net.ipv4.conf.eth0.arp_ignore 0 /etc/sysctl.conf echo net.ipv4.conf.eth0.arp_announce 0 /etc/sysctl.conf這里arp_ignore1的含義是只響應目標IP是本接口主IP的ARP請求arp_announce2則強制使用最佳本地地址即lo:0上的VIP作為ARP Reply的源IP。這兩行配置缺一不可。我曾見過運維同事只配了第一行結果LVS發(fā)ARP請求時RS雖然不響應但交換機會把VIP的MAC映射到某臺RS的eth0物理MAC上導致后續(xù)流量全部被錯誤導向——這就是典型的“半吊子ARP抑制”。3. 從零構建LVS-DR集群四步完成核心鏈路打通現(xiàn)在我們進入實操環(huán)節(jié)。假設你有三臺干凈的 CentOS 7 虛擬機LVS-Master10.0.1.10主調度節(jié)點LVS-Backup10.0.1.11備用節(jié)點Keepalived熱備RS-0110.0.1.20后端服務器1RS-0210.0.1.21后端服務器2VIP 設定為 10.0.1.100對外提供 Web 服務80端口。注意所有操作均在 root 用戶下進行且已關閉 firewalld或放行對應端口。3.1 LVS節(jié)點基礎配置讓內核“睜眼看見”IPVS模塊很多新手卡在第一步執(zhí)行ipvsadm -Ln報錯command not found或Cant initialize ipvs: Protocol not available。前者是沒裝工具后者是內核模塊未加載。先解決根本問題# 檢查IPVS內核模塊是否內置現(xiàn)代Linux內核基本都已集成 lsmod | grep ip_vs # 應輸出類似ip_vs_sh 12688 0, ip_vs_wrr 12697 0, ip_vs_rr 12600 0, ip_vs 145497 6 ip_vs_rr,ip_vs_sh,ip_vs_wrr # 若無輸出手動加載CentOS 7需啟用 modprobe ip_vs modprobe ip_vs_rr modprobe ip_vs_wrr modprobe ip_vs_sh # 永久生效寫入模塊加載列表 echo ip_vs /etc/modules-load.d/ipvs.conf echo ip_vs_rr /etc/modules-load.d/ipvs.conf echo ip_vs_wrr /etc/modules-load.d/ipvs.conf echo ip_vs_sh /etc/modules-load.d/ipvs.conf注意不要嘗試yum install ipvsadm后直接運行必須確認內核模塊已就緒。我曾幫某客戶排查他們裝了ipvsadm但內核沒加載模塊所有命令都返回“Protocol not available”折騰兩天才發(fā)現(xiàn)是/etc/modules-load.d/目錄權限被誤設為700root用戶都讀不了配置文件。3.2 配置LVS調度規(guī)則不只是加一條命令而是理解每項參數(shù)的業(yè)務含義在 LVS-Master 上執(zhí)行# 清空現(xiàn)有規(guī)則首次配置可跳過 ipvsadm -C # 添加虛擬服務VIP:80使用DR模式-g參數(shù)輪詢調度-s rr ipvsadm -A -t 10.0.1.100:80 -s rr # 添加真實服務器注意-g表示DR-w指定權重 ipvsadm -a -t 10.0.1.100:80 -r 10.0.1.20:80 -g -w 1 ipvsadm -a -t 10.0.1.100:80 -r 10.0.1.21:80 -g -w 1 # 查看當前規(guī)則此時應看到兩條ActiveConn為0的連接 ipvsadm -Ln輸出應類似IP Virtual Server version 1.2.1 (size4096) Prot LocalAddress:Port Scheduler Flags - RemoteAddress:Port Forward Weight ActiveConn InActConn TCP 10.0.1.100:80 rr - 10.0.1.20:80 Route 1 0 0 - 10.0.1.21:80 Route 1 0 0這里-g參數(shù)是DR模式的標志它告訴內核轉發(fā)時只替換目標MAC為RS的MAC不修改IP頭。而-w 1的權重值決定了在輪詢rr算法下每臺RS被選中的概率。如果RS-01配置更強16核64G而RS-02較弱4核16G可將權重設為ipvsadm -e -t 10.0.1.100:80 -r 10.0.1.20:80 -g -w 4這樣RS-01將獲得約80%的流量。實操心得權重調整不是拍腦袋。我們通常先用ab -n 10000 -c 100 http://10.0.1.20/和ab -n 10000 -c 100 http://10.0.1.21/分別壓測單臺RS的QPS假設RS-01達850 QPSRS-02僅210 QPS則權重比應設為 850:210 ≈ 4:1。這才是真正基于性能的動態(tài)調度。3.3 驗證數(shù)據(jù)平面連通性繞過HTTP用TCP連接測試最真實很多人驗證LVS是否成功習慣用curl http://10.0.0.100。這其實是個陷阱——如果后端Web服務沒起curl失敗你會以為LVS壞了如果DNS緩存了VIP的舊IPcurl可能根本沒走到LVS。更可靠的方法是直接測試TCP連接# 在任意客戶端機器非LVS/RS執(zhí)行 # 測試VIP:80端口是否可建立TCP連接不發(fā)送HTTP請求 nc -zv 10.0.1.100 80 # 應返回Connection to 10.0.1.100 80 port [tcp/http] succeeded! # 進一步驗證連接建立后立即斷開看LVS是否記錄了ActiveConn # 在LVS-Master上執(zhí)行另開終端 watch -n 1 ipvsadm -Ln | grep :80 # 此時ActiveConn應短暫跳變?yōu)?證明連接已穿透LVS到達RS這個測試的價值在于它剝離了應用層干擾純粹驗證LVS的數(shù)據(jù)轉發(fā)鏈路。我曾用此法快速定位過一個經典問題某次升級后curl總超時但nc卻秒通。最終發(fā)現(xiàn)是后端Nginx配置了keepalive_timeout 0導致HTTP長連接被異常關閉而LVS的連接跟蹤表conntrack默認保留TIME_WAIT狀態(tài)60秒新連接被阻塞——這是典型的“LVS沒問題但應用層配置與LVS機制沖突”的案例。3.4 部署Keepalived實現(xiàn)高可用主備切換不是“自動”而是“可預測”單點LVS是生產大忌。我們用Keepalived實現(xiàn)VIP漂移。在 LVS-Master 和 LVS-Backup 上均安裝yum install -y keepalived systemctl enable keepalived編輯/etc/keepalived/keepalived.confMaster版global_defs { router_id LVS_MASTER } 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.0.1.100/24 dev eth0 label eth0:1 } # 關鍵當本機ipvs規(guī)則異常時主動降權觸發(fā)切換 track_script { chk_lvs } } # 自定義健康檢查腳本 vrrp_script chk_lvs { script /usr/local/bin/check_lvs.sh interval 2 weight -20 }對應的/usr/local/bin/check_lvs.sh腳本#!/bin/bash # 檢查ipvsadm是否能正常列出規(guī)則且至少有一條ActiveConn 0 if ipvsadm -Ln | grep -q ActiveConn ipvsadm -Ln | grep -E :[0-9].*[0-9]$ | awk {sum$5} END{print sum0} | grep -q ^[1-9][0-9]*$; then exit 0 else exit 1 fiBackup節(jié)點配置僅需修改三處state BACKUPpriority 90低于Masterrouter_id LVS_BACKUP關鍵經驗Keepalived的track_script不是擺設。我們曾遇到Master節(jié)點因內核bug導致ipvs連接跟蹤表溢出ip_vs_conn_tab滿此時LVS雖能響應ARP但新連接無法建立。若無此腳本VIP會永遠卡在故障節(jié)點上。而該腳本每2秒檢查一次ActiveConn總數(shù)一旦為0即觸發(fā)降權3秒內完成VIP漂移到Backup節(jié)點——這才是真正的故障自愈。4. 生產級加固與排障那些文檔里不會寫的“血淚教訓”搭建完成只是起點。真正的挑戰(zhàn)在于讓集群在高壓、突變、故障下持續(xù)穩(wěn)定。以下是我在多個項目中沉淀的硬核加固點4.1 連接跟蹤表conntrack溢出LVS的“內存泄漏”式崩潰LVS依賴內核的連接跟蹤模塊nf_conntrack記錄每個連接狀態(tài)。默認值極小# 查看當前設置 sysctl net.netfilter.nf_conntrack_max # CentOS 7 默認僅65536對萬級并發(fā)遠遠不夠 # 臨時調整 sysctl -w net.netfilter.nf_conntrack_max524288 # 永久生效 echo net.netfilter.nf_conntrack_max 524288 /etc/sysctl.conf但光調大還不夠。更致命的是連接跟蹤老化時間timeout設置不合理。默認TCP ESTABLISHED狀態(tài)超時為432000秒5天意味著一個長連接會占用conntrack表項長達5天。在HTTP短連接場景下這會造成大量TIME_WAIT狀態(tài)堆積。解決方案是精細化配置# 縮短TCP ESTABLISHED超時生產建議300-600秒 echo net.netfilter.nf_conntrack_tcp_timeout_established 600 /etc/sysctl.conf # 縮短TIME_WAIT超時默認120秒可降至30秒 echo net.netfilter.nf_conntrack_tcp_timeout_time_wait 30 /etc/sysctl.conf # 啟用連接跟蹤哈希表自動伸縮內核3.12 echo net.netfilter.nf_conntrack_hashsize 65536 /etc/sysctl.conf踩坑實錄某直播平臺上線后LVS節(jié)點在峰值時頻繁丟包dmesg顯示nf_conntrack: table full, dropping packet。排查發(fā)現(xiàn)是主播推流使用RTMP長連接ESTABLISHED超時設為5天65536的表項在2小時內耗盡。調整為600秒后表項峰值穩(wěn)定在12000左右問題徹底解決。4.2 網(wǎng)絡接口隊列txqueuelen瓶頸千兆網(wǎng)卡為何跑不滿即使LVS CPU和內存充足也可能遭遇網(wǎng)卡瓶頸。Linux默認的發(fā)送隊列長度txqueuelen僅為1000# 查看當前值 ip link show eth0 | grep txqueuelen # 輸出... txqueuelen 1000 ... # 臨時增大千兆網(wǎng)卡建議5000-10000 ip link set eth0 txqueuelen 5000 # 永久生效寫入網(wǎng)卡配置 echo ETHTOOL_OPTS\speed 1000 duplex full autoneg off\ /etc/sysconfig/network-scripts/ifcfg-eth0 echo TXQUEUELEN5000 /etc/sysconfig/network-scripts/ifcfg-eth0這個參數(shù)直接影響網(wǎng)卡驅動處理數(shù)據(jù)包的緩沖能力。當LVS每秒需轉發(fā)數(shù)萬包時小隊列會導致內核頻繁觸發(fā)中斷CPU花在上下文切換上的時間遠超實際轉發(fā)時間。增大后CPU軟中斷si占比下降40%吞吐量提升2.3倍。4.3 RS健康檢查的“假死”與“誤殺”如何讓LVS真正懂業(yè)務LVS自帶的TCP端口檢查-t只能確認端口是否開放無法判斷后端服務是否真能處理請求。比如Nginx進程存活但worker進程全部卡死端口仍可連接。我們采用“業(yè)務級探活”在每臺RS上部署輕量HTTP探針# /usr/local/bin/lvs_health.sh #!/bin/bash # 檢查Nginx是否返回200且響應時間500ms if curl -s --max-time 0.5 -o /dev/null -w %{http_code} http://127.0.0.1/healthz | grep -q 200; then exit 0 else exit 1 fi然后在LVS節(jié)點配置Keepalived的real_server段落virtual_server 10.0.1.100 80 { delay_loop 3 lb_algo rr lb_kind DR protocol TCP real_server 10.0.1.20 80 { weight 1 TCP_CHECK { connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } # 新增調用業(yè)務探針 HTTP_GET { url { path /healthz status_code 200 } connect_timeout 3 nb_get_retry 3 delay_before_retry 3 } } }經驗之談delay_before_retry 3這個參數(shù)救過我們多次。某次RS因磁盤IO打滿curl /healthz響應時間波動在2-8秒。若設為1秒重試LVS會在3秒內連續(xù)發(fā)起3次請求進一步加劇IO壓力形成雪崩。設為3秒后給了RS喘息時間故障自動恢復率提升至92%。5. LVS集群的“體檢報告”五項必查指標與閾值紅線上線不是終點日常巡檢才是保障。我給所有維護LVS集群的團隊制定了一套“五分鐘體檢清單”每天早晚各執(zhí)行一次檢查項命令健康閾值異常含義應急操作1. VIP ARP響應arping -c 3 -I eth0 10.0.1.1003個包全部響應LVS節(jié)點未接管VIP或網(wǎng)絡隔離檢查Keepalived狀態(tài)systemctl status keepalived2. 連接跟蹤使用率conntrack -L | wc -lsysctl net.netfilter.nf_conntrack_max使用率 70%conntrack表即將溢出新連接被丟棄立即執(zhí)行conntrack -F清空并檢查超時設置3. RS連接分布均衡度ipvsadm -Ln | awk /-/ {print $6} | sort | uniq -c各RS連接數(shù)標準差 15%調度算法失效或RS性能嚴重不均檢查RS權重執(zhí)行ipvsadm -E -t ... -w動態(tài)調整4. LVS節(jié)點CPU軟中斷sar -I SUM -u 1 3 | tail -1 | awk {print $7}%si 35%網(wǎng)卡中斷處理不過來需調大txqueuelen執(zhí)行ip link set eth0 txqueuelen 100005. RS健康檢查失敗率tail -100 /var/log/messages | grep Real server down過去1小時失敗次數(shù) ≤ 2RS服務不穩(wěn)定或網(wǎng)絡抖動登錄RS執(zhí)行curl -v http://127.0.0.1/healthz這個清單的價值在于它把抽象的“系統(tǒng)健康”轉化為5個可量化、可執(zhí)行、可歸因的具體動作。去年某次大促前我們通過第3項檢查發(fā)現(xiàn)RS-01連接數(shù)是RS-02的3.2倍立即檢查發(fā)現(xiàn)是RS-01的Nginxworker_connections設為1024而RS-02為65536調整后連接分布標準差從42%降至5.3%P99延遲下降68%。最后分享一個個人體會LVS從來不是用來“替代”云負載均衡的而是作為最后一道可控防線。我們在所有云SLB前面再部署一層LVS集群不是為了省成本而是為了在云廠商控制臺失靈、API不可用、甚至整個Region故障時能用最原始的SSH登錄手動修改幾行ipvsadm命令把流量切到災備機房——那種指尖劃過鍵盤、看著ipvsadm -Ln輸出實時變化的掌控感是任何圖形界面都無法給予的踏實。技術演進再快底層網(wǎng)絡的確定性永遠是我們最值得信賴的錨點。