一、Haproxy簡介
1、Haproxy的介紹
HAProxy是法國開發者Willy Tarreau開發的一個開源軟件,是一款具備高並發、高性能的TCP和HTTP負載均衡器,支持基於cookie的持久性,自動故障切換,支持正則表達式及web狀態統計。
2、Haproxy的功能
HAProxy是TCP/HTTP反向代理服務器,尤其適合於高可用性高並發環境
• 可以針對HTTP請求添加cookie,進行路由后端服務器
• 可平衡負載至后端服務器,並支持持久連接
• 支持基於cookie進行調度
• 支持所有主服務器故障切換至備用服務器
• 支持專用端口實現監控服務
• 支持不影響現有連接情況下停止接受新連接請求
• 可以在雙向添加,修改或刪除HTTP報文首部
• 支持基於pattern實現連接請求的訪問控制
• 通過特定的URI為授權用戶提供詳細的狀態信息
二、Haproxy安裝
1、編譯安裝過程
(1) 准備源碼包,可到官網下載 https://www.haproxy.org
[root@centos7 ~]# ll haproxy-1.8.20.tar.gz -rw-r--r-- 1 root root 2083917 Jan 10 20:39 haproxy-1.8.20.tar.gz
(2) 安裝相應依賴包
[root@centos7 ~]# yum install -y gcc gcc-c++ pcre pcre-devel openssl openssl-devel systemd-devel
(3) 解壓源碼包,並進行編譯
[root@centos7 ~]# tar -zxvf haproxy-1.8.20.tar.gz [root@centos7 ~]# cd haproxy-1.8.20/ [root@centos7 haproxy-1.8.20]# make ARCH=x86_64 TARGET=linux2628 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy [root@centos7 haproxy-1.8.20]# make install PREFIX=/usr/local/haproxy [root@centos7 haproxy-1.8.20]# cp haproxy /usr/sbin/
(4) 創建啟動腳本
[root@centos7 haproxy-1.8.20]# vim /usr/lib/systemd/system/haproxy.service [Unit] Description=HAProxy Load Balancer After=syslog.target network.target [Service] ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /usr/local/haproxy/run/haproxy.pid ExecReload=/bin/kill -USR2 $MAINPID [Install] WantedBy=multi-user.target
(5) 創建用戶與相關目錄以及配置文件
[root@centos7 haproxy-1.8.20]# useradd -r -s /sbin/nologin haproxy [root@centos7 haproxy-1.8.20]# mkdir /etc/haproxy [root@centos7 haproxy-1.8.20]# mkdir /usr/local/haproxy/run [root@centos7 haproxy-1.8.20]# mkdir /var/lib/haproxy [root@centos7 haproxy-1.8.20]# chown -R haproxy:haproxy /var/lib/haproxy/ [root@centos7 haproxy-1.8.20]# vim /etc/haproxy/haproxy.cfg

[root@centos7 haproxy-1.8.20]# cat /etc/haproxy/haproxy.cfg global maxconn 100000 chroot /usr/local/haproxy #stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin #uid 981 #gid 981 user haproxy group haproxy daemon #nbproc 4 #cpu-map 1 0 #cpu-map 2 1 #cpu-map 3 2 #cpu-map 4 3 pidfile /usr/local/haproxy/run/haproxy.pid log 127.0.0.1 local3 info defaults option http-keep-alive option forwardfor maxconn 100000 mode http timeout connect 300000ms timeout client 300000ms timeout server 300000ms listen stats mode http bind 0.0.0.0:9999 stats enable log global stats uri /haproxy-status stats auth haadmin:q1w2e3r4ys listen web_port bind 0.0.0.0:80 mode http log global server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5
(6) 啟動haproxy服務
[root@centos7 haproxy-1.8.20]# systemctl start haproxy [root@centos7 haproxy-1.8.20]# ps -ef|grep haproxy root 58693 1 0 23:29 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /usr/local/haproxy/run/haproxy.pid haproxy 58697 58693 0 23:29 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /usr/local/haproxy/run/haproxy.pid root 58708 6403 0 23:29 pts/0 00:00:00 grep --color=auto haproxy
三、Haproxy配置項解析
1、global 全局配置段
• chroot #鎖定運行目錄 • deamon #以守護進程運行 • stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin #socket文件 • user, group, uid, gid #運行haproxy的用戶身份 • nbproc #開啟的haproxy進程數,與CPU保持一致 • nbthread #指定每個haproxy進程開啟的線程數,默認為每個進程一個線程 • cpu-map 1 0 #綁定haproxy 進程至指定CPU • maxconn #每個haproxy進程的最大並發連接數 • maxsslconn #SSL每個haproxy進程ssl最大連接數 • maxconnrate #每個進程每秒最大連接數 • spread-checks #后端server狀態check隨機提前或延遲百分比時間,建議2-5(20%-50%)之間 • pidfile #指定pid文件路徑 • log 127.0.0.1 local3 info #定義全局的syslog服務器;最多可以定義兩個
2、proxies 代理配置段
defaults [<name>] #默認配置項,針對以下的frontend、backend和listen生效,可以多個name
• option redispatch #當server Id對應的服務器掛掉后,強制定向到其他健康的服務器 • option abortonclose #當服務器負載很高的時候,自動結束掉當前隊列處理比較久的鏈接 • option http-keep-alive 60 #開啟會話保持 • option forwardfor #開啟IP透傳 • mode http #默認工作類型 • timeout connect 60s #轉發客戶端請求到后端server的最長連接時間(TCP之前) • timeout server 600s #轉發客戶端請求到后端服務端的超時超時時長(TCP之后) • timeout client 600s #與客戶端的最長空閑時間 • timeout http-keep-alive 120s #session 會話保持超時時間,范圍內會轉發到相同的后端服務器 • timeout check 5s #對后端服務器的檢測超時時間,一般在服務器組配置
frontend <name> #前端servername,類似於Nginx的一個虛擬主機server
• bind [<address>]:<port_range> [, ...] [param*] #指定HAProxy的監聽地址,可以是IPV4或IPV6,可以同時監聽多個IP或端口,可同時用於listen字段中 • mode http/tcp #指定負載協議類型 • use_backend backend_name #調用的后端服務器組名稱
示例:
frontend WEB_PORT bind 192.168.27.7:80 mode tcp use_backend backend_name
backend <name> #后端服務器組,等於Nginx的upstream
• mode http/tcp #指定負載協議類型 • option #配置選項,可加httpchk,smtpchk, mysql-check, pgsql-check,ssl-hello-chk等方法,可用於實現更多應用層檢測功能 • server #定義后端real server,后可接 check 對指定real進行健康狀態檢查,默認不開啟
check #對指定real server進行健康狀態檢查,默認不開啟 • addr IP #可指定的健康狀態監測IP • port num #指定的健康狀態監測端口 • inter num #健康狀態檢查間隔時間,默認2000 ms • fall num #后端服務器失效檢查次數,默認為3 • rise num #后端服務器從下線恢復檢查次數,默認為2 • weight #默認為1,最大值為256,0表示不參與負載均衡 • backup #將后端服務器標記為備份狀態 • disabled #將后端服務器標記為不可用狀態 • redirect prefix http://www.xxx.com/ #將請求臨時重定向至其它URL,只適用於http模式 • mbacklog axconn <maxconn> #當前后端server的最大並發連接數 • <backlog> #當server的連接數達到上限后的后援隊列長度

frontend WEB_PORT_80 bind 192.168.27.7:80 mode http use_backend web_prot_http_nodes backend web_prot_http_nodes mode http option forwardfor server web1 192.168.27.17:8080 weight 1 check inter 3000 fall 3 rise 5 server web2 192.168.27.27:8080 weight 1 check inter 3000 fall 3 rise 5 server web2 192.168.27.37:8080 check inter 3000 fall 3 rise 5 backup
listen <name> #將 frontend 和 backend 合並在一起配置
listen WEB_PORT_80 bind 192.168.27.7:80 mode http option forwardfor server web1 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server web2 192.168.27.27:8080 check inter 3000 fall 3 rise 5
注:name字段只能使用 " - "、" _ "、" . "、" : ",並且嚴格區分大小寫。
四、Haproxy的調度算法
通過 balance 指明對后端服務器的調度算法,配置在listen或backend。調度算法有以下幾種:
1、first
根據服務器在列表中的位置,自上而下進行調度,但是其只會當第一台服務器的連接數達到上限,新請求才會分配給下一台服務,因此會忽略服務器的權重設置;
listen web_prot_http_nodes bind 192.168.27.7:80 mode http #可以為tcp或http balance first option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
2、static-rr
基於權重的輪詢靜態調度算法,不支持權重的運行時調整及后端服務器慢啟動,其后端主機數量沒有限制;
listen web_prot_http_nodes bind 192.168.27.7:80 mode http #可以為tcp或http balance static-rr option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
3、roundrobin
基於權重的輪詢動態調度算法,支持權重的運行時調整,不等於lvs 的 rr,支持慢啟動即新加的服務器會逐漸增加轉發數,每個后端backend中最多支持4095個server,此為默認調度算法;
listen web_prot_http_nodes bind 192.168.27.7:80 mode http #可以為tcp或http balance rountrobin option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
4、leastconn
加權的最少連接動態調度算法,支持權重的運行時調整和慢啟動,即當前后端服務器連接最少的優先調度,比較適合長連接的場景使用,比如MySQL等場景;
listen web_prot_http_nodes bind 192.168.27.7:80 mode http #可以為tcp或http balance leastconn option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
5、source
源地址hash,基於用戶源地址hash並將請求轉發到后端服務器,默認為靜態即取模方式,但是可以通過hash-type支持的選項更改,后續同一個源地址請求將被轉發至同一個后端web服務器,比較適用於session保持/緩存業務等場景;
• map-based:取模法,基於服務器權重的hash數組取模,該hash是靜態的即不支持在線調整權重,不支持慢啟動,其對后端服務器調度均衡,缺點是當服務器的總權重發生變化時,即有服務器上線或下線,都會因權重發生變化而導致調度結果整體改變;
• consistent:一致性哈希,該hash是動態的,支持在線調整權重,支持慢啟動,優點在於當服務器的總權重發生變化時,對調度結果影響是局部的,不會引起大的變動;
listen web_prot_http_nodes bind 192.168.27.7:80 mode http #可以為tcp或http balance source hash-type consistent option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
6、uri
基於對用戶請求的uri做hash並將請求轉發到后端指定服務器;
• map-based:取模法
• consistent:一致性哈希
listen web_prot_http_nodes bind 192.168.27.7:80 mode http #只能是http balance uri hash-type consistent option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
7、url_param
對用戶請求的url中的<params>部分中的參數name作hash計算,並由服務器總權重相除以后派發至某挑出的服務器;通常用於追蹤用戶,以確保來自同一個用戶的請求始終發往同一個Backend Server;
假設url=http://www.xx.com/index.php?k1=v1&k2=v2,則url_param="k1=v1&k2=v2";
• map-based:取模法
• consistent:一致性哈希
#假設url=http://192.168.27.7/index.html?name=tom listen web_prot_http_nodes bind 192.168.27.7:80 mode http #只能是http balance url_param hash-type consistent option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
8、hdr
針對用戶每個http頭部(header)請求中的指定信息做hash,此處由<name>指定的http首部將會被取出並做hash計算,然后由服務器總權重相除以后派發至某挑出的服務器,假如無有效的值,則會被輪詢調度;
• map-based:取模法
• consistent:一致性哈希
listen web_prot_http_nodes bind 192.168.27.7:80 mode http #只能是http balance hdr(User_Agent) hash-type consistent option forwardfor server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
9、rdp-cookie
對遠程桌面的負載,使用cookie保持會話;
• map-based:取模法
• consistent:一致性哈希
listen RDP bind 192.168.27.7:3389 mode tcp #只能是tcp balance rdp_cookie hash-type consistent option forwardfor server 192.168.27.17 192.168.27.17:3389 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:3389 check inter 3000 fall 3 rise 5
五、部分配置實例
1、基於cookie實現的session保持
cookie <value>:為當前server指定cookie值,實現基於cookie的會話黏性
cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
<name>:cookie名稱,用於實現持久連接
rewrite:重寫
insert:插入
prefix:前綴
nocache:當client和hapoxy之間有緩存時,不緩存cookie
listen web_prot_http_nodes bind 192.168.27.7:80 mode http cookie SERVER-COOKIE insert indirect nocache option forwardfor server 192.168.27.17 192.168.27.17:8080 cookie web1 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 cookie web2 check inter 3000 fall 3 rise 5
2、Haproxy狀態頁實現
• stats enable #基於默認的參數啟用stats page • stats hide-version # 隱藏版本 • stats refresh <delay> # 設定自動刷新時間間隔 • stats uri <prefix> #自定義stats page uri,默認值:/haproxy?stats • stats realm <realm> #賬戶認證時的提示信息,示例:stats realm : HAProxy\ Statistics 此處\ 為轉義空格 • stats auth <user>:<passwd> #認證時的賬號和密碼,可使用多次,默認:no authentication • stats refresh 5s #定義頁面自動刷新間隔時間 • stats admin { if | unless } <cond> #啟用stats page中的管理功能
listen stats bind 192.168.27.7:9009 stats enable stats hide-version stats uri /haproxy-status stats realm HAPorxy\ Stats\ Page stats auth haadmin:123456 stats auth admin:123456 #可以有多個 stats refresh 30s stats admin if TRUE
3、Haproxy日志配置
在haproxy配置文件default配置項定義: log 127.0.0.1 local{1-7} info #基於syslog記錄日志到指定設備,級別有(err、warning、info、debug) 配置rsyslog: $ModLoad imudp $UDPServerRun 514 local3.* /var/log/haproxy.log 配置HAProxy: listen web_port bind 127.0.0.1:80 mode http log global option tcplog #允許記錄tcp連接的狀態和時間 server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5 重啟rsyslog服務與haproxy服務
4、三種后端服務器的監測
(1) 基於四層傳輸端口監測
listen web_prot_http_nodes bind 192.168.27.7:80 mode http log global option forwardfor server 192.168.27.17 192.168.27.17:8080 check port 9000 addr 172.168.27.17 inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check port 9000 addr 172.168.27.27 inter 3000 fall 3 rise 5
(2) 基於指定URI 做狀態監測
listen web_prot_http_nodes bind 192.168.27.7:80 mode http log global option forwardfor option httpchk GET /wp-includes/js/jquery/jquery.js?ver=1.12.4 HTTP/1.0 #基於指定URL server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
(3) 基於指定URI的request請求頭部內容做狀態監測
listen web_prot_http_nodes bind 192.168.27.7:80 mode http log global option forwardfor option httpchk HEAD /wp-includes/js/jquery/jquery.js?ver=1.12.4 HTTP/1.0\r\nHost:\ 192.168.27.7 #通過request獲取的頭部信息進行匹配進行健康檢測 server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5 server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5
5、自定義錯誤頁面
• errorfile 500 /usr/local/haproxy/html/500.html #自定義錯誤頁面跳轉 • errorloc 503 http://192.168.7.103/error_page/503.html #自定義錯誤頁面跳轉
6、基於acl+文件后綴實現動靜分離
listen web_port bind 192.168.27.7:80 mode http acl php_server path_end -i .php use_backend php_server_host if php_server acl image_server path_end -i .jpg .png .jpeg .gif use_backend image_server_host if image_server default_backend default_host backend default_host mode http server web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5 backend php_server_host mode http server web1 192.168.27.27:8080 check inter 2000 fall 3 rise 5 backend image_server_host mode http server web1 192.168.27.37:8080 check inter 2000 fall 3 rise 5
7、acl匹配訪問路徑
listen web_port bind 192.168.27.7:80 mode http acl static_path path_beg -i /static /images /javascript use_backend static_path_host if static_path default_backend default_host backend default_host mode http server web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5 backend static_path_host mode http server web1 192.168.27.27:8080 check inter 2000 fall 3 rise 5
8、基於http策略的訪問控制
listen web_port bind 192.168.27.7:80 mode http acl badguy_deny src 192.168.4.1 http-request deny if badguy_deny http-request allow default_backend default_host backend default_host mode http server web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5 backend static_path_host mode http server web1 192.168.27.27:8080 check inter 2000 fall 3 rise 5
9、https的配置
#web server http frontend web_server-http bind 192.168.27.7:80 mode http redirect scheme https if !{ ssl_fc } #把80端口的請求重向定443 use_backend web_host #web server https frontend web_server-https bind 192.168.27.7:443 ssl crt /usr/local/haproxy/certs/haproxy.pem #crt后的證書文件為PEM格式,且同時包含證書和所有私鑰 mode http use_backend web_host backend web_host mode http http-request set-header X-Forwarded-Port %[dst_port] #向后端傳遞用戶請求的端口 http-request add-header X-Forwarded-Proto https if { ssl_fc } #向后端傳遞用戶請求的協議 server web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5 server web2 192.168.27.27:8080 check inter 2000 fall 3 rise 5

# mkdir /usr/local/haproxy/certs # cd /usr/local/haproxy/certs # openssl genrsa -out haproxy.key 2048 # openssl req -new -x509 -key haproxy.key -out haproxy.crt -subj "/CN=www.xxx.com" # cat haproxy.key haproxy.crt > haproxy.pem #將私鑰和證書導入到一個文件中 # openssl x509 -in haproxy.pem -noout -text #查看證書
10、Haproxy后端服務器的動態上下線
# yum install socat # echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock # echo "get weight web_host/192.168.7.101" | socat stdio /var/lib/haproxy/haproxy.sock # echo "disable server web_host/192.168.7.101" | socat stdio /var/lib/haproxy/haproxy.sock # echo "enable server web_host/192.168.7.101" | socat stdio /var/lib/haproxy/haproxy.sock