HAProxy是法國人Willy Tarreau開發的一款可應對客戶端10000以上的同時鏈接的高性能的TCP和javascript
HTTP負載均衡器。因爲其豐富強大的功能在國內備受推崇,是目前主流的負載均衡器。本文介紹其功能特性並結合配置實例演示,若有錯誤敬請賜教。php
Haproxy主要工做位置:css
1. 支持http反向代理html
2. 支持動態程序的反向代理前端
3. 支持基於數據庫的反向代理java
Haproxy 程序組成:mysql
程序環境:web
安裝:yum install haproxy -y 正則表達式
主程序: /usr/sbin/haproxy算法
配置文件: /etc/haproxy/haproxy.cfg
主配置文件主要結構:1. global 全局配置段 2. proxies代理配置段
索引
1. global:全局配置段配置
1.1 全局日誌配置
1.2 性能調整常見參數
2.proxies:代理配置段結構
3.實現簡單proxy配置實驗
3.1 方法1
3.2 方法2
4.代理配置段常見配置參數
4.1 Balance調度算法相關
4.2 server:定義後端主機相關選項
4.3 實現圖形化配置頁
4.4 default默認配置中定義的內容
4.5 forwardfor後端記錄真實請求配置
4.6 自定義錯誤頁面
4.7 自定義修改報文首部
4.8 自定義鏈接超時相關配置
5. ACL靈活轉發詳解
5.1 acl語法
5.2 匹配條件<criterion>進階
5.3 acl做爲條件時的邏輯關係
5.4 系統預約義ACL(部分)
5.5 配置block拒絕訪問
5.6 指定backend組
5.7 http 7層訪問控制
5.8 tcp 4層鏈接控制
5.9 配置HAProxy支持https協議
6. 附實現動靜分離實驗示例
1. global:全局配置段
1.1 log:全局日誌配置
默認發往本機的日誌服務器;
(1) 系統默認:log 127.0.0.1 local2
發往遠端可添加:log 遠端IP local2
(2) 修改本機日誌配置文件:
vim /etc/rsyslog.conf $ModLoad imudp #取消註釋 $UDPServerRun 514 #取消註釋 local2.* /var/log/haproxy.log #新增 |
(3) 遠端日誌配置(配合前端log配置)
vim /etc/rsyslog.conf local2.* /var/log/haproxy.log #新增 |
1.2 性能調整(依據生產環境適當調整):
maxconn <number>:設定每一個haproxy進程所能接受的最大併發鏈接數
maxconnrate <number>:設置每一個進程每秒種所能創建的最大鏈接數量
maxse***ate <number>:設置每一個進程每秒種所能創建的最大會話數量
maxsslconn <number>: 每進程支持SSL的最大鏈接數量
spread-checks <0..50, in percent> 健康檢測延遲時長比建議2-5之間
2.proxies:代理配置段結構
(1). defaults:爲frontend, backend, listen提供默認配置
(2). fronted:前端,指定接收客戶端鏈接偵聽套接字設置
(3). backend:後端,指定將鏈接請求轉發至後端服務器的相關設置
(4). listen:同時擁有前端和後端,適用於一對一環境
3.實現簡單proxy配置:
實驗拓撲:
3.1 方法一:
配置 /etc/haproxy/haproxy.cfg :
將frontend段、backend段註釋,新建以下配置
frontend http *:80 #均衡器端採用http 協議,監聽80端口 default_backend websrvs #引用後端自定義服務器組名websrvs backend websrvs #設定默認後端,自定義名字爲websrvs balance roundrobin #輪詢方式爲加權輪詢 server web1 192.168.43.61:80 check #設定後端服務器IP ,並引入健康檢查 server web2 192.168.43.63:80 check #設定後端服務器IP ,並引入健康檢查 service haproxy start |
在瀏覽器訪問http://172.18.43.62 刷新便可看到輪詢效果
3.2 方法2:
上面兩段配置也能夠配置在一段實現相同功能,配置以下:
listen http bind :80 balance roundrobin server web1 192.168.43.61:80 check server web2 192.168.43.63:80 check |
配置參數 bind:指定一個或多個前端偵聽地址和端口
語法: bind [<address>]:<port_range> [, ...] [param*]
示例:
listen http_proxy
bind :80,:443
bind 10.0.0.1:10080,10.0.0.1:10443
4.代理配置段常見配置參數
4.1Balance相關
balance:後端服務器組內的服務器調度算法
語法: balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post]
調度算法:
① roundrobin:基於權重輪詢,動態算法, 支持權重的運行時調整,支持慢啓動;每一個後端backend中最多支持4095個server
server options: weight #
② static-rr:基於權重輪詢,靜態算法,不支持權重的運行時調整及慢啓動;後端主機數量無上限
③ leastconn:加權最少鏈接,動態算法,最少鏈接的後端服務器優先分配接收新鏈接,相同鏈接時輪詢,推薦在較長會話的場景使用,例如MySQL、 LDAP等,不適合http。
④ first:根據服務器在列表中的位置,自上而下進行調度;前面服務器的鏈接數達到上限,新請求才會分配給下一臺服務器。
⑤ hdr(<name>):對於每一個http請求,此處由<name>指定的http首部將會被取出作hash計算; 並由服務器總權重相除之後派發至某挑出的服務器; 無有效值的會被輪詢調度
例:hdr(host) hdr(Cookie)
⑤ rdp-cookie 遠程桌面相關
hash類算法:
需配合參數:hash-type <method> <function> <modifier>
method:
map-based:除權取餘法,哈希數據結構是靜態數組
consistent:一致性哈希,哈希數據結構是一棵樹
⑥ source:源地址hash,新鏈接先按權重分配,後續鏈接按source分配請求
⑦ uri:對URI的左半部分或整個uri作hash計算,併除以服務器總權重取模,之後派發至某挑出的服務器,適用於後端緩存服務器
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分: /<path>;<params>
整個uri: /<path>;<params>?<query>#<frag>
⑧ url_param:對用戶請求的uri聽<params>部分中的參數的值(一般爲用戶ID)做hash計算,並由服務器總權重相除之後派發至某挑出的服務器;一般用於追蹤用戶,以確保來自同一個用戶的請求始終發往同一個Backend Server。
4.2 server:定義後端主機相關選項
語法:
server <name> <address>[:[port]] [param*]
<name>:服務器在haproxy上的自定義名稱;出如今日誌及警告信息
<address>:服務器地址,支持使用主機名
[:[port]]:端口映射;省略時,表示同bind中綁定的端口
[param*]:server後可加的參數
weight <weight>:權重,默認爲1
maxconn <maxconn>:當前server的最大併發鏈接數
backlog <backlog>:當server的鏈接數達到上限後的後援隊列長度
backup:設定當前server爲備用服務器
check:對當前server作健康狀態檢測,只用於四層檢測
注意: httpchk, 「smtpchk」, 「mysql-check」, 「pgsql-check」 and 「sslhello-chk」 用於定義應用層檢測方法
addr :檢測時使用的IP地址(檢測的不必定是vip)
port :針對此端口進行檢測
inter <delay>:連續兩次檢測之間的時間間隔,默認單位爲毫秒,默認爲2000ms
rise <count>:連續多少次檢測結果爲「成功」才標記服務器爲可用;默認爲2
fall <count>:連續多少次檢測結果爲「失敗」才標記服務器爲不可用;默認爲3
disabled:標記爲不可用
redir <prefix>:將發往此server的全部GET和HEAD類的請求重定向至指定的URL
cookie <value>:爲當前server指定cookie值,實現基於cookie的會話黏性。
基於cookie的session sticky的實現:
frontend http bind 172.18.43.62:80 default_backend websrvs backend websrvs balance roundrobin cookie SRV insert nocache #自定義會話添加cookie信息SRV,insert:插入 nocache:不緩存增長保密性 server web1 192.168.43.61:80 check weight 2 cookie srv1 #自定義該server添加cookie信息爲srv1 server web2 192.168.43.63:80 check maxconn 5000 cookie srv2 #自定義該server添加cookie信息爲srv2 server sorroyserver 192.168.43.62:80 backup |
4.3 實現圖形化配置頁面
stats enable 添加這條參數後會在web頁面啓用統計頁;參數可放置位置。
咱們在frontend段添加stats enable ,重啓haproxy。瀏覽器訪問172.18.43.62/haproxy?stats便可
相關參數:
① stats refresh <delay>設定自動刷新時間間隔
若服務器出現故障,默認手動刷新才能才能看到狀態的變化,可設置自動刷新
例:添加stats refresh 2s
② stats uri <prefix> 自定義stats page uri
默認爲/haproxy?stats 可自定義uri
例:stats uri /hastas
重啓後訪問http://172.18.43.62/hastas便可
③ stats hide-version
如上圖所示界面會顯示haproxy版本信息,若想隱藏版本加上此參數便可
④ stats auth <user>:<passwd> 認證時的帳號和密碼,可以使用屢次。如多個用戶定義多行便可,例:
stats auth ha1:centos1
stats auth ha2:centos2
⑤ stats realm <realm> 認證時瀏覽器彈出對話框的提示信息
例:stats realm "haproxy info"
⑥ stats admin { if | unless } <cond> 啓用stats page中的管理功能
例:stats admin if TRUE
將stats分離出單獨語句塊,採用內網的6666端口提升訪問安全性示例:
listen admin bind 192.168.43.62:6666 stats enable stats uri /status stats realm "haproxy info" stats auth ha1:centos stats hide-version stats refresh 5s stats admin if TRUE |
從內網訪問界面:
4.4 default中定義的內容
能夠在frontend、backend、listen中分別進行定義,如沒有指定將默認default中設置,如:
maxconn <conns>:爲指定的frontend定義其最大併發鏈接數;默認爲3000
mode { tcp|http|health } 定義haproxy的工做模式(默認http)
tcp:基於layer4實現代理;可代理mysql, pgsql, ssh,ssl等協議,https時使用此模式,默認模式
http:僅當代理協議爲http時使用,centos實際默認模式
health:工做爲健康狀態檢查的響應模式,當鏈接請求到達時迴應「OK」後即斷開鏈接,較少使用
TCP模式的健康狀態檢測示例:
listen ssh bind :22022 balance leastconn mode tcp server sshsrv1 172.16.100.6:22 check server sshsrv2 172.16.100.7:22 check |
4.5 forwardfor配置
語法 :option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
在由haproxy發日後端主機的請求報文中添加「X-ForwardedFor」首部,其值爲前端客戶端的地址;用於向後端主發送真實的客戶端IP
[ except <network> ]:請求報請來自此處指定的網絡時不予添加此首部,如haproxy自身所在網絡
[ header <name> ]:使用自定義的首部名稱,而非「XForwarded-For」
[ if-none ] 若是沒有首部才添加首部,若是有使用默認值
默認defaults中有一條配置option forwardfor except 127.0.0.0/8
若想後端日誌記錄真實請求客戶端IP,需更改後端兩臺服務器配置文件:
vim /etc/httpd/conf/httpd.conf LogFormat "%{x-forwarded-for}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" haformat #添加日誌格式 CustomLog logs/access_log haformat #修改記錄日誌 |
重載客戶端httpd服務,瀏覽器刷新請求。在客戶端觀看日誌便可看到真實請求服務器
tail -f /var/log/httpd/access_log |
4.6 自定義錯誤頁面
① errorfile <code> <file> 自定義錯誤頁
<code>: HTTP status code. 支持200, 400, 403, 408, 500, 502, 503, 504.
<file>:錯誤頁文件路徑
例:errorfile 400 /etc/haproxy/errorfiles/400badreq.http
② rrorloc <code> <url> 至關於errorloc302 <code> <url>,利用302重定向至指URL
例:errorloc 503 http://www.magedu.com/error_pages/503.html
4.7修改報文首部
① reqadd <string> [{if | unless} <cond>] 在請求報文尾部添加指定首部(用於web端區分從哪一個調度器發來請求)
例:在frontend中添加 reqadd X-via:\ haproxy1
後端修改httpd.conf中logformat添加%{X-via}i
再次訪問日誌就會看到是經過哪一個調度器調度到本機
② rspadd <string> [{if | unless} <cond>] 在響應報文尾部添加指定首部 (用於haproxy以前的調度器查看用於排錯)
示例: rspadd X-Via:\ HAPorxy
③ reqdel <search> [{if | unless} <cond>]
reqidel <search> [{if | unless} <cond>] (ignore case) 不分大小寫
從請求報文中刪除匹配正則表達式的首部
④ rspdel <search> [{if | unless} <cond>]
rspidel <search> [{if | unless} <cond>] (ignore case) 不分大小寫
從響應報文中刪除匹配正則表達式的首部
示例: rspidel Server.* 用於隱藏web服務器版本信息
rspadd Server:\ Apache 15.1 結合上例可僞造server信息
4.8 定義鏈接超時
① timeout client <timeout> 客戶端最長空閒鏈接超時時長 默認單位是毫秒
② timeout server <timeout> 後端服務器最長空閒鏈接超時時長
③ timeout http-keep-alive <timeout> 持久鏈接的持久時長
④ timeout http-request <timeout> 一次完整的HTTP請求的最大等待時長
⑤ timeout connect <timeout> 成功鏈接後端服務器的最大等待時長
⑥ timeout client-fin <timeout> 客戶端半鏈接的空閒時長
⑦ timeout server-fin <timeout> 後端服務器半鏈接的空閒時長
5. ACL靈活轉發詳解
acl:訪問控制列表(ACL)的使用提供了一個靈活的解決方案來執行內容交換,而且一般基於從請求中提取的內容、響應或任何環境狀態進行決策,是haproxy的重要特點。
5.1 語法
acl <aclname> <criterion> [flags] [operator] [<value>]...
<aclname>: ACL名稱,可以使用字母 數字 : . - _區分字符大小寫
<criterion>: 比較的標準和條件
dst 目標IP
dst_port 目標PORT
src 源IP
src_port 源PORT
示例: acl invalid_src src 172.16.100.200
<flags>
-i 不區分大小寫
-m 使用指定的pattern匹配方法
-n 不作DNS解析
-u 強制每一個ACL必須惟一ID,不然多個同名ACL或關係
-- 強制flag結束. 當字符串和某個flag類似時使用
[operator]
匹配整數值: eq、 ge、 gt、 le、 lt
匹配字符串:
- exact match (-m str) :字符串必須徹底匹配模式
- substring match (-m sub) :在提取的字符串中查找若是包含, ACL將匹配
- prefix match (-m beg) :在提取的字符串首部中查找模式,若是其中任何一個被發現, ACL將匹配
- suffix match (-m end) :將模式與提取字符串的尾部進行比較,若是其中任何一個匹配,則ACL進行匹配
- subdir match (-m dir) :查看提取出來的用斜線分隔(「/」)的字符串, 若是其中任何一個匹配,則ACL進行匹配
- domain match (-m dom) :查找提取的用點(「.」)分隔字符串,若是其中任何一個匹配,則ACL進行匹配
<value>的類型:
- boolean
- integer or integer range
- IP address / network
- string (exact, substring, suffix, prefix, subdir,domain)
- regular expression
- hex block
5.2 匹配條件<criterion>進階:
(1)base : string
返回第一個主機頭和請求的路徑部分的鏈接,該請求從第一個斜槓開始,並在問號以前結束,對虛擬主機有用
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
base : exact string match
base_beg : prefix match
base_dir : subdir match
base_dom : domain match
base_end : suffix match
base_len : length match
base_reg : regex match
base_sub : substring match
(2)path : string
提取請求的URL路徑,該路徑從第一個斜槓開始,並在問號以前結束(無主機部分)
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
path : exact string match
path_beg : prefix match
path_dir : subdir match
path_dom : domain match
path_end : suffix match
path_len : length match
path_reg : regex match
path_sub : substring match
例:acl adminpath path_beg -i /admin
acl p_w_picpathfile path_end .jpg .png .bmp
(3)url : string
提取請求中的URL。 一個典型的應用是具備預取能力的緩存,以及須要從數據庫聚合多個信息並將它們保存在緩存中的網頁門戶入口
url : exact string match
url_beg : prefix match
url_dir : subdir match
url_dom : domain match
url_end : suffix match
url_len : length match
url_reg : regex match
url_sub : substring match
(4)req.hdr([<name>[,<occ>]]) : string
提取在一個HTTP請求報文的首部
hdr([<name>[,<occ>]]) : exact string match
hdr_beg([<name>[,<occ>]]) : prefix match
hdr_dir([<name>[,<occ>]]) : subdir match
hdr_dom([<name>[,<occ>]]) : domain match
hdr_end([<name>[,<occ>]]) : suffix match
hdr_len([<name>[,<occ>]]) : length match
hdr_reg([<name>[,<occ>]]) : regex match
hdr_sub([<name>[,<occ>]]) : substring match
(5)status : integer
返回在響應報文中的狀態碼
5.3 acl做爲條件時的邏輯關係:
- 與:隱式(默認)使用
- 或:使用「or」 或 「||」表示
- 否認:使用「!「 表示
同一個組名可定義屢次
示例: if invalid_src invalid_port 與關係
if invalid_src || invalid_port 或
if ! invalid_src 非
5.4 預約義ACL(部分)
ACL名稱
|
等價於
|
說明
|
TRUE |
always_true |
老是匹配 |
FALSE |
always_false |
從不匹配 |
HTTP_1.1 |
req_ver 1.1 |
匹配HTTP協議1.1 |
HTTP |
req_proto_http |
匹配HTTP協議 |
LOCALHOST
|
src 127.0.0.1/8
|
匹配從localhost來的鏈接
|
METH_CONNECT
|
method CONNECT
|
匹配HTTP CONNECT方法
|
5.5 配置block拒絕訪問
語法:block { if | unless } <condition> 阻止7層請求if/unless一個條件匹配
例1:
frontend http acl deny_src src 172.18.0.108 #自定義源地址爲172.18.0.108的acl組deny_src acl deny_port dst_port 80:100 #自定義目標端口爲80到100的acl組deny_port block if deny_src || deny_port #若是屬於deny_src組或deny_port組則拒絕訪問 block unless deny_src #若是不屬於acl組deny_src則拒絕訪問 |
例2(阻止curl訪問):
acl bad_curl hdr_sub(User-Agent) -i curl block if bad_curl |
5.6 指定backend組
語法:use_backend <backend> [{if | unless} <condition>]
當if/unless一個基於ACL的條件匹配時切換指定backend(可實現動靜分離)
例1:
acl p_w_picpathfile path_end .jpg .png .bmp acl appfile path_end .php use_backend websrvs1 if p_w_picpathfile use_backend websrvs2 if appfile |
例2:
例3:
acl webhost hdr(host) web.51cto.com acl apphost hdr(host) app.51cto.com use_backend websrvs if webhost use_backend appsrvs if apphost |
5.7 http 7層訪問控制
語法:http-request { allow | deny |add-header <name> <fmt>|set-header <name> <fmt> } [ { if | unless }<condition> ]
對7層請求的訪問控制
5.8 tcp4層鏈接控制
語法:tcp-request connection {accept|reject} [{if | unless} <condition>]
根據第4層條件對傳入鏈接執行操做
例:
listen ssh bind :22022 balance leastconn acl invalid_src src 172.16.200.2 tcp-request connection reject if invalid_src mode tcp server sshsrv1 172.16.100.6:22 check server sshsrv2 172.16.100.7:22 check backup |
5.9 配置HAProxy支持https協議:
① 支持ssl會話;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
crt 後證書文件爲PEM格式,且同時包含證書和全部私鑰
爲實驗方便自簽證書方法:
在etc/pki/tls/certs/目錄下執行make命令可得到同時包含證書和全部私鑰的證書
cd /etc/pki/tls/certs/ make /etc/haproxy/haproxy.pem |
證書和私鑰分離的狀況可經過重定向得到:cat demo.crt demo.key > demo.pem
② 把80端口的請求重向定443
bind *:80
redirect scheme https if !{ ssl_fc } #注意花括號裏面有空格
③ 向後端傳遞用戶請求的協議和端口(frontend或backend)
http_request set-header X-Forwarded-Port %[dst_port]
http_request add-header X-Forwared-Proto https if { ssl_fc }
例:
測試:
向後端傳遞用戶請求:
修改後端httpd.conf中日誌格式便可
6. 附基於ACL的動靜分離示例
frontend web *:80 acl url_static path_beg -i /static /p_w_picpaths /javascript /stylesheets acl url_static path_end -i .jpg .gif .png .css .js .html .txt .htm use_backend staticsrvs if url_static default_backend appsrvs backend staticsrvs balance roundrobin server stcsrv1 172.16.100.6:80 check backend appsrvs balance roundrobin server app1 172.16.100.7:80 check server app1 172.16.100.7:8080 check listen stats bind :9091 stats enable stats auth admin:admin stats admin if TRUE |