在企業生產環境中,天天會有不少的需求變動,好比增長服務器、新業務上線、url路由修改、域名配置等等,對於前端負載均衡設備來講,容易維護,複雜度低,是首選指標。在企業中,穩定壓倒一切,與其搞得很複雜,常常出問題,不如作的簡單和穩定。php
在企業中,90%以上的故障,來源於需求變動。多是程序bug,也多是人爲故障,也多是架構設計問題等等。前端負載均衡設備爲重中之重,在軟件選型上必定充分考慮,能知足業務的前提下,儘量下降複雜度,提升易維護性。css
經過分析IP層及TCP/UDP層的流量實現的基於"IP+端口"的負載均衡。mysql
能夠根據內容,再配合負載均衡算法來選擇後端服務器,不但能夠根據"ip+端口"方式進行負載分流,還能夠根據網站的URL,訪問域名,瀏覽器類別,語言等決定負載均衡的策略。七層負載均衡模式下,負載均衡與客戶端及後端的服務器會分別創建一次TCP鏈接,而在四層負載均衡模式下(DR),僅創建一次TCP鏈接;七層負載均衡對負載均衡設備的要求更高,處理能力也低於四層負載均衡。nginx
(1)HAProxy是一個使用C語言編寫的自由及開放源代碼軟件,其提供高性能性、負載均衡,以及基於TCP和HTTP的應用程序代理。相較與 Nginx,HAProxy 更專一與反向代理,所以它能夠支持更多的選項,更精細的控制,更多的健康狀態檢測機制和負載均衡算法。
(2)HAProxy特別適用於那些負載特大的web站點,這些站點一般又須要會話保持或七層處理。HAProxy運行在當前的硬件上,徹底能夠支持數以萬計的併發鏈接。而且它的運行模式使得它能夠很簡單安全的整合進您當前的架構中, 同時能夠保護你的web服務器不被暴露到網絡上。
(3)包括 GitHub、Bitbucket、Stack Overflow、Reddit、Tumblr、Twitter在內衆多知名網站,及亞馬遜網絡服務系統都使用了HAProxy
HAProxy 是TCP / HTTP 反向代理服務器,尤爲適合於高可用性環境
① 能夠針對HTTP 請求添加cookie ,進行路由後端服務器
⑩ 支持http 反向代理,支持動態程序的反向代理,支持基於數據庫的反向代理
① 可靠性與穩定性都很是出色,可與硬件級設備媲美。
② 支持鏈接拒絕,能夠用於防止DDoS攻擊
③ 支持長鏈接、短鏈接和日誌功能,可根據須要靈活配置
④ 路由HTTP請求到後端服務器,基於cookie做會話綁定;同時支持經過獲取指的url來檢測後端服務器的狀態
⑤ HAProxy還擁有功能強大的ACL支持,可靈活配置路由功能,實現動靜分離,在架構設計與實現上帶來很大方便
⑥ 可支持四層和七層負載均衡,幾乎能爲全部服務常見的提供負載均衡功能
⑦ 擁有功能強大的後端服務器的狀態監控web頁面,能夠實時瞭解設備的運行狀態,還可實現設備上下線等簡單操做。例:cobbler、samba、httpd
⑧ 支持多種負載均衡調度算法,而且也支持session保持。
(1)Haproxy安裝經常使用兩種方式,yum安裝和源碼包安裝
(2)yum 安裝:一般是在線安裝,好處是安裝方式簡單,不易出錯;經常使用的安裝yum源爲epel
(3)源碼包安裝:是先將 Haproxy 的源碼下載下來,在本身的系統裏編譯生成可執行文件,而後執行,好處是由於是在本身的系統上編譯的,更符合本身系統的性能,也就是說在本身的系統上執行 Haproxy服務性能效率更好。
主配置文件:/etc/haproxy/haproxy.cfg
Unit file:/usr/lib/systemd/system/haproxy.service(centos7)
Init.file :/etc/init.d/haproxy (centos6)
全局設定(globalsettings)和 對代理的設定(proxies)
(1)global settings:主要用於定義haproxy進程管理安全及性能相關的參數
(2)proxies共分爲4段:defaults,frontend,backend,listen
① defaults <name>:爲其它配置段提供默認參數,下面的段能夠繼承默認參數;默認配置參數可由下一個"defaults"從新設定。
② frontend <name>:定義一系列監聽的套接字,這些套接字可接受客戶端請求並與之創建鏈接。能夠監聽多個端口,例:監聽80和3306端口,80請求給後端的web服務器,3306請求給後端的數據庫服務器
③ backend <name>:定義"後端"服務器,前端代理服務器將會把客戶端的請求調度至這些服務器。
④ listen <name>:定義監聽的套接字和後端的服務器。相似於將frontend和backend段放在一塊兒,適用於一對一環境
① 後端的real server能夠屬於多個backend組,一個backend能夠包括一個或多個real server
① nbproc <number> 要啓動的haproxy 的進程數量,系統默認單進程,要求使用daemon 模式;和linux的cpu數相關,lscpu能夠查看cpu數
② ulimit-n <number> 每一個haproxy 進程可打開的最大文件數,系統自動會指定,不建議設置
① vim /etc/rsyslog.conf 在日誌服務的配置文件中自定義一條存放haproxy 日誌的設置
service rsyslog restart 重啓日誌服務
log 172.17.22.22 local2 日誌存放在遠程服務器上
capture cookie <name> len <length>
capture request header <name> len <length>
示例:capture request header X-Forwarded-For len 15
capture response header <name> len <length>
capture response header Content-length len 9
capture response header Location len 15
① maxconn <number>: 設置每一個haproxy 進程所能接受的最大併發鏈接數
② maxconnrate <number> :設置每一個進程每秒種所能創建的最大鏈接數量,速率,一個鏈接裏能夠有多個會話,也能夠沒有會話
③ maxsessrate <number> :設置每一個進程每秒種所能創建的最大會話數量
④ maxsslconn <number>:每進程支持SSL 的最大鏈接數量
⑤ spread-checks <0..50, in percent>:健康檢測延遲時長比建議2-5 之間
global log 127.0.0.1 local2 chroot /var/lib/haproxy pidfile /var/run/haproxy.pid maxconn 40000 user haproxy group haproxy daemon stats socket /var/lib/haproxy/stats
defaults mode http #實現http的7層規則 log global #日誌定義 option httplog #啓用日誌記錄HTTP請求,默認haproxy日誌記錄是不記錄HTTP請求 option dontlognull #日誌中將不會記錄空鏈接。 option httpclose # 強制短鏈接,每次收發完包後都把鏈接關閉 option forwardfor #添加xforward日誌標記 retries 3 # 定義鏈接後端服務器的失敗重連次數 timeout http-request 10s # 請求超時 timeout queue 1m #隊列超時 timeout connect 10s #鏈接超時 timeout client 1m #客戶端超時
"frontend"段用於定義一系列監聽的套接字,這些套接字可接受客戶端請求並與之創建鏈接
例:frontend main *:5000 acl url_static path_beg -i /static /images /javascript/stylesheets acl url_static path_end -i .jpg .gif .png .css .js use_backend static if url_static default_backend app
"backend"段用於定義一系列"後端"服務器,代理將會將對應客戶端的請求轉發至這些服務器。
例:backend app balance roundrobin server app1 127.0.0.1:5001 check server app2 127.0.0.1:5002 check server app3 127.0.0.1:5003 check server app4 127.0.0.1:5004 check
listen段經過關聯"前端"和"後端"定義了一個完整的代理,frontend和backend 塊的結合體
bind [<address>]:<port_range> [, ...] 多個能夠以,隔開
bind [<address>]:<port_range> [, ...] interface <interface>
(2)此指令僅能用於frontend和listen區段,用於定義一個或幾個監聽的套接字。
① <address>:可選選項,其能夠爲主機名、IPv4地址、IPv6地址或*;省略此選項、將其指定爲*或0.0.0.0時,將監聽當前系統的全部IPv4地址;
② <port_range>:能夠是一個特定的TCP端口,也但是一個端口範圍(如5005-5010),代理服務器將經過指定的端口來接收客戶端請求;須要注意的是,每組監聽的套接字
③ <address:port>在同一個實例上只能使用一次,並且小於1024的端口須要有特定權限的用戶才能使用,這可能須要經過uid參數來定義;
④ <interface>:指定物理接口的名稱,僅能在Linux系統上使用;其不能使用接口別名,而僅能使用物理接口名稱,並且只有管理有權限指定綁定的物理接口;
bind 10.0.0.1:10080,10.0.0.1:10443
設定實例的運行模式或協議。當實現內容交換時,前端和後端必須工做於同一種模式(通常說來都是HTTP模式),不然將沒法啓動實例。能夠放在任何4段中 default frontent backent listen
① tcp:實例運行於純TCP模式,在客戶端和服務器端之間將創建一個全雙工的鏈接,且不會對7層報文作任何類型的檢查,一般用於SSL、SSH、SMTP等應用;
② http:實例運行於HTTP模式,7層,客戶端請求在轉發至後端服務器以前將被深度分析,全部不與RFC格式兼容的請求都會被拒絕;centos實際默認模式
③ health:實例工做於health模式,其對入站請求僅響應"OK"信息並關閉鏈接,且不會記錄任何日誌信息;此模式將用於響應外部組件的健康狀態檢查請求;目前來說,此模式已經廢棄,由於tcp或http模式中的monitor關鍵字可完成相似功能;能夠用於測試
tcp-request connection {accept|reject} [{if | unless} <condition>] 根據第4層條件對傳入鏈接執行操做
格式:balance <algorithm> [ <arguments> ]
定義負載均衡算法,可用於"defaults"、"listen"和"backend"。<algorithm>用於在負載均衡場景中挑選一個server,其僅應用於用戶新請求或須要將一個鏈接從新派發至另外一個服務器時。支持的算法有:
① roundrobin:基於權重進行輪叫,在服務器的處理時間保持均勻分佈時,這是最平衡、最公平的算法。此算法是動態的,這表示其權重能夠在運行時進行調整,不過,在設計上,每一個後端服務器僅能最多接受4128個鏈接;
特色:動態算法,支持權重的運行時調整,支持慢啓動;每一個後端backend 中最多支持4095 個server,有上限
② static-rr:基於權重進行輪叫,與roundrobin相似,可是爲靜態方法,在運行時調整其服務器權重不會生效;不過,其在後端服務器鏈接數上沒有限制;
特色:靜態算法,不支持權重的運行時調整及,不支持慢啓動(很差用);後端主機數量無上限
③ leastconn:新的鏈接請求被派發至具備最少鏈接數目的後端服務器;在有着較長時間會話的場景中推薦使用此算法,如LDAP、SQL數據庫等,其並不太適用於較短會話的應用層協議
④ first:根據服務器在列表中的位置,自上而下進行調度;前面服務器的鏈接數達到上限,新請求才會分配給下一臺服務;
⑤ source :源地址hash,新鏈接先按權重分配,後續鏈接按source 分配請求,用的很少
⑥ uri:對URI 的左半部分或整個uri 作hash 計算,併除以服務器總權重取模,之後派發至某挑出的服務器,適用於後端緩存服務器
例:<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
整個uri :/<path>;<params>?<query>#<frag>
⑦ url_param:對用戶請求的uri 中的<params> 部分中的參數的值做hash 計算,並由服務器總權重相除之後派發至某挑出的服務器;一般用於追蹤用戶,以確保來自同一個用戶的請求始終發往同一個Backend Server
例:http://www.magedu.com/bbs/hello;type=title (這個參數至關於用戶的id)
hdr(<name>) :對於每一個http 請求,此處由<name> 指定的http 首部將會被取出作hash; 計算; 並由服務器總權重相除之後派發至某挑出的服務器; 無有效值的會被輪詢調度 hdr(Cookie)
server <name> <address>[:[port]] [param*]
① <name> :服務器在haproxy 上的內部名稱;出如今日誌及警告信息;若是設定了"http-send-server-name",它還將被添加至發往此服務器的請求首部中;
② <address> :服務器地址,支持使用主機名,只不過在啓動時須要解析主機名至相應的IPv4地址;
③ [:[port]] :指定將鏈接請求所發往的此服務器時的目標端口,其爲可選項;未設定時,將使用客戶端請求時的同一相端口;
④ [param*] :參數,下面僅說明幾個經常使用的參數;
① weight <weight>:權重,默認爲1,最大值爲256,0表示不參與負載均衡;
② backup:設定爲備用服務器,僅在負載均衡場景中的其它server均不可用於啓用此server;
③ check:啓動對此server執行健康狀態檢查,其能夠藉助於額外的其它參數完成更精細的設定,如:
addr:檢測時使用的IP 地址,能夠不爲real server的ip
inter <delay>:設定健康狀態檢查的時間間隔,單位爲毫秒,默認爲2000;也可使用fastinter和downinter來根據服務器端狀態優化此時間延遲;
rise <count>:設定健康狀態檢查中,某離線的server從離線狀態轉換至正常狀態須要成功檢查的次數;
fall <count>:確認server從正常狀態轉換爲不可用狀態須要檢查的次數;
例: backend lnmp-server balance roundrobin server sorryserver 172.17.1.6:80 backup server lnmpserver1 172.17.1.7:80 weight 1 check inter 3000 rise 3 fall server lnmpserver2 172.17.22.22:80 weight 2 check inter 3000 rise 3 fall
④ cookie <value>:爲指定server設定cookie值,此處指定的值將在請求入站時被檢查,第一次爲此值挑選的server將在後續的請求中被選中,其目的在於實現持久鏈接的功能;
cookie SRV insert nocache 先定義,下邊才能使用;insert插入報文首部,nocache不緩存,安全 server lnmpserver2 172.17.1.7:80 check inter 3000 rise 3 fall 5 cookie srv1 server lnmpserver2 172.17.22.22:80 check inter 3000 rise 3 fall 5 cookie srv2
注意:curl 測試需加-b SRV= 指定的對應cookie訪問,如:curl -b SRV=srv1 172.17.11.11
⑤ maxconn <maxconn>:指定此服務器接受的最大併發鏈接數;若是發往此服務器的鏈接數目高於此處指定的值,其將被放置於請求隊列,以等待其它鏈接被釋放;
注意:此處是放在backend 段的server 後,是後端服務器的最大併發鏈接數;
⑥ maxqueue <maxqueue>:設定請求隊列的最大長度;
⑦ backlog <backlog> :當server 的鏈接數達到上限後的後援隊列長度
⑧ observe <mode>:經過觀察服務器的通訊情況來斷定其健康狀態,默認爲禁用,其支持的類型有"layer4"和"layer7","layer7"僅能用於http代理場景;
⑨ redir <prefix>:啓用重定向功能,將發往此服務器的GET和HEAD請求均以302狀態碼響應;須要注意的是,在prefix後面不能使用/,且不能使用相對地址,以避免形成循環;
例如:server srv1 172.16.100.6:80 redir http://www.baidu.com
若用curl查詢,記得加-L 跳轉;curl -L 172.17.11.11
能夠放在任何4段中 default frontent backent listen
stats enable #啓用統計頁;基於默認的參數啓用stats page stats uri /haproxy?stats(默認值) #自定義stats page uri stats hide-version #隱藏統計報告版本信息 stats realm HAProxy\ Statistics #頁面登錄信息 stats auth user:passwd #驗證帳號和密碼信息 stats refresh 20s #設定自動刷新時間間隔 stats admin if TRUE #若是驗證經過,啓用stats page 中的管理功能
打開狀態訪問頁面 http://192.168.30.6:9527/haproxy?admin
對後端服務器作http 協議健康狀態檢測:一般用於backend
在default、backend、listen使用,禁止在frontend使用
option httpchk 默認爲:/ OPTIONS HTTP/1.0
option httpchk <method> <uri> <version>
http-check expect [!] <match> <pattern> 指望獲得的 http協議健康狀態檢測響應內容或指定響應碼
option httpchk GET /index.html HTTP/1.1\r\nhost: #檢測後端的index.html頁面,構造響應報文首部,HTTP/1.1 協議版本,/n換行
http-check expect status 200 #返回的響應碼爲200是正常,接受不到200,就再也不給後端server調度
(1)分析:後端收到服務的請求是haproxy的,因此日誌記錄的請求ip也是haproxy的;如咱們想要記錄真實client 的ip,需加forwardfor 選項;
在由haproxy 發日後端主機的請求報文中添加"X-Forwarded-For" 首部,其值爲前端客戶端的地址;用於向後端主發送真實的客戶端IP
option forwardfor [ except <network> ] [ header <name> ] [ if-none ]
[ except <network> ] :請求報請來自此處指定的網絡時不予添加此首部,如haproxy 自身所在網絡
[ header <name> ] :使用自定義的首部名稱,而非默認的"X-Forwarded-For"
[ if-none ] 若是沒有首部才添加首部,若是有使用默認值
compression algo <algorithm> ... :啓用http 協議的壓縮機制,指明壓縮算法gzip, deflate
compression type <mime type> ... :指明壓縮的MIMI 類型
(4)例:option forwardfor except 127.0.0.0/8
還需在nginx、httpd服務的日誌格式中加上"$http_x_forwarded_for" ,才能記錄client 的ip
(1)errorfile <code> <file> 自定義做爲頁面
支持200, 400, 403, 408, 500, 502, 503, 504.
<file> :錯誤頁文件路徑,固然,需在haproxy上事先準備好
mkdir /etc/haproxy/error_pages
echo Custom ERROR 503 > /etc/haproxy/error_pages/503.html 定製503錯誤
errorfile 503 /etc/haproxy/error_pages/503.html
(2)errorloc <code> <url> 重定向到其餘頁面
至關於errorloc302 <code> <url> ,利用302 重定向至指URL
errorloc 503 http://www.baidu.com/error_pages/503.html
reqadd <string> [{if | unless} <cond>]
rspadd <string> [{if | unless} <cond>]
示例:reqadd X-via:\ haproxy01 \ 轉譯空格
在後端server nginx上日誌格式加上這條 "$http_x_via"
rspadd Server:\ alonginx 僞造報文首部,加個假的版本信息
reqdel <search> [{if | unless} <cond>]
reqidel <search> [{if | unless} <cond>] i不分大小寫
rspdel <search> [{if | unless} <cond>]
rspidel <search> [{if | unless} <cond>] 不分大小寫
示例: rspidel server.* 刪除報文首部的版本信息
③ timeout http-keep-alive <timeout>
④ timeout http-request <timeout>
⑥ timeout client-fin <timeout>
⑦ timeout server-fin <timeout>
acl:訪問控制列表,用於實現基於請求報文的首部、響應報文的內容或其它的環境狀態信息來作出轉發決策,這大大加強了其配置彈性。其配置法則一般分爲兩步,首先去定義ACL ,即定義一個測試條件,然後在條件獲得知足時執行某特定的動做,如阻止請求或轉發至某特定的後端。
acl <aclname> <criterion> [flags] [operator] [<value>] ...
① <aclname> 必須:ACL 名稱,區分字符大小寫,且其只能包含大小寫字母、數字、-( 鏈接線) 、_( 下劃線) 、.( 點號) 和:( 冒號) ;haproxy 中,acl 能夠重名,重名是或的關係
② <criterion> 必須:測試標準,即對什麼信息發起測試;測試方式能夠由[flags] 指定的標誌進行調整;而有些測試標準也能夠須要爲其在<value> 以前指定一個操做符[operator]
-u 強制每一個ACL 必須 惟一ID ,不然多個同名ACL 或關係
-- 強制flag 結束. 當字符串和某個flag 類似時使用
- 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 進行
- string (exact, substring, suffix, prefix, subdir, domain)
(1) base : string 返回第一個主機頭和請求的路徑部分的鏈接,該請求從第一個斜槓開始,並在問號以前結束, 對虛擬主機有用
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
base : exact string match 確切的字符串匹配
base_reg : regex match 正則表達式匹配
base_sub : substring match 子串匹配
(2) path : string 提取請求的URL 路徑,該路徑從第一個斜槓開始,並在問號以前結束(無主機部分)
<scheme>://<user>:<password>@<host>:<port>/<path>;<params>?<query>#<frag>
① acl adminpath path_beg /admin 以admin開頭的
block if deny_src adminpath 都拒絕訪問
② acl imagefile path_end -i .bmp .jpg .png .gif .jpeg 以圖片後綴結尾的,不區分大小寫
use_backend imagesrvs if imagefile 都給imagesrvs 爲名的backend後端server 處理
(3) url : string 提取請求中的URL。一個典型的應用是具備預取能力的緩存,以及須要從數據庫聚合多個信息並將它們保存在緩存中的網頁門戶入口
(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 子串匹配
① acl bad_curl hdr_sub(User-Agent) -i curl 以curl 訪問的
② acl phphost hdr(host) php.magedu.com 訪問php的域名
use_backend srvs1 if wwwhost 都給對應的後端server組處理
四、引用執行acl 的設置
① use_backend <backend> [{if | unless} <condition>]
當if/unless 一個基於ACL 的條件匹配時切換指定backend
② block { if | unless } <condition> 阻止7 層請求if/unless 一個條件匹配
③ http-request { allow | deny |add-header <name> <fmt> |set-header <name> <fmt> } [ { if | unless } <condition> ] 對7 層請求的訪問控制
例:acl deny_method method HEAD 訪問我首部的請求,就是curl -I
http-request deny if deny_method 拒絕
④ tcp-request connection {accept|reject} [{if | unless} <condition>] 根據第4層條件對傳入鏈接執行操做