HAProxy 是一款提供高可用性、負載均衡以及基于TCP(第四層)和HTTP(第七層)應用的代理軟件。
相較與 Nginx,HAProxy 更專注與反向代理,因此它可以支持更多的選項,更精細的控制,更多的健康狀態檢測機制和負載均衡算法。
四層和七層負載均衡的區別:
四層:
- 通過分析IP層及TCP/UDP層的流量實現的基于“IP+端口”的負載均衡。
七層:
-
可以根據報內容,再配合負載均衡算法來選擇后端服務器,不但可以根據“ip+端口”方式進行負載分流,還可以根據網站的URL,訪問域名,瀏覽器類別,語言等決定負載均衡的策略。
-
七層負載均衡模式下,負載均衡與客戶端及后端的服務器會分別建立一次TCP連接,而在四層負載均衡模式下,僅建立一次TCP連接;七層負載均衡對負載均衡設備的要求更高,處理能力也低于四層負載均衡。
程序環境:
- 主程序:/usr/sbin/haproxy
- 主配置文件:/etc/haproxy/haproxy.cfg
- Unit file:/usr/lib/systemd/system/haproxy.service
配置文件:/etc/haproxy/haproxy.cfg
配置段:
global:全局配置段
進程管理及安全配置相關的參數
性能調整相關參數
Debug參數
proxies:代理配置段
defaults:為frontend, listen, backend提供默認配置;
fronted:前端,相當于nginx, server {}
backend:后端,相當于nginx, upstream {}
listen:同時擁前端和后端
注意:所有代理的名稱只能使用大寫字母、小寫字母、數字、-(中線)、_(下劃線)、.(點號)和:(冒號)。此外,ACL名稱會區分字母大小寫
global:全局配置段
* 進程管理及安全配置相關的參數
– chroot <jail dir>:修改haproxy的工作目錄至指定的目錄并在放棄權限之前執行chroot()操作,可以提升haproxy的安全級別,不過需要注意的是要確保指定的目錄為空目錄且任何用戶均不能有寫權限; – daemon:讓haproxy以守護進程的方式工作于后臺,其等同于“-D”選項的功能,當然,也可以在命令行中以“-db”選項將其禁用; – gid <number>:以指定的GID運行haproxy,建議使用專用于運行haproxy的GID,以免因權限問題帶來風險; – group <group name>:同gid,不過指定的組名; – log <address> <facility> [max level [min level]]:定義全局的syslog服務器,最多可以定義兩個; – log-send-hostname [<string>]:在syslog信息的首部添加當前主機名,可以為“string”指定的名稱,也可以缺省使用當前主機名; – nbproc <number>:指定啟動的haproxy進程的個數,只能用于守護進程模式的haproxy;默認只啟動一個進程,鑒于調試困難等多方面的原因,一般只在單進程僅能打開少數文件描述符的場景中才使用多進程模式; – pidfile: – uid:以指定的UID身份運行haproxy進程; – ulimit-n:設定每進程所能夠打開的最大文件描述符數目,默認情況下其會自動進行計算,因此不推薦修改此選項;Linux默認單進程打開文件數為1024個 – user:同uid,但使用的是用戶名; – stats:用戶訪問統計數據的接口 – node:定義當前節點的名稱,用于HA場景中多haproxy進程共享同一個IP地址時; – description:當前實例的描述信息;
* 性能調整相關的參數
– maxconn <number>:設定每個haproxy進程所接受的最大并發連接數,其等同于命令行選項“-n”;“ulimit -n”自動計算的結果正是參照此參數設定的; – maxpipes <number>:haproxy使用pipe完成基于內核的tcp報文重組,此選項則用于設定每進程所允許使用的最大pipe個數;每個pipe會打開兩個文件描述符,因此,“ulimit -n”自動計算時會根據需要調大此值;默認為maxconn/4,其通常會顯得過大; – noepoll:在Linux系統上禁用epoll機制; – nokqueue:在BSE系統上禁用kqueue機制; – nopoll:禁用poll機制; – nosepoll:在Linux禁用啟發式epoll機制; – nosplice:禁止在Linux套接字上使用內核tcp重組,這會導致更多的recv/send系統調用;不過,在Linux 2.6.25-28系列的內核上,tcp重組功能有bug存在; – spread-checks <0..50, in percent>:在haproxy后端有著眾多服務器的場景中,在精確的時間間隔后統一對眾服務器進行健康狀況檢查可能會帶來意外問題;此選項用于將其檢查的時間間隔長度上增加或減小一定的隨機時長; – tune.bufsize <number>:設定buffer的大小,同樣的內存條件小,較小的值可以讓haproxy有能力接受更多的并發連接,較大的值可以讓某些應用程序使用較大的cookie信息;默認為16384,其可以在編譯時修改,不過強烈建議使用默認值; – tune.chksize <number>:設定檢查緩沖區的大小,單位為字節;更大的值有助于在較大的頁面中完成基于字符串或模式的文本查找,但也會占用更多的系統資源;不建議修改; – tune.maxaccept <number>:設定haproxy進程內核調度運行時一次性可以接受的連接的個數,較大的值可以帶來較大的吞吐率,默認在單進程模式下為100,多進程模式下為8,設定為-1可以禁止此限制;一般不建議修改; – tune.maxpollevents <number>:設定一次系統調用可以處理的事件最大數,默認值取決于OS;其值小于200時可節約帶寬,但會略微增大網絡延遲,而大于200時會降低延遲,但會稍稍增加網絡帶寬的占用量; – tune.maxrewrite <number>:設定為首部重寫或追加而預留的緩沖空間,建議使用1024左右的大小;在需要使用更大的空間時,haproxy會自動增加其值; – tune.rcvbuf.client <number>: – tune.rcvbuf.server <number>:設定內核套接字中服務端或客戶端接收緩沖的大小,單位為字節;強烈推薦使用默認值; – tune.sndbuf.client: – tune.sndbuf.server:
proxies:代理配置段
- defaults段為frontend, listen, backend提供默認配置;
- frontend段用于定義一系列監聽的套接字,這些套接字可接受客戶端請求并與之建立連接。
- backend段用于定義一系列“后端”服務器,代理將會將對應客戶端的請求轉發至這些服務器。
- listen段通過關聯“frontend”和“backend”定義了一個完整的代理,通常只對TCP流量有用
bind:定義一個或幾個監聽的套接字,綁定ip及端口
bind [<address>]:<port_range> [, …] [param*]
例:
listen http_proxy bind :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
balance: 定義負載均衡調度算法,可用于“defaults”、“listen”和“backend”組
balance <algorithm> [ <arguments> ]
balance url_param <param> [check_post]
HAProxy 負載均衡調度算法:
roundrobin輪詢 server options: weight # 動態算法:支持權重的運行時調整,支持慢啟動;每個后端中最多支持4095個server; static-rr: 靜態算法:不支持權重的運行時調整及慢啟動;后端主機數量無上限;不支持平滑切換; leastconn: 最少鏈接算法,推薦使用在具有較長會話的場景中,例如MySQL、LDAP等 ;不適用與http; first: 根據服務器在列表中的位置,自上而下進行調度;前面服務器的連接數達到上限,新請求才會分配給下一臺服務; source:基于源IP的綁定,源地址hash; 除權取余法: 一致性哈希: uri: 對URI的左半部分做hash計算,并由服務器總權重相除以后派發至某匹配的服務器;使得對同一個URI的請求總是被派發至某特定的服務器,除非服務器的權重總數發生了變化;此算法常用于代理緩存或反病毒代理以提高緩存的命中率;需要注意的是,此算法僅應用于HTTP后端服務器場景;其默認為靜態算法,不過也可以使用hash-type修改此特性。 <scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag> 左半部分:/<path>;<params> 整個uri:/<path>;<params>?<query>#<frag> url_param:對用戶請求的uri聽<params>部分中的參數的值作hash計算,并由服務器總權重相除以后派發至某匹配的服務器;通常用于追蹤用戶,以確保來自同一個用戶的請求始終發往同一個Backend Server; hdr(<name>):對于每個http請求,此處由<name>指定的http首部將會被取出做hash計算; 并由服務器總權重相除以后派發至某匹配的服務器;沒有有效值的會被輪詢調度; hdr(Cookie) rdp-cookie rdp-cookie(<name>) 查詢每個進來的TCP請求并hash,該機制用于退化的持久連接,hash方式取決于hash_type; hash-type:哈希算法 定義用于將hash碼映射至后端服務器的方法;其不能用于frontend區段;可用方法有map-based和consistent,在大多數場景下推薦使用默認的map-based方法。 hash-type <method> <function> <modifier> map-based:除權取余法,哈希數據結構是靜態的數組; consistent:一致性哈希,哈希數據結構是一個樹; <function> is the hash function to be used : 哈希函數 sdbm djb2 wt6
指定后端主機
use_backend <backend> [{if | unless} <condition>] 當符合指定的條件時使用特定的backend; default_backend <backend> 定義一個名為<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*]:參數 maxconn <maxconn>:當前server的最大并發連接數; backlog <backlog>:當前server的連接數達到上限后的后援隊列長度; backup:設定當前server為備用服務器; check:對當前server做健康狀態檢測; addr :檢測時使用的IP地址; port :針對此端口進行檢測; inter <delay>:連續兩次檢測之間的時間間隔,默認為2000ms; rise <count>:連續多少次檢測結果為“成功”才標記服務器為可用;默認為2; fall <count>:連續多少次檢測結果為“失敗”才標記服務器為不可用;默認為3; 注意:httpchk,"smtpchk", "mysql-check", "pgsql-check" and "ssl-hello-chk" 用于定義應用層檢測方法;
統計接口啟用相關的參數:
stats enable 啟用統計頁;基于默認的參數啟用stats page; - stats uri : /haproxy?stats #默認,可自定義 - stats realm : "HAProxy Statistics" - stats auth : no authentication - stats scope : no restriction stats auth <user>:<passwd> 認證時的賬號和密碼,可使用多次; stats realm <realm> 認證時的realm; 提示 stats uri <prefix> 自定義stats page uri 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
maxconn <conns>:為指定的frontend定義其最大并發連接數;默認為2000; Fix the maximum number of concurrent connections on a frontend. mode { tcp|http|health } 定義haproxy的工作模式; tcp:基于layer4實現代理;可代理mysql, pgsql, ssh, ssl等協議; http:僅當代理的協議為http時使用; health:工作為健康狀態檢查的響應模式,當連接請求到達時回應“OK”后即斷開連接; 示例: listen ssh bind :22022 balance leastconn mode tcp server sshsrv1 172.16.100.6:22 check server sshsrv2 172.16.100.7:22 check cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ] <name>:is the name of the cookie which will be monitored, modified or inserted in order to bring persistence. rewirte:重寫; 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 option forwardfor [ except <network> ] [ header <name> ] [ if-none ] 允許在發往服務器的請求首部中插入“X-Forwarded-For”首部 Enable insertion of the X-Forwarded-For header to requests sent to servers 在由haproxy發往后端主機的請求報文中添加“X-Forwarded-For”首部,其值前端客戶端的地址;用于向后端主發送真實的客戶端IP; [ except <network> ]:請求報請來自此處指定的網絡時不予添加此首部; [ header <name> ]:使用自定義的首部名稱,而非“X-Forwarded-For”; errorfile <code> <file> 在用戶請求不存在的頁面時,返回一個頁面文件給客戶端而非由haproxy生成的錯誤代碼;可用于所有段中。Return a file contents instead of errors generated by HAProxy <code>:is the HTTP status code. Currently, HAProxy is capable of generating codes 200, 400, 403, 408, 500, 502, 503, and 504.指定對HTTP的哪些狀態碼返回指定的頁面 <file>:designates a file containing the full HTTP response.指定用于響應的頁面文件; 示例: errorfile 400 /etc/haproxy/errorfiles/400badreq.http errorfile 408 /dev/null # workaround Chrome pre-connect bug errorfile 403 /etc/haproxy/errorfiles/403forbid.http errorfile 503 /etc/haproxy/errorfiles/503sorry.http errorloc <code> <url> errorloc302 <code> <url> 請求錯誤時,返回一個HTTP重定向至某URL的信息;可用于所有配置段中。 errorfile 403 http://www.magedu.com/error_pages/403.html reqadd <string> [{if | unless} <cond>] Add a header at the end of the HTTP request rspadd <string> [{if | unless} <cond>] Add a header at the end of the HTTP response rspadd X-Via:\ HAPorxy reqdel <search> [{if | unless} <cond>] reqidel <search> [{if | unless} <cond>] (ignore case) Delete all headers matching a regular expression in an HTTP request rspdel <search> [{if | unless} <cond>] rspidel <search> [{if | unless} <cond>] (ignore case) Delete all headers matching a regular expression in an HTTP response rspidel Server.* 日志系統: log: 為每個實例啟用事件和流量日志,因此可用于所有區段 log global log <address> [len <length>] <facility> [<level> [<minlevel>]] no log 注意: 默認發往本機的日志服務器; (1) local2.* /var/log/local2.log (2) $ModLoad imudp $UDPServerRun 514 log-format <string>: 課外實踐:參考文檔實現combined格式的記錄 capture cookie <name> len <length> Capture and log a cookie in the request and in the response. capture request header <name> len <length> Capture and log the last occurrence of the specified request header. capture request header X-Forwarded-For len 15 capture response header <name> len <length> Capture and log the last occurrence of the specified response header. capture response header Content-length len 9 capture response header Location len 15 為指定的MIME類型啟用壓縮傳輸功能 compression algo <algorithm> ...:啟用http協議的壓縮機制,指明壓縮算法gzip, deflate; compression type <mime type> ...:指明壓縮的MIMI類型; 對后端服務器做http協議的健康狀態檢測: option httpchk option httpchk <uri> option httpchk <method> <uri> option httpchk <method> <uri> <version> 定義基于http協議的7層健康狀態檢測機制; http-check expect [!] <match> <pattern> Make HTTP health checks consider response contents or specific status codes. 連接超時時長: timeout client <timeout> #客戶端超時 Set the maximum inactivity time on the client side. 默認單位是毫秒; timeout server <timeout> #服務器端超時 Set the maximum inactivity time on the server side. timeout http-keep-alive <timeout> #設置http-keep-alive的超時時間 持久連接的持久時長; timeout http-request <timeout> #http請求超時時間 Set the maximum allowed time to wait for a complete HTTP request timeout connect <timeout> #連接超時 Set the maximum time to wait for a connection attempt to a server to succeed. timeout client-fin <timeout> 設置客戶端的不活動超時,半關閉連接 Set the inactivity timeout on the client side for half-closed connections. timeout server-fin <timeout> 設置服務器超時連接,半關閉連接 Set the inactivity timeout on the server side for half-closed connections. use_backend <backend> [{if | unless} <condition>] Switch to a specific backend if/unless an ACL-based condition is matched. 當符合指定的條件時使用特定的backend; block { if | unless } <condition> Block a layer 7 request if/unless a condition is matched acl invalid_src src 172.16.200.2 block if invalid_src errorfile 403 /etc/fstab #錯誤頁面顯示 errorloc 403 http://www.baidu.com #跳轉機制 http-request { allow | deny } [ { if | unless } <condition> ] Access control for Layer 7 requests tcp-request connection {accept|reject} [{if | unless} <condition>] Perform an action on an incoming connection depending on a layer 4 condition 示例: 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:
acl
acl: The use of Access Control Lists (ACL) provides a flexible solution to perform content switching and generally to take decisions based on content extracted from the request, the response or any environmental status. haproxy的ACL用于實現基于請求報文的首部、響應報文的內容或其它的環境狀態信息來做出轉發決策,這大大增強了其配置彈性。其配置法則通常分為兩步,首先去定義ACL,即定義一個測試條件,而后在條件得到滿足時執行某特定的動作,如阻止請求或轉發至某特定的后端。定義ACL的語法格式如下。 acl <aclname> <criterion> [flags] [operator] [<value>] ... <aclname>:ACL names must be formed from upper and lower case letters, digits, '-' (dash), '_' (underscore) , '.' (dot) and ':' (colon).ACL names are case-sensitive. <value>的類型:acl測試條件支持的值有以下四類: - boolean - integer or integer range - IP address / network - string (exact, substring, suffix, prefix, subdir, domain) - regular expression - hex block 16進制 <flags> -i : 不區分中模式字符的大小寫; ignore case during matching of all subsequent patterns. -m : use a specific pattern matching method -n : forbid the DNS resolutions -u : force the unique id of the ACL -- : 標志符的強制結束標記,在模式中的字符串像標記符時使用; force end of flags. Useful when a string looks like one of the flags. [operator] 匹配整數值:eq、ge、gt、le、lt 匹配字符串: - exact match (-m str) : the extracted string must exactly match the patterns ; - substring match (-m sub) : the patterns are looked up inside the extracted string, and the ACL matches if any of them is found inside ; - prefix match (-m beg) : the patterns are compared with the beginning of the extracted string, and the ACL matches if any of them matches. - suffix match (-m end) : the patterns are compared with the end of the extracted string, and the ACL matches if any of them matches. - subdir match (-m dir) : the patterns are looked up inside the extracted string, delimited with slashes ("/"), and the ACL matches if any of them matches. - domain match (-m dom) : the patterns are looked up inside the extracted string, delimited with dots ("."), and the ACL matches if any of them matches. acl作為條件時的邏輯關系: - AND (implicit) - OR (explicit with the "or" keyword or the "||" operator) - Negation with the exclamation mark ("!") if invalid_src invalid_port if invalid_src || invalid_port if ! invalid_src invalid_port <criterion> : dst : ip dst_port : integer src : ip src_port : integer acl invalid_src src 172.16.200.2 #拒絕該IP訪問 path : string This extracts the request's URL path, which starts at the first slash and ends before the question mark (without the host part). /path;<params> 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 This extracts the request's URL as presented in the request. A typical use is with prefetch-capable caches, and with portals which need to aggregate multiple information from databases and keep them in caches. 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 This extracts the last occurrence of header <name> in an HTTP request. 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 Returns an integer containing the HTTP status code in the HTTP response. Pre-defined ACLs ACL name Equivalent to Usage FALSE always_false never match HTTP req_proto_http match if protocol is valid HTTP HTTP_1.0 req_ver 1.0 match HTTP version 1.0 HTTP_1.1 req_ver 1.1 match HTTP version 1.1 HTTP_CONTENT hdr_val(content-length) gt 0 match an existing content-length HTTP_URL_ABS url_reg ^[^/:]*:// match absolute URL with scheme HTTP_URL_SLASH url_beg / match URL beginning with "/" HTTP_URL_STAR url * match URL equal to "*" LOCALHOST src 127.0.0.1/8 match connection from local host METH_CONNECT method CONNECT match HTTP CONNECT method 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 TRUE always_true always match WAIT_END wait_end wait for end of content analysis HAProxy:global, proxies(fronted, backend, listen, defaults) balance: roundrobin, static-rr leastconn first source hdr(<name>) uri (hash-type) url_param Nginx調度算法:ip_hash, hash, leastconn, lvs調度算法: rr/wrr/sh/dh, lc/wlc/sed/nq/lblc/lblcr ****基于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
配置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 如何向后端傳遞用戶請求的協議和端口 http_request set-header X-Forwarded-Port %[dst_port] http_request add-header X-Forwared-Proto https if { ssl_fc }
haproxy配置文檔路徑:http://cbonte.github.io/haproxy-dconv/
原創文章,作者:Mr-Xiao,如若轉載,請注明出處:http://www.www58058.com/76124