1.HAProxy介紹
? HAProxy: 是法國人Willy Tarreau開發的一個開源軟件,是 一款應對客戶端10000以上的同時連接的高性能的TCP
和 HTTP負載均衡器。其功能是用來提供基于cookie持久性, 基于內容的交換,過載保護的高級流量管制,自動故障切換 ,
以正則表達式為基礎的標題控制運行時間,基于Web的報 表,高級日志記錄以幫助排除故障的應用或網絡及其他功能
? LB Cluster:
四層:lvs, nginx(stream),haproxy(mode tcp)
七層:http: nginx(http), haproxy(mode http), httpd...
? HAProxy:http://www.haproxy.org
? 文檔:https://cbonte.github.io/haproxy-dconv/
● HAProxy是TCP / HTTP反向代理服務器,尤其適合于高可用 性環境
● 可以針對HTTP請求添加cookie,進行路由后端服務器
● 可平衡負載至后端服務器,并支持持久連接
● 支持基于cookie進行調度
● 支持所有主服務器故障切換至備用服務器
● 支持專用端口實現監控服務
● 支持不影響現有連接情況下停止接受新連接請求
● 可以在雙向添加,修改或刪除HTTP報文首部
● 支持基于pattern實現連接請求的訪問控制
● 通過特定的URI為授權用戶提供詳細的狀態信息
? 版本:1.4 1.5 1.6 1.7 1.8
clipboard.png
2.Haproxy功能
● 支持http反向代理
● 支持動態程序的反向代理
● 支持基于數據庫的反向代理
clipboard1.png
3. HAProxy組成
https://cbonte.github.io/haproxy-dconv/
clipboard2.png
? 程序環境:
主程序:/usr/sbin/haproxy
配置文件:/etc/haproxy/haproxy.cfg
Unit file:/usr/lib/systemd/system/haproxy.service
? 配置段:
● global:全局配置段
進程及安全配置相關的參數
性能調整相關參數
Debug參數
● proxies:代理配置段
defaults:為frontend, backend, listen提供默認配置
fronted:前端,相當于nginx, server {}
backend:后端,相當于nginx, upstream {}
listen:同時擁有前端和后端,適用于一對一環境 (最好前后端分開,以后
好調整)
? 簡單的配置示例:
frontend web
bind *:80 綁定所有端口
default_backend websrvs 默認的backend
backend websrvs
balance roundrobin
server srv1 172.16.0.6:80 check
server srv2 172.16.0.7:80 check
haproxy -f haproxy 檢查配置文件
systemctl status haproxy 檢查一下haproxy狀態
eg:
clipboard3.png
clipboard4.png
clipboard5.png
4.global配置 :
global配置參數:
進程及安全管理:chroot, deamon,user, group, uid, gid
nbproc :要啟動的haproxy的進程數量,系統 默認單進程,要求使用daemon模式
ulimit-n :每個haproxy進程可打開的最大文件數,系統自動會指定,不建議設置
daemon:后端方式運行,建議使用
log:定義全局的syslog服務器;最多可以定義兩個
log <address> [len <length>] <facility>[max level [min level]]
address: rsyslog服務器地址
len: 記錄日志的長度,默認1024 10
5.日志系統
log:
log global
log <address> [len <length>] <facility>[<level>[<minlevel>]]
no log
注意:
默認發往本機的日志服務器;
(1) local2.* /var/log/local2.log
(2)#vim /etc/rsyslog.conf
$ModLoad imudp
$UDPServerRun 514
? log-format <string>:
課外實踐:參考文檔實現combined格式的記錄
記錄日志到本機
clipboard6.png
clipboard7.png
clipboard8.png
clipboard9.png
存放日志到遠程服務器
clipboard10.png
clipboard11.png
clipboard12.png
clipboard13.png
6.日志管理
將特定信息記錄在日志中
? capture cookie len <name> len <length>
捕獲請求和響應報文中的 cookie并記錄日志
? capture request header <name> len <length>
捕獲請求報文中指定的首部并記錄日志
示例: capture request header X-Forwarded-For len
? capture response header <name> len <length>
捕獲響應報文中指定的首部并記錄日志
示例: capture response header Content-length len 9
capture response header Location len 15
7.性能調整
性能調整:
maxconn <number>:設定每個haproxy進程所能接受的最大并發連接數
maxconnrate <number>:設置每個進程每秒種所能建立的最大連接數量
maxsessrate <number>:設置每個進程每秒種所能建立的最大會話數量
maxsslconn <number> : 每進程支持SSL的最大連接數量
spread-checks <0..50, in percent> 健康檢測延遲時長百分比
建議2%-5%之間
8.配置段
* 代理配置段:
- defaults
- frontend
- backend
- listen
? Frontend段:指定接收客戶端連接偵聽套接字設置
? Backend段:指定將連接請求轉發至后端服務器的相關設置
? Listen段:指定完整的前后端設置,只對 TCP 有效
? proxy 名稱:使用字母 數字 - _ . : 并區分字符大小寫
9.配置參數
? bind:指定一個或多個前端偵聽地址和端口
bind [<address>]:<port_range> [, ...] [param*]
? 示例:
listen http_proxy
bind :80,:443 監聽所有IP的80和443端口
bind 10.0.0.1:10080,10.0.0.1:10443
bind /var/run/ssl-frontend.sock user root mode 600 accept-proxy
clipboard14.png
10.Balance配置
? balance:后端服務器組內的服務器調度算法
? balance <algorithm> [ <arguments> ]
? balance url_param <param> [check_post]
? 調度算法:
* roundrobin:基于權重輪詢,動態算法,支持權重的運行時調整,支持慢啟 動;每個后端backend中最多支持4095個server
server options: weight #
* static-rr:基于權重輪詢,靜態算法,不支持權重的運行時調整及慢啟動;后端主機數量無上限
* leastconn:加權最少連接,動態算法,最少連接的后端服務器優先分配接收新連接,相同連接時輪詢,推薦在較長會話的場景使用,例如 MySQL、LDAP等,不適合http
* first:根據服務器在列表中的位置,自上而下進行調度;前面服務器 的連接數達到上限,新請求才會分配給下一臺服務
* source:源地址hash,新連接先按權重分配,后續連接按source分配 請求 16 Balance配置
* uri: 對URI的左半部分或整個uri做hash計算,并除以服務器總權 重取模,以后派發至某挑出的服務器,適用于后端緩存服務器
<scheme>://<user>:<passwd>@<host>:<port>/<path>;<params>?<query>#<frag>
左半部分:/<path>;<params>
整個uri:/<path>;<params>?<query>#<frag>
* url_param: 對用戶請求的uri聽部分中的參數的值作hash計算,并由服務器總權重相除以后派發至某挑出的服務器;通常用于追蹤用 戶,以確保來自同一個用戶請求始終發往同一個Backend Server
* hdr():對于每個http請求,此處由<name>指定的 http首部將會被取出做hash計算; 并由服務器總權重相除以后派發至某挑出的服務器;無有效值的會被輪詢調度
hdr(Cookie)
* rdp-cookie 遠程桌面相關
* rdp-cookie()
11.哈希算法
? hash-type:哈希算法
hash-type <method> <function> <modifier>
method:
map-based:除權取余法,哈希數據結構是靜態數組
consistent:一致性哈希,哈希數據結構是一棵樹
<function> : 哈希函數
sdbm djb2 wt6
? default_backend <backend>
無use_backend 匹配時,使用默認的backend,用于 frontend中
? default-server [param*]
為backend中的各server設定默認選項
配置
? server <name> <address> [:[port]] [param*]
定義后端主機的各服務器及其選項
server <name> <address> [:port] [settings ...]
default-server [settings ...]
<name>:服務器在haproxy上的內部名稱;出現在日志及警告信息
<address>:服務器地址,支持使用主機名
[:[port]]:端口映射;省略時,表示同bind中綁定的端口
[param*]:參數
weight :權重,默認為1
maxconn :當前server的最大并發連接數
backlog :當server的連接數達到上限后的后援隊列長度
backup:設定當前server為備用服務器 20 健康狀態檢測
? check:對當前server做健康狀態檢測,只用于四層檢測
注意:httpchk, “smtpchk”, “mysql-check”, “pgsql-check” and “sslhello-chk” 用于定義應用層檢測方法
addr :檢測時使用的IP地址
port :針對此端口進行檢測
inter <delay> :連續兩次檢測之間的時間間隔,默認為2000ms
rise <count>:連續多少次檢測結果為“成功”才標記服務器為可用 ;默認為2
fall <count>:連續多少次檢測結果為“失敗”才標記服務器為不可 用;默認為3
cookie <value>:為當前server指定cookie值,實現基于cookie的會話黏性
disabled:標記為不可用
redir <prefix>:將發往此server的所有GET和HEAD類的請求重定向至指定的URL
12.cookie配置
? cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain ]* [ maxidle ] [ maxlife <life> ]
<name> :cookie名稱,用于實現持久連接
rewrite:重寫
insert:插入
prefix:前綴
配置示例
? 基于cookie的session sticky的實現:
backend websrvs
cookie WEBSRV insert nocache indirect
server srv1 172.16.100.6:80 weight 2 check rise 1 fall 2 maxconn 3000 cookie srv1
server srv2 172.16.100.7:80 weight 1 check rise 1 fall 2 maxconn 3000 cookie srv2
13. 統計接口啟用相關的參數
? stats enable
啟用統計頁;基于默認的參數啟用stats page
- stats uri : /haproxy?stats uri默認值
- stats realm : HAProxy\ Statistics
- stats auth : no authentication
? stats uri <prefix>
自定義stats page uri
? stats auth <user>:<passwd>
認證時的賬號和密碼,可使用多次
? stats realm <realm>
認證時的realm
? stats hide-version
隱藏版本
? stats refresh <delay>
設定自動刷新時間間隔
? stats admin { if | unless } <cond>
啟用stats page中的管理功能
? 配置示例:
listen stats
bind :9099
stats enable
stats realm HAPorxy\ Stats\ Page
stats auth admin:admin
stats admin if TRUE
14.工作模式
? maxconn :為指定的frontend定義其最大并發連接 數;默認為2000
? mode { tcp|http|health }
定義haproxy的工作模式
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
15.健康狀態檢測
? 對后端服務器做http協議的健康狀態檢測:
option httpchk 默認為:/ OPTIONS HTTP/1.0
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
定義基于http協議的7層健康狀態檢測機制
http-check expect [!] <match> <pattern>
http協議健康狀態檢測響應內容或指定響應碼
16.forwardfor配置
? option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
在由haproxy發往后端主機的請求報文中添加“X-ForwardedFor”首部,其值為前端客戶端的地址;用于向后端主發送真實的客戶端IP
[ except <network> ]:請求報請來自此處指定的網絡時不予 添加此首部,如haproxy自身所在網絡
[ header <name> ]:使用自定義的首部名稱,而非“XForwarded-For”
[ if-none ] 如果沒有首部才添加首部,如果有使用默認值
? 為指定的MIME類型啟用壓縮傳輸功能
compression algo ...:啟用http協議的壓縮機 制,指明壓縮算法gzip, deflate
compression type ...:指明壓縮的MIMI類型
17.錯誤頁配置
errorfile <code> <file> 自定義錯誤頁
<code> :HTTP status code.
支持200, 400, 403, 408, 500, 502, 503, 504\.
<file>:錯誤頁文件路徑
? 示例:
errorfile 400 /etc/haproxy/errorfiles/400badreq.http
errorfile 408 /dev/null # workaround Chrome preconnect bug
errorfile 403 /etc/haproxy/errorfiles/403forbid.http
errorfile 503 /etc/haproxy/errorfiles/503sorry.http
? errorloc <code> <url>
相當于errorloc302 ,利用302重定向至指URL
errorloc 503 http://www.magedu.com/error_pages/503.html
報文首部
? 修改報文首部
* reqadd <string>[{if | unless} <cond> ]
在請求報文尾部添加指定首部
* rspadd <string> [{if | unless} <cond> ]
在響應報文尾部添加指定首部
示例: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.*
連接超時
* 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> 后端服務器半連接的空閑時長
18.ACL
? acl:訪問控制列表(ACL)的使用提供了一個靈活的解決方 案來執行內容交換,并且通?;趶恼埱笾刑崛〉膬热荨㈨?應或任何環境狀態進行決策
? acl <aclname> <criterion> [flags] [operator] [<value>]
...
<aclname>:ACL名稱,可使用字母 數字 : . - _
區分字符大小寫
<criterion>: 比較的標準和條件
? <value>的類型:
- boolean
- integer or integer range
- IP address / network
- string (exact, substring, suffix, prefix, subdir, domain)
- regular expression
- hex block
?<flag>
-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進行匹配
? acl作為條件時的邏輯關系:
- 與:隱式(默認)使用
- 或:使用“or” 或 “||”表示
- 否定:使用“!“ 表示
示例: if invalid_src invalid_port 與關系
if invalid_src || invalid_port 或
if ! invalid_src 非
?<criterion>:各種條件
dst 目標IP
dst_port 目標PORT
src 源IP
src_port 源PORT
示例:acl invalid_src src 172.16.100.200
? base : string
返回第一個主機頭和請求的路徑部分的連接,該請求從第一個斜杠開始,并在問號之前結束,對虛擬主機有用
<scheme>://<user>:<passwd>@<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
? 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
? 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
? 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
示例:
acl bad_curl hdr_sub(User-Agent) -i curl
block if bad_curl
? status : integer
返回在響應報文中的狀態碼
* 預定義ACL
? ACL名稱 等價于 說明
? TRUE always_true 總是匹配
? FALSE always_false 從不匹配
? HTTP req_proto_http 匹配HTTP協議
? HTTP_1.0 req_ver 1.0 匹配HTTP協議1.0
? HTTP_1.1 req_ver 1.1 匹配HTTP協議1.1
? HTTP_CONTENT hdr_val(content-length) gt 0 匹配已存在內容長度
? HTTP_URL_ABS url_reg ^[^/:]*:// 匹配URL絕對路徑
? HTTP_URL_SLASH url_beg / 匹配URL相對路徑
? HTTP_URL_STAR url * 匹配 URL 等于 "*"
? LOCALHOST src 127.0.0.1/8 匹配從localhost來的連接
? METH_CONNECT method CONNECT 匹配HTTP CONNECT方法
* ACL
? METH_GET method GET HEAD match HTTP GET or HEAD method
? METH_HEAD method HEAD match HTTP HEAD method
? METH_OPTIONS method OPTIONS match HTTP OPTIONS method
? METH_POST method POST match HTTP POST method
? METH_TRACE method TRACE match HTTP TRACE method
? RDP_COOKIE req_rdp_cookie_cnt gt 0 match presence of an RDP cookie
? REQ_CONTENT req_len gt 0 match data in the request buffer
? WAIT_ENDwait_end wait for end of content analysis
19.配置
? use_backend <backend>[{if | unless} <condition>]
當if/unless一個基于ACL的條件匹配時切換指定backend
? block { if | unless } <condition>
阻止7層請求if/unless一個條件匹配
? 示例:
acl invalid_src src 172.16.200.2
block if invalid_src
errorfile 403 /etc/fstab
? http-request { allow | deny |add-header <name> <fmt> |set-header <name> <fmt>} [ { if | unless } <condition> ]
對7層請求的訪問控制
? 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
基于ACL的動靜分離示例
frontend web *:80
acl url_static path_beg -i /static /images /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
20.支持https協議
? 配置HAProxy支持https協議:
? 1 支持ssl會話;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
crt 后證書文件為PEM格式,且同時包含證書和所有私鑰
cat demo.crt demo.key > demo.pem
? 2 把80端口的請求重向定443
bind *:80
redirect scheme https if !{ ssl_fc }
? 3 向后端傳遞用戶請求的協議和端口(frontend或backend)
http_request set-header X-Forwarded-Port %[dst_port]
http_request add-header X-Forwared-Proto https if { ssl_fc }