[TOC]html
HAProxy是一個免費的負載均衡軟件,能夠運行於大部分主流的Linux操做系統上。前端
HAProxy提供了L4(TCP)和L7(HTTP)兩種負載均衡能力,具有豐富的功能。HAProxy的社區很是活躍,版本更新快速(最新穩定版1.7.2於2017/01/13推出)。最關鍵的是,HAProxy具有媲美商用負載均衡器的性能和穩定性。linux
由於HAProxy的上述優勢,它當前不只僅是免費負載均衡軟件的首選,更幾乎成爲了惟一選擇。git
性能github
穩定性算法
做爲建議以單進程模式運行的程序,HAProxy對穩定性的要求是十分嚴苛的。按照做者的說法,HAProxy在13年間從未出現過一個會致使其崩潰的BUG,HAProxy一旦成功啓動,除非操做系統或硬件故障,不然就不會崩潰(我以爲可能多少仍是有誇大的成分)。數據庫
在上文中提到過,HAProxy的大部分工做都是在操做系統內核完成的,因此HAProxy的穩定性主要依賴於操做系統,做者建議使用2.6或3.x的Linux內核,對sysctls參數進行精細的優化,而且確保主機有足夠的內存。這樣HAProxy就可以持續滿負載穩定運行數年之久。後端
我的的建議:瀏覽器
net.ipv4.tcp_tw_reuse = 1 net.ipv4.ip_local_port_range = 1024 65023 net.ipv4.tcp_max_syn_backlog = 10240 net.ipv4.tcp_max_tw_buckets = 400000 net.ipv4.tcp_max_orphans = 60000 net.ipv4.tcp_synack_retries = 3 net.core.somaxconn = 10000
下面介紹在CentOS7中安裝和運行HAProxy最新穩定版(1.7.2)的方法緩存
爲HAProxy建立用戶和用戶組,此例中用戶和用戶組都是」ha」。注意,若是想要讓HAProxy監聽1024如下的端口,則須要以root用戶來啓動
下載並解壓
1 wget http://www.haproxy.org/download/1.7/src/haproxy-1.7.2.tar.gz 2 tar -xzf haproxy-1.7.2.tar.gz
1 make PREFIX=/home/ha/haproxy TARGET=linux2628 2 make install PREFIX=/home/ha/haproxy
PREFIX爲指定的安裝路徑,TARGET則根據當前操做系統內核版本指定:
1 - linux22 for Linux 2.2 2 - linux24 for Linux 2.4 and above (default) 3 - linux24e for Linux 2.4 with support for a working epoll (> 0.21) 4 - linux26 for Linux 2.6 and above 5 - linux2628 for Linux 2.6.28, 3.x, and above (enables splice and tproxy)
此例中,咱們的操做系統內核版本爲3.10.0,因此TARGET指定爲linux2628
1 mkdir -p /home/ha/haproxy/conf 2 vi /home/ha/haproxy/conf/haproxy.cfg
咱們先建立一個最簡單配置文件:
global #全局屬性 daemon #以daemon方式在後臺運行 maxconn 256 #最大同時256鏈接 pidfile /home/ha/haproxy/conf/haproxy.pid #指定保存HAProxy進程號的文件 defaults #默認參數 mode http #http模式 timeout connect 5000ms #鏈接server端超時5s timeout client 50000ms #客戶端響應超時50s timeout server 50000ms #server端響應超時50s frontend http-in #前端服務http-in bind *:8080 #監聽8080端口 default_backend servers #請求轉發至名爲"servers"的後端服務 backend servers #後端服務servers server server1 127.0.0.1:8000 maxconn 32 #backend servers中只有一個後端服務,名字叫server1,起在本機的8000端口,HAProxy同時最多向這個服務發起32個鏈接
更加詳細的配置會在後面章節中進行說明 注意:HAProxy要求系統的ulimit -n參數大於[maxconn*2+18],在設置較大的maxconn時,注意檢查並修改ulimit -n參數
在/etc/init.d目錄下添加HAProxy服務的啓停腳本:
vi /etc/init.d/haproxy #! /bin/sh set -e PATH=/sbin:/bin:/usr/sbin:/usr/bin:/home/ha/haproxy/sbin PROGDIR=/home/ha/haproxy PROGNAME=haproxy DAEMON=$PROGDIR/sbin/$PROGNAME CONFIG=$PROGDIR/conf/$PROGNAME.cfg PIDFILE=$PROGDIR/conf/$PROGNAME.pid DESC="HAProxy daemon" SCRIPTNAME=/etc/init.d/$PROGNAME # Gracefully exit if the package has been removed. test -x $DAEMON || exit 0 start() { echo -e "Starting $DESC: $PROGNAME\n" $DAEMON -f $CONFIG echo "." } stop() { echo -e "Stopping $DESC: $PROGNAME\n" haproxy_pid="$(cat $PIDFILE)" kill $haproxy_pid echo "." } restart() { echo -e "Restarting $DESC: $PROGNAME\n" $DAEMON -f $CONFIG -p $PIDFILE -sf $(cat $PIDFILE) echo "." } case "$1" in start) start ;; stop) stop ;; restart) restart ;; *) echo "Usage: $SCRIPTNAME {start|stop|restart}" >&2 exit 1 ;; esac exit 0
啓動、中止和重啓:
service haproxy start service haproxy stop service haproxy restart
HAProxy不會直接輸出文件日誌,因此咱們要藉助Linux的rsyslog來讓HAProxy輸出日誌
在global域和defaults域中添加:
global ... log 127.0.0.1 local0 info log 127.0.0.1 local1 warning ... defaults ... log global ...
意思是將info級(及以上)的日誌推送到rsyslog的local0接口,將warn級(及以上)的日誌推送到rsyslog的local1接口,而且全部frontend都默認使用global中的日誌配置。
注:info級的日誌會打印HAProxy處理的每一條請求,會佔用很大的磁盤空間,在生產環境中,建議將日誌級別調整爲notice
vi /etc/rsyslog.d/haproxy.conf $ModLoad imudp $UDPServerRun 514 $FileCreateMode 0644 #日誌文件的權限 $FileOwner ha #日誌文件的owner local0.* /var/log/haproxy.log #local0接口對應的日誌輸出文件 local1.* /var/log/haproxy_warn.log #local1接口對應的日誌輸出文件
vi /etc/sysconfig/rsyslog # Options for rsyslogd # Syslogd options are deprecated since rsyslog v3. # If you want to use them, switch to compatibility mode 2 by "-c 2" # See rsyslogd(8) for more details SYSLOGD_OPTIONS="-c 2 -r -m 0"
service rsyslog restart service haproxy restart
此時就應該能在/var/log目錄下看到haproxy的日誌文件了
經過rsyslog輸出的日誌是不會進行切分的,因此須要依靠Linux提供的logrotate來進行切分工做
使用root用戶,建立haproxy日誌切分配置文件:
mkdir /root/logrotate vi /root/logrotate/haproxy /var/log/haproxy.log /var/log/haproxy_warn.log { #切分的兩個文件名 daily #按天切分 rotate 7 #保留7份 create 0644 ha ha #建立新文件的權限、用戶、用戶組 compress #壓縮舊日誌 delaycompress #延遲一天壓縮 missingok #忽略文件不存在的錯誤 dateext #舊日誌加上日誌後綴 sharedscripts #切分後的重啓腳本只運行一次 postrotate #切分後運行腳本重載rsyslog,讓rsyslog向新的日誌文件中輸出日誌 /bin/kill -HUP $(/bin/cat /var/run/syslogd.pid 2>/dev/null) &>/dev/null endscript } 並配置在crontab中運行: 0 0 * * * /usr/sbin/logrotate /root/logrotate/haproxy
本節中,咱們將使用HAProxy搭建一個L7負載均衡器,應用以下功能
架構以下:
架構中共有6個後端服務,劃分爲3組,每組中2個服務:
部署6個後端服務,可使用任意的Web服務,如Nginx、Apache HTTPD、Tomcat、Jetty等,具體Web服務的安裝過程省略。
此例中,咱們在192.168.8.111和192.168.8.112兩臺主機上分別安裝了3個Nginx:
ms1.srv1 - 192.168.8.111:8080 ms1.srv2 - 192.168.8.112:8080 ms2.srv1 - 192.168.8.111:8081 ms2.srv2 - 192.168.8.112:8081 def.srv1 - 192.168.8.111:8082 def.srv1 - 192.168.8.111:8082
在這6個Nginx服務分別部署健康檢查頁面healthCheck.html,頁面內容任意。確保經過http://ip:port/healthCheck.html能夠訪問到這個頁面
接下來在6個Nginx服務中部署服務頁面:
在第一組中部署ms1/demo.html 在第二組中部署ms2/demo.html 在第三組中部署def/demo.html
demo.html的內容,以部署在192.168.8.111:8080上的爲例:
Hello! This is ms1.srv1!
部署在192.168.8.112:8080上的就應該是
Hello! This is ms1.srv2!
以此類推
在192.168.8.110主機安裝HAProxy HAProxy的安裝和配置步驟如上一章中描述,此處略去
HAProxy配置文件: global daemon maxconn 30000 #ulimit -n至少爲60018 user ha pidfile /home/ha/haproxy/conf/haproxy.pid log 127.0.0.1 local0 info log 127.0.0.1 local1 warning defaults mode http log global option http-keep-alive #使用keepAlive鏈接 option forwardfor #記錄客戶端IP在X-Forwarded-For頭域中 option httplog #開啓httplog,HAProxy會記錄更豐富的請求信息 timeout connect 5000ms timeout client 10000ms timeout server 50000ms timeout http-request 20000ms #鏈接建立從客戶端讀取完整HTTP請求的超時時間,用於避免類DDOS攻擊 option httpchk GET /healthCheck.html #定義默認的健康檢查策略 frontend http-in bind *:9001 maxconn 30000 #定義此端口上的maxconn acl url_ms1 path_beg -i /ms1/ #定義ACL,當uri以/ms1/開頭時,ACL[url_ms1]爲true acl url_ms2 path_beg -i /ms2/ #同上,url_ms2 use_backend ms1 if url_ms1 #當[url_ms1]爲true時,定向到後端服務羣ms1中 use_backend ms2 if url_ms2 #當[url_ms2]爲true時,定向到後端服務羣ms2中 default_backend default_servers #其餘狀況時,定向到後端服務羣default_servers中 backend ms1 #定義後端服務羣ms1 balance roundrobin #使用RR負載均衡算法 cookie HA_STICKY_ms1 insert indirect nocache #會話保持策略,insert名爲"HA_STICKY_ms1"的cookie #定義後端server[ms1.srv1],請求定向到該server時會在響應中寫入cookie值[ms1.srv1] #針對此server的maxconn設置爲300 #應用默認健康檢查策略,健康檢查間隔和超時時間爲2000ms,兩次成功視爲節點UP,三次失敗視爲節點DOWN server ms1.srv1 192.168.8.111:8080 cookie ms1.srv1 maxconn 300 check inter 2000ms rise 2 fall 3 #同上,inter 2000ms rise 2 fall 3是默認值,能夠省略 server ms1.srv2 192.168.8.112:8080 cookie ms1.srv2 maxconn 300 check backend ms2 #定義後端服務羣ms2 balance roundrobin cookie HA_STICKY_ms2 insert indirect nocache server ms2.srv1 192.168.8.111:8081 cookie ms2.srv1 maxconn 300 check server ms2.srv2 192.168.8.112:8081 cookie ms2.srv2 maxconn 300 check backend default_servers #定義後端服務羣default_servers balance roundrobin cookie HA_STICKY_def insert indirect nocache server def.srv1 192.168.8.111:8082 cookie def.srv1 maxconn 300 check server def.srv2 192.168.8.112:8082 cookie def.srv2 maxconn 300 check listen stats #定義監控頁面 bind *:1080 #綁定端口1080 stats refresh 30s #每30秒更新監控數據 stats uri /stats #訪問監控頁面的uri stats realm HAProxy\ Stats #監控頁面的認證提示 stats auth admin:admin #監控頁面的用戶名和密碼
修改完成後,啓動HAProxy
1 service haproxy start
首先,訪問一下監控頁面http://192.168.8.110:1080/stats 並按提示輸入用戶名密碼
接下來就能看到監控頁面:
監控頁面中列出了咱們配置的全部frontend和backend服務,以及它們的詳細指標。如鏈接數,隊列狀況,session rate,流量,後端服務的健康狀態等等
接下來,咱們一一測試在HAProxy中配置的功能
從監控頁面中就能夠直接看出健康檢查配置的是否正確,上圖中能夠看到,backend ms一、ms二、default_servers下屬的6個後端服務的Status都是20h28m UP,表明健康狀態已持續了20小時28分鐘,而LastChk顯示L7OK/200 in 1ms則表明在1ms前進行了L7的健康檢查(即HTTP請求方式的健康檢查),返回碼爲200
此時咱們將ms1.srv1中的healthCheck.html更名
mv healthCheck.html healthCheck.html.bak
而後再去看監控頁面: ms1.srv1的狀態變成了2s DOWN,LastChk則是L7STS/404 in 2ms,表明上次健康檢查返回了404 再恢復healthCheck.html,很快就能看到ms1.srv1從新恢復到UP狀態。
訪問http://192.168.8.110:9001/ms1/demo.html : 能夠看到成功定向到了ms1.srv1上
訪問http://192.168.8.110:9001/ms2/demo.html :
訪問http://192.168.8.110:9001/def/demo.html :
3) 負載均衡和會話保持策略
在分別訪問過ms1/demo.html, ms2/demo.html, m3/demo.html後,查看一下瀏覽器的Cookie:
能夠看到HAProxy已經回寫了三個用於會話保持的cookie,此時反覆刷新這三個頁面,會發現老是被定向到*.srv1上
接下來咱們刪除HA_STICKY_ms1這條cookie,而後再訪問ms1/demo.html,會看到:
同時也被新寫入了一條Cookie:
若是發現仍然被定位到ms1.srv1,同時也沒有寫入新的HA_STICKY_ms1 Cookie,那麼多是瀏覽器緩存了ms1/demo.html頁面,請求並無到達HAProxy。F5刷新一下應該就能夠了。
HAProxy做爲L4負載均衡器工做時,不會去解析任何與HTTP協議相關的內容,只在傳輸層對數據包進行處理。也就是說,以L4模式運行的HAProxy,沒法實現根據URL向不一樣後端轉發、經過cookie實現會話保持等功能。
同時,在L4模式下工做的HAProxy也沒法提供監控頁面。
但做爲L4負載均衡器的HAProxy可以提供更高的性能,適合於基於套接字的服務(如數據庫、消息隊列、RPC、郵件服務、Redis等),或不須要邏輯規則判斷,並已實現了會話共享的HTTP服務。
本例中,咱們使用HAProxy以L4方式來代理兩個HTTP服務,不提供會話保持。
global daemon maxconn 30000 #ulimit -n至少爲60018 user ha pidfile /home/ha/haproxy/conf/haproxy.pid log 127.0.0.1 local0 info log 127.0.0.1 local1 warning defaults mode tcp log global option tcplog #開啓tcplog timeout connect 5000ms timeout client 10000ms timeout server 10000ms #TCP模式下,應將timeout client和timeout server設置爲同樣的,以防止出現問題 option httpchk GET /healthCheck.html #定義默認的健康檢查策略 frontend http-in bind *:9002 maxconn 30000 #定義此端口上的maxconn default_backend default_servers #請求定向至後端服務羣default_servers backend default_servers #定義後端服務羣default_servers balance roundrobin server def.srv1 192.168.8.111:8082 maxconn 300 check server def.srv2 192.168.8.112:8082 maxconn 300 check
雖然TCP模式下的HAProxy沒法經過HTTP Cookie實現會話保持,但能夠很方便的實現基於客戶端IP的會話保持。只需將
balance roundrobin
改成
balance source
此外,HAProxy提供了強大的stick-table功能,HAProxy能夠從傳輸層的數據包中採樣出大量的屬性,並將這些屬性做爲會話保持的策略寫入stick-table中。 本文中不對stick-table進行深刻探討,如須要了解,可參考官方文檔configuration.html#4-stick-table
HAProxy的配置文件共有5個域
acl:同frontend域
balance [algorithm]:在此backend下全部server間的負載均衡算法,經常使用的有roundrobin和source,完整的算法說明見官方文檔configuration.html#4.2-balance
cookie:在backend server間啓用基於cookie的會話保持策略,最經常使用的是insert方式,如cookie HA_STICKY_ms1 insert indirect nocache,指HAProxy將在響應中插入名爲HA_STICKY_ms1的cookie,其值爲對應的server定義中指定的值,並根據請求中此cookie的值決定轉發至哪一個server。indirect表明若是請求中已經帶有合法的HA_STICK_ms1 cookie,則HAProxy不會在響應中再次插入此cookie,nocache則表明禁止鏈路上的全部網關和緩存服務器緩存帶有Set-Cookie頭的響應。
default-server:用於指定此backend下全部server的默認設置。具體見下面的server配置。
disabled:禁用此backend
http-request/http-response:同frontend域
log:同frontend域
mode:同frontend域
option forwardfor:同frontend域
option http-keep-alive:同frontend域
option httpclose:同frontend域
option httpchk [METHOD] [URL] [VERSION]:定義以http方式進行的健康檢查策略。如option httpchk GET /healthCheck.html HTTP/1.1
option httplog:同frontend域
option tcplog:同frontend域
server [name] [ip]:[port] [params]:定義backend中的一個後端server,[params]用於指定這個server的參數,經常使用的包括有:
check:指定此參數時,HAProxy將會對此server執行健康檢查,檢查方法在option httpchk中配置。同時還能夠在check後指定inter, rise, fall三個參數,分別表明健康檢查的週期、連續幾回成功認爲server UP,連續幾回失敗認爲server DOWN,默認值是inter 2000ms rise 2 fall 3 cookie [value]:用於配合基於cookie的會話保持,如cookie ms1.srv1表明交由此server處理的請求會在響應中寫入值爲ms1.srv1的cookie(具體的cookie名則在backend域中的cookie設置中指定) maxconn:指HAProxy最多同時向此server發起的鏈接數,當鏈接數到達maxconn後,向此server發起的新鏈接會進入等待隊列。默認爲0,即無限 maxqueue:等待隊列的長度,當隊列已滿後,後續請求將會發至此backend下的其餘server,默認爲0,即無限 weight:server的權重,0-256,權重越大,分給這個server的請求就越多。weight爲0的server將不會被分配任何新的鏈接。全部server默認weight爲1
timeout connect [time]:指HAProxy嘗試與backend server建立鏈接的超時時間
timeout check [time]:默認狀況下,健康檢查的鏈接+響應超時時間爲server命令中指定的inter值,若是配置了timeout check,HAProxy會以inter做爲健康檢查請求的鏈接超時時間,並以timeout check的值做爲健康檢查請求的響應超時時間
timeout server [time]:指backend server響應HAProxy請求的超時時間
上文所屬的frontend和backend域關鍵配置中,除acl、bind、http-request、http-response、use_backend外,其他的都可以配置在default域中。default域中配置了的項目,若是在frontend或backend域中沒有配置,將會使用default域中的配置。
listen域是frontend域和backend域的組合,frontend域和backend域中全部的配置均可以配置在listen域下
HAProxy的配置項很是多,支持很是豐富的功能,上文只列出了做爲L7負載均衡器使用HAProxy時的一些關鍵參數。完整的參數說明請參見官方文檔 configuration.html
儘管HAProxy很是穩定,但仍然沒法規避操做系統故障、主機硬件故障、網絡故障甚至斷電帶來的風險。因此必須對HAProxy實施高可用方案。
下文將介紹利用Keepalived實現的HAProxy熱備方案。即兩臺主機上的兩個HAProxy實例同時在線,其中權重較高的實例爲MASTER,MASTER出現問題時,另外一臺實例自動接管全部流量。
在兩臺HAProxy的主機上分別運行着一個Keepalived實例,這兩個Keepalived爭搶同一個虛IP地址,兩個HAProxy也嘗試去綁定這同一個虛IP地址上的端口。 顯然,同時只能有一個Keepalived搶到這個虛IP,搶到了這個虛IP的Keepalived主機上的HAProxy即是當前的MASTER。 Keepalived內部維護一個權重值,權重值最高的Keepalived實例可以搶到虛IP。同時Keepalived會按期check本主機上的HAProxy狀態,狀態OK時權重值增長。
在兩臺物理機上安裝並配置HAProxy,本例中,將在192.168.8.110和192.168.8.111兩臺主機上上安裝兩套徹底同樣的HAProxy,具體步驟省略,請參考「使用HAProxy搭建L7負載均衡器」一節。
下載,解壓,編譯,安裝:
wget http://www.keepalived.org/software/keepalived-1.2.19.tar.gz tar -xzf keepalived-1.2.19.tar.gz ./configure --prefix=/usr/local/keepalived make make install
註冊爲系統服務:
cp /usr/local/keepalived/sbin/keepalived /usr/sbin/ cp /usr/local/keepalived/etc/sysconfig/keepalived /etc/sysconfig/ cp /usr/local/keepalived/etc/rc.d/init.d/keepalived /etc/init.d/ chmod +x /etc/init.d/keepalived
注意:Keepalived須要使用root用戶進行安裝和配置
建立並編輯配置文件
mkdir -p /etc/keepalived/ cp /usr/local/keepalived/etc/keepalived/keepalived.conf /etc/keepalived/ vi /etc/keepalived/keepalived.conf
配置文件內容:
global_defs { router_id LVS_DEVEL #虛擬路由名稱 } #HAProxy健康檢查配置 vrrp_script chk_haproxy { script "killall -0 haproxy" #使用killall -0檢查haproxy實例是否存在,性能高於ps命令 interval 2 #腳本運行週期 weight 2 #每次檢查的加權權重值 } #虛擬路由配置 vrrp_instance VI_1 { state MASTER #本機實例狀態,MASTER/BACKUP,備機配置文件中請寫BACKUP interface enp0s25 #本機網卡名稱,使用ifconfig命令查看 virtual_router_id 51 #虛擬路由編號,主備機保持一致 priority 101 #本機初始權重,備機請填寫小於主機的值(例如100) advert_int 1 #爭搶虛地址的週期,秒 virtual_ipaddress { 192.168.8.201 #虛地址IP,主備機保持一致 } track_script { chk_haproxy #對應的健康檢查配置 } }
若是主機沒有killall命令,則須要安裝psmisc包:
yum intall psmisc
service keepalived start
啓動後,先分別在兩臺主機查看虛IP 192.168.8.201由誰持有,執行命令:
ip addr sh enp0s25 (將enp0s25替換成主機的網卡名)
持有虛IP的主機輸出會是這樣的:
另外一臺主機輸出則是這樣的:
若是你先啓動備機的Keepalived,那麼頗有可能虛IP會被備機搶到,由於備機的權重配置只比主機低1,只要執行一次健康檢查就能把權重提升到102,高於主機的101。
此時訪問http://192.168.8.201:9001/ms1/demo.html ,能夠看到咱們先前部署的網頁。
此時,檢查/var/log/haproxy.log,能看到此請求落在了搶到了虛IP的主機上。
接下來,咱們停掉當前MASTER主機的HAProxy實例(或者Keepalive實例,效果同樣)
service haproxy stop
再次訪問http://192.168.8.201:9001/ms1/demo.html ,並查看備機的/var/log/haproxy.log,會看到此請求落在了備機上,主備自動切換成功。
也能夠再次執行ip addr sh enp0s25命令,會看到虛IP被備機搶去了。
在/var/log/message中,也可以看到keepalived輸出的切換日誌: