1、Haproxy簡介javascript
HAproxy 是一款高性能的TCP和HTTP負載均衡器。其功能是用來提供基於cookie的持久性,基於內容的交換,過載保護的高級流量管制,自動故障切換,以正則表達式爲基礎的標題控制運行時間,基於Web的報表,高級日誌記錄以幫助排除故障的應用或網絡,以及其餘一些功能。HAProxy運行在當前的硬件上,事件驅動的狀態機達到每秒20000點擊和超過億單元以太網,甚至支持數以萬計的同步鏈接。php
HAProxy是法國人Willy Tarreau我的開發的一個開源軟件,目標是應對客戶端10000以上的同時鏈接,爲後端應用服務器、數據庫服務器提供高性能的負載均衡服務。在底層數據結構方面,舊版本HAProxy曾經使用過紅黑樹,用於任務調度、負載均衡等方面。可是Willy Tarreau認爲,在事件響應很是頻繁的狀況下,任務插入、刪除的頻率很是高,這時候使用紅黑樹存在性能瓶頸,尤爲不能接受紅黑樹刪除節點的時間複雜度爲O(log n)。所以,他發明了一種新的數據結構,叫作彈性二叉樹(elastic binary tree),簡稱ebtree。css
目前新版本的HAProxy已使用ebtree,而除了HAProxy以外,尚未其它著名的開源軟件使用ebtree。能夠這麼說,HAProxy最有特點的地方就是ebtree,ebtree名符實際上是HAProxy的獨門武器。html
2、Haproxy的特性前端
HAProxy是免費、極速且可靠的用於爲TCP和基於HTTP應用程序提供高可用、負載均衡和代理服務的解決方案,尤爲適用於高負載且須要持久鏈接或7層處理機制的web站點。java
客戶端側的長鏈接(client-side keep-alive)web
TCP加速(TCP speedups)正則表達式
響應池(response buffering)算法
基於源的粘性(source-based stickiness)數據庫
更好的統計數據接口(a much better stats interfaces)
更詳細的健康狀態檢測機制(more verbose health checks)
基於流量的健康評估機制(traffic-based health)
基於ACL的持久性(ACL-based persistence)
ACL:編寫內容交換規則;
負載均衡算法(load-balancing algorithms):更多的算法支持;
分層設計(layered design):分別實現套接字、TCP、HTTP處理以提供更好的健壯性、更快的處理機制及便捷的演進能力;
快速、公平調度器(fast and fair scheduler):爲某些任務指定優先級可實現理好的QoS;
會話速率限制(session rate limiting):適用於託管環境;
3、Haproxy的性能
HAProxy藉助於OS上幾種常見的技術來實現性能的最大化。
單進程、事件驅動模型顯著下降了上下文切換的開銷及內存佔用。
O(1)事件檢查器(event checker)容許其在高併發鏈接中對任何鏈接的任何事件實現即時探測。
在任何可用的狀況下,單緩衝(single buffering)機制能以不復制任何數據的方式完成讀寫操做,這會節約大量的CPU時鐘週期及內存帶寬;
藉助於Linux 2.6 (>= 2.6.27.19)上的splice()系統調用,HAProxy能夠實現零複製轉發(Zero-copy forwarding),在Linux 3.5及以上的OS中還能夠實現零複製啓動(zero-starting);
MRU內存分配器在固定大小的內存池中可實現即時內存分配,這可以顯著減小建立一個會話的時長;
樹型存儲:側重於使用做者多年前開發的彈性二叉樹,實現了以O(log(N))的低開銷來保持計時器命令、保持運行隊列命令及管理輪詢及最少鏈接隊列;
優化的HTTP首部分析:優化的首部分析功能避免了在HTTP首部分析過程當中重讀任何內存區域;
精心地下降了昂貴的系統調用,大部分工做都在用戶空間完成,如時間讀取、緩衝聚合及文件描述符的啓用和禁用等;
全部的這些細微之處的優化實現了在中等規模負載之上依然有着至關低的CPU負載,甚至於在很是高的負載場景中,5%的用戶空間佔用率和95%的系統空間佔用率也是很是廣泛的現象,這意味着HAProxy進程消耗比系統空間消耗低20倍以上。所以,對OS進行性能調優是很是重要的。即便用戶空間的佔用率提升一倍,其CPU佔用率也僅爲10%,這也解釋了爲什麼7層處理對性能影響有限這一現象。由此,在高端系統上HAProxy的7層性能可輕易超過硬件負載均衡設備。
在生產環境中,在7層處理上使用HAProxy做爲昂貴的高端硬件負載均衡設備故障故障時的緊急解決方案也時長可見。硬件負載均衡設備在「報文」級別處理請求,這在支持跨報文請求(request across multiple packets)有着較高的難度,而且它們不緩衝任何數據,所以有着較長的響應時間。對應地,軟件負載均衡設備使用TCP緩衝,可創建極長的請求,且有着較大的響應時間
4、Haproxy基本實現
haproxy的安裝,這裏演示的爲centos 7,經過yum光盤鏡像安裝
[root@localhost ~]# yum install haproxy [root@localhost ~]# rpm -ql haproxy /etc/haproxy/haproxy.cfg #主配置文件 /etc/logrotate.d/haproxy #日誌回滾 /usr/lib/systemd/system/haproxy.service #服務管理單元 /usr/sbin/haproxy #haproxy主程序
這裏先實現一個最基本的基於輪詢負載負載均衡,先簡單簡單配置兩個httpd服務器
[root@wlw1 ~]# echo 'My web1 192.168.0.45' > /var/www/html/index.html [root@wlw2 ~]# echo 'My web2 192.168.0.66' > /var/www/html/index.html
haproxy服務器配置以下,
vim /etc/haproxy/haproxy.cfg frontend main *:80 default_backend webserver backend webserver balance roundrobin server web.ip45 192.168.0.45:80 check server web.ip66 192.168.0.66:80 check
實驗結果,能夠看到實現了輪詢效果
[root@localhost ~]# curl http://192.168.0.56 My web1 192.168.0.45 [root@localhost ~]# curl http://192.168.0.56 My web2 192.168.0.66 [root@localhost ~]# curl http://192.168.0.56 My web1 192.168.0.45 [root@localhost ~]# curl http://192.168.0.56 My web2 192.168.0.66
5、Haproxy常見全局global配置選項及其用法
①、log:經過logserver記錄日誌,定義全局的syslog服務器,最多能夠定義兩個
vim /etc/haproxy/haproxy.cfg global log 127.0.0.1 local2 [root@localhost ~]# vim /etc/rsyslog.conf $ModLoad imudp #開啓syslog監聽服務 $UDPServerRun 514 local2.* /var/log/haproxy.log
配置好全局日誌後經過查看訪問日誌查詢是否成功生效
[root@localhost ~]# tail /var/log/haproxy.log Oct 24 06:25:51 localhost haproxy[1626]: 192.168.0.56:39072 [24/Oct/2015:06:25:51.817] main webserver/web.ip45 4/0/4/8/16 200 289 - - ---- 1/1/0/0/0 0/0 "GET / HTTP/1.1" Oct 24 06:25:52 localhost haproxy[1626]: 192.168.0.56:39075 [24/Oct/2015:06:25:52.687] main webserver/web.ip66 0/0/1/8/9 200 289 - - ---- 1/1/0/1/0 0/0 "GET / HTTP/1.1" #上面信息,192.168.0.56發送的請求,由main前端響應,這裏對應咱們配置文件中frontend配置的名字,發送給webserver/web.ip45後端服務器的web.ip45web服務器處理。
②、log-send-hostname <string>:在syslog信息的首部添加當前主機名,能夠爲「string」指定的名稱,也能夠缺省使用當前主機名;
③、nbproc <number>:指定啓動的haproxy進程的個數,只能用於守護進程模式的haproxy;默認只啓動一個進程,鑑於調試困難等多方面的緣由,通常只在單進程僅能打開少數文件描述符的場景中才使用多進程模式;
④、ulimit-n <number>:設定每進程所可以打開的最大文件描述符數目,默認狀況下其會自動進行計算,所以不推薦修改此選項;
⑤、maxconn <number>:設定每一個haproxy進程所接受的最大併發鏈接數,「ulimit -n」自動計算的結果正是參照此參數設定的;
⑥、spread-checks <0..50, in percent>:在haproxy後端有着衆多服務器的場景中,在精確的時間間隔後統一對衆服務器進行健康情況檢查可能會帶來意外問題;此選項用於將其檢查的時間間隔長度上增長或減少必定的隨機時長;
6、Haproxy常見代理配置選項及其用法
①、balance:定義負載均衡算法,可用於「defaults」、「listen」和「backend」。
支持如下算法(動態:權重可動態調整,修改權重後無需重啓服務。靜態:調整權重不會實時生效,須要重啓服務)
roundrobin: 基於權重輪詢,動態算法,每一個後端主機最多支持4128個鏈接;
static-rr:基於權重輪詢,靜態算法,每一個後端主機支持的數量無上限;
leastconn:新的鏈接請求被派發至具備最少鏈接數目的後端服務器;在有着較長時間會話的場景中推薦使用此算法,如LDAP、SQL等,其並不太適用於較短會話的應用層協議,如HTTP;此算法是動態的,能夠在運行時調整其權重;
source:將請求的源地址進行hash運算,並由後端服務器的權重總數相除後派發至某匹配的服務器;這可使得同一個客戶端IP的請求始終被派發至某特定的服務器;不過,當服務器權重總數發生變化時,如某服務器宕機或添加了新的服務器,許多客戶端的請求可能會被派發至與此前請求不一樣的服務器;經常使用於負載均衡無cookie功能的基於TCP的協議;其默認爲靜態,不過也可使用hash-type修改此特性;
uri:對URI的左半部分(「問題」標記以前的部分)或整個URI進行hash運算,並由服務器的總權重相除後派發至某匹配的服務器;這可使得對同一個URI的請求老是被派發至某特定的服務器,除非服務器的權重總數發生了變化;此算法經常使用於代理緩存或反病毒代理以提升緩存的命中率;須要注意的是,此算法僅應用於HTTP後端服務器場景;其默認爲靜態算法,不過也可使用hash-type修改此特性;
URL Syntax: <scheme>://<host>:<port>/<path>;<params>?<query>#<frag>
http://www.wlw.com/test/go;type=s
vim /etc/haproxy/haproxy.cfg frontend main *:80 default_backend webserver backend webserver balance uri hash-type consistent server web.ip45 192.168.0.45:80 check server web.ip66 192.168.0.66:80 check
爲了測試出結果。咱們爲web1和web2各提供五個頁面供測試
[root@wlw1 ~]# for i in {1..5};do echo "Page $i from web.ip45" > /var/www/html/page$i.html;done [root@wlw2 ~]# for i in {1..5};do echo "Page $i from web.ip66" > /var/www/html/page$i.html;done
這裏咱們使用三個客戶端來測試結果,能夠看到只要是訪問同一個uri都是調度到同一臺服務器上
[root@localhost ~]# curl http://192.168.0.56/page1.html Page 1 from web.ip66 [root@wlw1 ~]# curl http://192.168.0.56/page1.html Page 1 from web.ip66 [root@wlw2 ~]# curl http://192.168.0.56/page1.html Page 1 from web.ip66 [root@localhost ~]# curl http://192.168.0.56/page4.html Page 4 from web.ip45 [root@wlw1 ~]# curl http://192.168.0.56/page4.html Page 4 from web.ip45 [root@wlw2 ~]# curl http://192.168.0.56/page4.html Page 4 from web.ip45
url_param:經過<argument>爲URL指定的參數在每一個HTTP GET請求中將會被檢索;若是找到了指定的參數且其經過等於號「=」被賦予了一個值,那麼此值將被執行hash運算並被服務器的總權重相除後派發至某匹配的服務器;此算法能夠經過追蹤請求中的用戶標識進而確保同一個用戶ID的請求將被送往同一個特定的服務器,除非服務器的總權重發生了變化;若是某請求中沒有出現指定的參數或其沒有有效值,則使用輪叫算法對相應請求進行調度;此算法默認爲靜態的,不過其也可使用hash-type修改此特性;
hdr(<name>):對於每一個HTTP請求,經過<name>指定的HTTP首部將會被檢索;若是相應的首部沒有出現或其沒有有效值,則使用輪叫算法對相應請求進行調度;其有一個可選選項「use_domain_only」,可在指定檢索相似Host類的首部時僅計算域名部分(好比經過www.magedu.com來講,僅計算magedu字符串的hash值)以下降hash算法的運算量;此算法默認爲靜態的,不過其也可使用hash-type修改此特性;
[root@localhost ~]# vim /etc/haproxy/haproxy.cfg frontend main *:80 default_backend webserver backend webserver balance hdr(User-Agent) hash-type consistent server web.ip45 192.168.0.45:80 check server web.ip66 192.168.0.66:80 check
這裏咱們使用curl的選項-A來模擬不一樣瀏覽器,測試咱們根據用戶瀏覽器類型來調度到不一樣的服務器
[root@localhost ~]# curl -A 'Google' http://192.168.0.56/index.html My web2 192.168.0.66 [root@localhost ~]# curl -A 'IE 6' http://192.168.0.56/index.html My web1 192.168.0.45
②、hash-type <method>
定義用於將hash碼映射至後端服務器的方法;其不能用於frontend區段;可用方法有map-based和consistent,在大多數場景下推薦使用默認的map-based方法。
map-based:hash表是一個包含了全部在線服務器的靜態數組。其hash值將會很是平滑,會將權重考慮在列,但其爲靜態方法,對在線服務器的權重進行調整將不會生效,這意味着其不支持慢速啓動。此外,挑選服務器是根據其在數組中的位置進行的,所以,當一臺服務器宕機或添加了一臺新的服務器時,大多數鏈接將會被從新派發至一個與此前不一樣的服務器上,對於緩存服務器的工做場景來講,此方法不甚適用。
consistent:hash表是一個由各服務器填充而成的樹狀結構;基於hash鍵在hash樹中查找相應的服務器時,最近的服務器將被選中。此方法是動態的,支持在運行時修改服務器權重,所以兼容慢速啓動的特性。添加一個新的服務器時,僅會對一小部分請求產生影響,所以,尤爲適用於後端服務器爲cache的場景。不過,此算法不甚平滑,派發至各服務器的請求未必能達到理想的均衡效果,所以,可能須要不時的調整服務器的權重以得到更好的均衡性。
③、bind:此指令僅能用於frontend和listen區段,用於定義一個或幾個監聽的套接字。
[root@localhost ~]# vim /etc/haproxy/haproxy.cfg frontend main bind *:80 bind *:8989 [root@localhost ~]# ss -tnlp [root@localhost ~]# ss -tnlp State Recv-Q Send-Q Local Address:Port Peer Address:Port LISTEN 0 128 *:80 *:* users:(("haproxy",2146,5)) LISTEN 0 128 *:8989 *:* users:(("haproxy",2146,6))
④、mode: HAProxy的工做模式;默認爲tcp;還有基於web應用的http
⑤、爲每一個實例啓用事件和流量日誌,所以可用於全部區段。每一個實例最多能夠指定兩個log參數,不過,若是使用了「log global」且"global"段已經定了兩個log參數時,多餘了log參數將被忽略。
⑥、maxconn:設定一個前端的最大併發鏈接數,所以,其不能用於backend區段。對於大型站點來講,能夠儘量提升此值以便讓haproxy管理鏈接隊列,從而避免沒法應答用戶請求。固然,此最大值不能超出「global」段中的定義。
⑦、default_backend:在沒有匹配的"use_backend"規則時爲實例指定使用的默認後端,所以,其不可應用於backend區段。在"frontend"和"backend"之間進行內容交換時,一般使用"use-backend"定義其匹配規則;而沒有被規則匹配到的請求將由此參數指定的後端接收。
⑧、server:爲後端聲明一個server,所以,不能用於defaults和frontend區段。
server <name> <addr>[:port] [param*]
backup: 設定當前server爲backup server;
check: 健康狀態檢測;
inter <delay>:檢測時間間隔;單位爲ms, 默認爲2000;
fall: up --> down, soft state, soft state, hard state;
rise:down --> up,
後端http服務時的健康狀態的檢測方法:
option httpchk:請求首頁,對方響應200即爲成功
option httpchk <uri>:指定的uri,對方響應200即爲成功
option httpchk <method> <uri>:指定方法和uri
option httpchk <method> <uri> <version>:不能用於frontend段
backend https_relay mode tcp option httpchk OPTIONS * HTTP/1.1\r\nHost:\ #使用OPTINOS方法請求,請求uriHTTP/1.1\r\nHost:\ www.wlw.com server web1 192.168.0.88:443 check port 80 #轉發服務器爲192.168.0.88:443,請求443端口。然而能夠對80端口作檢測
cookie <value>:爲指定server設定cookie值,此處指定的值將在請求入站時被檢查,第一次爲此值挑選的server將在後續的請求中被選中,其目的在於實現持久鏈接的功能;基於cookie會話的源綁定。
maxconn: 此服務接受的併發鏈接的最大數量;
maxqueue: 請求隊列的最大長度;
observe: 根據流量判斷後端server的健康狀態;
weight: 指定權重,默認爲1,最大爲256;0表示不被調度,即爲下線。
redir <prefix>: 啓用重定向功能,將發往此服務器的GET和HEAD請求均以302狀態碼響應;須要注意的是,在prefix後面不能使用/,且不能使用相對地址,以避免形成循環
server web1 192.168.0.88:80 redir http://img.wlw.com check
⑨、stats:啓用基於程序編譯時默認設置的統計報告,不能用於「frontend」區段。
listen stats bind *:1515 #讓stats統計報告監聽在1515端口上 stats enable #開啓stats功能 stats hide-version #隱藏版本信息 stats uri /hpadmin?stats #設置uri stats realm HAporxy\ admin #開啓認證時登陸框顯示的信息 stats auth wlw:wlw #認證的帳號密碼 stats auth test:test stats admin if TRUE #若是上面條件認證經過,開啓管理接口 stats scope . #僅能爲127.0.0.1本地訪問
⑩、option forwardfor:容許在發往服務器的請求首部中插入「X-Forwarded-For」首部。
[root@localhost ~]# vim /etc/haproxy/haproxy.cfg defaults option forwardfor except 127.0.0.0/8 [root@wlw ~]# vim /etc/httpd/conf/httpd.conf LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined #爲http訪問日誌中的主機替換爲發送客戶端首部的真實IP地址 [root@wlw ~]# tail /var/log/httpd/access_log 192.168.0.102 - - [25/Oct/2015:05:48:43 +0800] "GET / HTTP/1.1" 304 - "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36"
11、errorfile:在用戶請求不存在的頁面時,返回一個頁面文件給客戶端,這裏可用的狀態碼有200、400、40三、40八、500、50二、503和504;
errorfile 503 /etc/haproxy/errorpages/503sorry.http
12、添加請求或響應報文首部:reqadd,請求報文發完server的時候添加。rspadd,響應報文發給客戶端的時候添加。
[root@localhost ~]# vim /etc/haproxy/haproxy.cfg frontend main bind *:8989 bind *:80 default_backend webserver rspadd Via:\ 192.168.0.56 [root@localhost ~]# curl -I http://192.168.0.56 HTTP/1.1 200 OK Via: 192.168.0.56
6、Haproxy實現LAMP動靜分離
[root@localhost system]# vim /etc/haproxy/haproxy.cfg frontend http bind *:80 mode http acl url_static path_beg -i /static /p_w_picpaths /javascript /stylesheets acl url_static path_end -i .htm .jpg .jpeg .gif .png .css .js use_backend static_servers if url_static default_backend dynamic_servers backend static_servers balance roundrobin server web_static 192.168.0.45:80 check backend dynamic_servers cookie srv insert nocache balance roundrobin server web_dynamic 192.168.0.66:80 check cookie dynamic
在瀏覽器中經過開發工具查看
測試把192.168.0.66的httpd關閉。由於192.168.0.66是響應動態頁面的服務器,因此關閉後php頁面沒法響應,可是訪問圖片正常