HAProxy簡介javascript
HAProxy是免費、極速且可靠的用於爲TCP和基於HTTP應用程序提供高可用、負載均衡和代理服務的解決方案,尤爲適用於高負載且須要持久鏈接或7層處理機制的web站點。HAProxy還能夠將後端的服務器與網絡隔離,起到保護後端服務器的做用。HAProxy的負載均衡能力雖不如LVS,但也是至關不錯,並且因爲其工做在7層,能夠對http請求報文作深刻分析,按照本身的須要將報文轉發至後端不一樣的服務器(例如動靜分離),這一點工做在4層的LVS沒法完成。php
安裝配置HAproxycss
HAProxy已經集成在base源中,可直接經過yum下載。
html
[root@node1 ~]# yum install haproxy
固然也能夠去官網直接下載源碼編譯安裝。前端
/etc/haproxy/haproxy.cfg爲haproxy的主配置文件,裏面包括全局配置段(global settings)和代理配置段(proxies)。
java
global settings:主要用於定義haproxy進程管理安全及性能相關的參數node
proxies:代理相關的配置能夠有以下幾個配置端組成。nginx
- defaults <name>:爲其它配置段提供默認參數,默認配置參數可由下一個「defaults」從新設定。git
- frontend <name>:定義一系列監聽的套接字,這些套接字可接受客戶端請求並與之創建鏈接。github
- backend <name>:定義「後端」服務器,前端代理服務器將會把客戶端的請求調度至這些服務器。
- listen <name>:定義監聽的套接字和後端的服務器。相似於將frontend和backend段放在一塊兒
HAproxy的工做模式:
HAProxy的工做模式通常有兩種:tcp模式和http模式。
tcp模式:實例運行於TCP模式,在客戶端和服務器端之間將創建一個全雙工的鏈接,且不會對7層報文作任何類型的檢查,只能以簡單模式工做。此爲默認模式,一般用於SSL、SSH、SMTP等應用。
http模式:實例運行於HTTP模式,客戶端請求在轉發至後端服務器以前將被深度分析,全部不與RFC格式兼容的請求都會被拒絕。
當實現內容交換時,前端和後端必須工做於同一種模式(通常都是HTTP模式),不然將沒法啓動實例。工做模式可經過mode參數在default,frontend,listen,backend中實現定義。
mode {tcp|http}
下面介紹一些HAproxy的常見用法。
應用實例
基於HAProxy實現負載均衡
在backend段或listen段中經過server定義後端節點。
格式:server <name> <address>[:port] [param*]
<name>:爲此服務器指定的內部名稱
[param*]:爲此服務器設定的一系參數。其可用的參數不少,如下爲經常使用參數。
服務器參數:
backup:設定爲備用服務器,僅在負載均衡場景中的其它server均不可用於啓用此server;
maxconn <maxconn>:指定此服務器接受的最大併發鏈接數;若是發往此服務器的鏈接數目高於此處指定的值,其將被放置於請求隊列,以等待其它鏈接被釋放;
maxqueue <maxqueue>:設定請求隊列的最大長度;
observe <mode>:經過觀察服務器的通訊情況來斷定其健康狀態,默認爲禁用,其支持的類型有「layer4」和「layer7」,「layer7」僅能用於http代理場景;
redir <prefix>:啓用重定向功能,將發往此服務器的GET和HEAD請求均以302狀態碼響應;
weight <weight>:服務器權重,默認爲1,最大值爲256,0表示不參與負載均衡;
定義負載均衡的算法,算法的定義除了listen段和backend段中也能夠放在defaults段中,定義格式以下:
balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post [<max_wait>]]
常見的調度算法有:
roundrobin:基於權重進行輪詢,此算法是動態的,其權重能夠在運行時進行調整。
static-rr:基於權重進行輪詢,與roundrobin相似,可是爲靜態方法,在運行時調整其服務器權重不會生效。
leastconn:新的鏈接請求被派發至具備最少鏈接數目的後端服務器,動態算法,適用於較長時間會話的場景。
source:將請求的源地址進行hash運算,並與後端服務器的總權重做取模運算後調度至某臺服務器;同一IP地址的請求將始終被調度至某特定的服務器,靜態算法,可使用hash-type修改此特性;
uri:對URI的左半部分(「?」以前的部分)或整個URI進行hash運算,並與後端服務器的總權重做取模運算後調度至某臺服務器;同一URI的請求將始終被調度至某特定的服務器,靜態算法,可使用hash-type修改此特性;
hdr(<name>):根據用戶請求報文中指定的http首部的值進行調度,經常使用於實現將對同一個虛擬主機的請求始終發往同個backend server。
前端代理服務器上配置示例(其他爲默認配置):
#--------------------------------------------------------------------- # main frontend which proxys to the backends #--------------------------------------------------------------------- frontend service *:80 default_backend app #--------------------------------------------------------------------- # static backend for serving up p_w_picpaths, stylesheets and such #--------------------------------------------------------------------- backend app balance roundrobin server app1 192.168.2.7:80 maxconn 3000 weight 2 server app2 192.168.2.18:80 maxconn 3000 weight 1 server app3 127.0.0.1:8080 backup
在app1(192.168.2.7)上配置測試頁面:
[root@node1 ~]# vim /web/index.html <h2>server node1</h2>
在app1(192.168.2.18)上:
[root@node2 ~]# vim /web/index.html <h2>server node2</h2>
在代理服務器上有兩個接口:192.168.1.116(面向客戶端),192.168.2.11。配置完成後啓動haproxy服務。後端節點上啓動nginx服務。
已實現輪詢訪問。
在上述的算法中涉及到hash運算,hash-type參數可定義hash的運算方式。格式以下:
格式:hash-type <map-based|consistent>
map-based:靜態方法,在線調整服務器權重不能當即生效。hash表是一個包含了全部在線服務器的靜態數組。簡而言之,經過這種運算方式將請求調度至後端的某臺服務器,當後端的服務器放生變更時(如某臺服務器宕機或新添加了一臺服務器),大部分的鏈接將會被從新調度至一個與以前不一樣的服務器上。
consistent:動態發放,支持在線調整服務器權重。hash表是一個由各服務器填充而成的樹狀結構,使用此算法調度,當後端的服務器發生變更時,大分佈的鏈接將依舊被調度至本來的服務器上。
默認方式爲map-based,可應用於大部分場景。可是若後端的服務器爲緩存服務器,使用默認方式,當後端的服務器調整時,將致使緩存沒法命中,從而影響系統的性能。推薦的配置方式:
backend <name> balance uri hash-type consistent server .... server ...
對後端服務器健康情況的檢測
check爲server的參數,可啓動對此server執行健康狀態的檢測。check藉助其額外的參數可實現更精細的監測機制。
inter <delay>:健康狀態檢測的時間間隔,單位爲毫秒,默認爲2000,可使用fastinter和downinter來根據服務器端狀態優化此時間延遲;
rise <count>:健康狀態檢測中,某離線的server從離線狀態轉換至正常狀態須要成功檢查的次數;
fall <count>:確認server從正常狀態轉換爲不可用狀態須要檢查的次數;
配置示例:
backend app balance roundrobin server app1 192.168.2.7:80 maxconn 3000 weight 2 check inter 1 rise 1 fall 2 server app2 192.168.2.18:80 maxconn 3000 weight 1 check inter 1 rise 1 fall 2 server app3 127.0.0.1:8080 backup
state頁面
啓用統計報告,經過state頁面可查看到各服務器的狀態及其相關信息。關於state的配置建議單獨定義一個listen。
listen stats mode http bind 192.168.1.116:1080 #監聽端口 stats enable #啓用state功能 stats scope app #統計報告的報告區段,不啓動這項則報告全部區段 stats hide-version #隱藏HAProxy版本號 stats uri /haproxyadmin?stats #state頁面的訪問路徑 stats realm Haproxy\ Statistics #認證時提示信息 stats auth baby:baby #認證的帳號密碼 stats admin if TRUE #啓用管理功能
配置完成後重啓haproxy服務。而後訪問定義的路徑:http://192.168.1.116:1080/haproxyadmin?stats。首先完成認證。
基於前面配置完成的健康狀態檢測,如今中止其中一臺後端服務器的nginx服務。
[root@node1 web]# service nginx stop Stopping nginx: [ OK ]
紅色表示服務不在線,若中止全部後端服務器的服務,則會訪問定義爲backup的server(127.0.0.1上的sorry頁面)。
基於cookie的session綁定
在響應報文中添加cookie信息,下一次的客戶請求會帶上這個cookie信息,服務器端根據cookie將請求始終定向至後端的某一臺服務器。可用於保持session會話。
cookie配置格式:
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ][ postonly ] [ preserve ] [ httponly ] [ secure ][ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
配置示例:
backend app balance roundrobin cookie babyserver insert nocache indirect server app1 192.168.2.17:80 check port 80 cookie app1 server app2 192.168.2.16:80 check port 80 cookie app2
重啓服務,客戶端進行訪問。
客戶端查看響應報文:
Set-Cookie首部已經添加信息,接下來該客戶端的訪問(只要cookie信息還在)將始終被定向至app2。
option forwardfor
客戶端的請求經前端的代理服務器轉發至後端的web服務器,代理服務器在轉發時將目標地址改成後端的某臺web服務器地址,將源地址由client ip(客戶端地址)改成本身面向後端服務器的地址。後端的web服務器若使用默認格式記錄日誌,則記錄的客戶端IP地址都爲前端的代理服務器地址。這時須要在發日後端的請求報文中添加內容爲客戶端IP地址的首部,以便後端的web服務器可以正確獲取客戶端地址。
使用option forwardfor 在發往服務器的請求首部中插入「X-Forwarded-For」首部。
格式:option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
<network>:源地址被該參數匹配到時,禁用此功能;
<name>:可自定義首部名稱代替「X-Forwarded-For」;
if-none:僅在此首部不存在時才容許添加至請求報文中。
backend app ....... option forwardfor header X-Client
在後端的web服務器上修改日誌格式。
這裏後端的web服務器爲nginx,若爲httpd,%{headname}i獲取指定首部信息。從新加載配置文件後,便可獲取客戶端IP。須要注意的是,HAProxy工做於隧道模式,其僅檢查每個鏈接的第一個請求,所以,僅第一個請求報文被附加此首部。若是想爲每個請求都附加此首部,須要確保同時使用了「option httpclose」、「option forceclose」和「option http-server-close」幾個option。
ACL簡介
haproxy的ACL可以經過檢測請求報文的首部、響應報文的內容或其餘的環境狀態信息做出轉發決策,加強了其配置彈性。配置分兩步驟:首先定義ACL,即定義一個測試條件,再定義動做,即知足測試條件的狀況下執行的某特定動做。
定義格式:acl <aclname> <criterion> [flags] [operator] <value> ...
<aclname>:ACL名稱。
<criterion>:測試標準,即對什麼信息發起測試。
[flags]:目前haproxy的acl支持的標誌位有3個:
-i:不區分<value>中模式字符的大小寫;
-f:從指定的文件中加載模式;
--:標誌符的強制結束標記;
<value>:acl測試的值。
常見的測試標準(criterion)有be_sess_rate,fe_sess_rate,hdr <string>,method <string>,path_beg <string>,path_end <string>,hdr_beg <string>,hdr_end <string>.....具體的用法能夠查閱相關文檔。
基於ACL實現動靜分離
實驗環境:
haproxy2做爲高可用集羣的備用節點。
前端代理服務器收到的請求經過分析其uri,將靜態內容調度至static server1和2,將動態內容調度至dynamic server1和2。
1)首先haproxy1和haproxy2實現時間同步
2)在haproxy1和haproxy2安裝keepalived和haproxy。
3)編輯配置文件
配置haproxy,配置完成後將配置文件同步至haproxy2節點(關於每一個參數的解釋,可參考http://cbonte.github.io/haproxy-dconv/):
[root@node1 haproxy]# vim haproxy.cfg #--------------------------------------------------------------------- # Global settings #--------------------------------------------------------------------- global log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 4000 #最大併發鏈接數 user haproxy #運行haproxy的用戶 group haproxy #運行haproxy的組 daemon #後臺運行 # turn on stats unix socket stats socket /var/lib/haproxy/stats #--------------------------------------------------------------------- # common defaults that all the 'listen' and 'backend' sections will # use if not designated in their block #--------------------------------------------------------------------- defaults mode http #工做模式 log global #使用全局日誌 option httplog option dontlognull option http-server-close #容許客戶端關閉鏈接 option forwardfor except 127.0.0.0/8 option redispatch #某上游服務器故障,從新將發往該服務器的請求發往其餘的server。 retries 3 #請求重試次數 timeout http-request 10s timeout queue 1m timeout connect 10s timeout client 1m timeout server 1m timeout http-keep-alive 10s timeout check 10s maxconn 3000 ?#--------------------------------------------------------------------- # main frontend which proxys to the backends #--------------------------------------------------------------------- frontend service 192.168.1.200:80 option httpclose #容許服務器端被動關閉鏈接 option logasap capture request header Host len 20 capture request header Referer len 60 #定義ACL,如下兩個ACL是獲取靜態請求 acl url_static path_beg -i /static /p_w_picpaths /javascript /stylesheets acl url_static path_end -i .jpg .gif .png .css .js use_backend static if url_static #將靜態請求定向至static default_backend app #非靜態請求定向至app option forwardfor header X-Client #添加內容爲客戶端IP的首部 #--------------------------------------------------------------------- # static backend for serving up p_w_picpaths, stylesheets and such #--------------------------------------------------------------------- backend static balance roundrobin server first 192.168.2.7:80 check port 80 maxconn 3000 server second 192.168.2.18:80 check port 80 maxconn 3000 #--------------------------------------------------------------------- # round robin balancing between the various backends #--------------------------------------------------------------------- backend app balance roundrobin option forwardfor header X-Client server app1 192.168.2.17:80 check port 80 maxconn 3000 server app2 192.168.2.16:80 check port 80 maxconn 3000 server app3 127.0.0.1:8080 backup
配置keepalived:
haproxy1上:
[root@node1 ~]# 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 1234 } virtual_ipaddress { 192.168.1.200 } notify_master "/etc/init.d/haproxy start" #提高爲主節點時,啓動haproxy服務 notify_backup "/etc/init.d/haproxy stop" #降級爲備節點時,關閉haproxy服務 notify_fault "/etc/init.d/haproxy stop" #運行出錯時,關閉haproxy服務 }
haproxy2上(省略部分與haproxy1上一致):
vrrp_instance VI_1 { state BACKUP #備用節點 ...... priority 99 #服務器優先級 ....... }
配置完成後在啓動各節點上的服務:
[root@www ~]# ansible haproxy -m shell -a 'service haproxy start' [root@www ~]# ansible haproxy -m shell -a 'service keepalived start' [root@www ~]# ansible webstatic -m shell -a 'service nginx start' [root@www ~]# ansible webdynamic -m shell -a 'service httpd start'
能夠看到主節點上的虛擬IP已啓用。在各個web節點上準備測試頁面。
dynamic server1和server2上:
####server1##### [root@node1 ~]# vim /var/www/html/index.php <h1>dynamic server1</h1> <?php phpinfo(); ?> ####server2##### [root@node2 ~]# vim /var/www/html/index.php <h1>dynamic server2</h1> <?php phpinfo(); ?>
static server1和server2上:
####server1##### [root@node1 web]# vim p_w_picpaths/abc.html <h1>static node1</h1> ####server2##### [root@node2 web]# vim p_w_picpaths/abc.html <h1>static node2</h1>
進行訪問測試:
訪問靜態內容:
訪問動態內容:
這裏已經對單節點haproxy作了高可用,當主節點故障時,服務可以自動切換至備節點而不中斷訪問。完成部署!.................^_^