簡介
HAProxy是一款高性能、開源的負載均衡器與反向代理服務器,主要用于 HTTP、TCP等協議的流量分發,廣泛應用于高并發、高可用的網絡架構中
HAProxy是法國威利塔羅(Willy Tarreau)使用C語言開發的一個開源軟件
企業版:https://www.haproxy.com/
社區版:https://www.haproxy.org/
GitHub:https://github.com/haprox
配置
官方文檔:https://docs.haproxy.org/
配置文件:/etc/haproxy/haproxy.cfg
Haproxy配置由兩大部分組成,分別是
全局配置段:global | 代理配置段:proxies |
---|---|
進程及安全配置相關參數 | defaults段:為frontend、backend、listen提供默認配置 |
性能調整相關參數 | frontend段:前端配置 |
Debug參數 | backend段:后端配置 |
listen:前端 + 后端配置,生成推薦使用 |
global部分
配置名 | 數值 | 功能 |
---|---|---|
log | 127.0.0.1 local2 | 全局的syslog服務器,最多定義兩個,需要開啟UDP協議 |
chroot | /var/lib/haproxy | 指定運行目錄 |
pidfile | /var/run/haproxy.pid | 指定pid文件路徑 |
maxconn | 4000 | 每個Haproxy進程的最大并發連接數 |
maxsslconn | n | 每個Haproxy進程ssl最大連接數,適用于haproxy配置證書的情況下 |
maxconnrate | n | 每個進程每秒創建的最大連接數量 |
nbproc | n | 開啟Haproxy worker進程數,默認一個 |
cpu-map | 1 0 | 綁定Haproxy worker進程到指定CPU |
cpu-map | 2 1 | 將2個work進程綁定到1號CPU上 |
nbthread(與nbproc互斥) | n | 每個Haproxy進程的線程數,默認1進程1線程 |
user,group,uid,gid | haproxy,haproxy,xxx,xxx | 運行Haproxy的用戶身份 |
spread-checks | n | 后端Server狀態check隨機提前或延遲百分比時間,建議20%-50%之間,默認值0 |
daemon | 以守護進程運行 | |
stats socket /var/lib/haproxy/stats | /var/lib/haproxy/stats | 套接字文件 |
ssl-default-bind-ciphers PROFILE=SYSTEM | PROFILE=SYSTEM | HAProxy作為服務器使用的加密套件 |
ssl-default-bind-ciphers PROFILE=SYSTEM ssl-default-server-ciphers PROFILE=SYSTEM | PROFILE=SYSTEM | HAProxy作為客戶端使用的加密套件 |
多進程
[root@Haproxy ~]# yum install haproxy -y
[root@Haproxy ~]# systemctl enable --now haproxy
[root@Haproxy ~]# pstree -p | grep haproxy
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
stats socket /var/lib/haproxy/stats
nbproc 2
cpu-map 1 0
cpu-map 2 1
[root@Haproxy ~]# systemctl restart haproxy.servic
[root@Haproxy ~]# pstree -p | grep haproxy
多進程和多線程互斥,兩個不能同時配置
多線程
# 未開啟多線程時
[root@Haproxy ~]# pstree -p | grep haproxy
[root@Haproxy ~]# cat /proc/31104/status | grep Threads
# 開啟多線程時
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
stats socket /var/lib/haproxy/stats
nbthread 3
[root@Haproxy ~]# systemctl restart haproxy.service
[root@Haproxy ~]# pstree -p | grep haproxy|-haproxy(31186)---haproxy(31188)-+-{haproxy}(31189)| `-{haproxy}(31190)
[root@Haproxy ~]# cat /proc/31188/status | grep Threads
Threads: 3
[root@Haproxy ~]# cat /proc/31189/status | grep Threads
Threads: 3
proxies部分
又細分為三小段;listen段將fronted和backend合并
配置段 | 功能 |
---|---|
defaults | 默認配置項;針對frontend、backend、listen生效 |
frontend | 前端Servername,類似LVS的服務集群 |
backup | 后端RealServer,類似LVS的RS服務器 |
listen | 將frontend和backup合并配置 |
defaults段
配置名 | 數值 | 功能 |
---|---|---|
defaults | name | 默認配置項,可以有多個name,也可以沒有 |
mode | http | 使用的連接協議 |
log | global | 指定日志地址和記錄日志的設備; global:使用global段中的log值 |
option | httplog | 日志記錄選項; httplog:記錄與HTTP相關屬性值 |
option | dontlognull | 不記錄空會話連接日志 |
option http-server-close | 等待客戶端完整HTTP請求的時間,此處等待10s | |
option forwardfor | except 127.0.0.0/8 | 透傳客戶端真實IP到后端Web服務器;except 127.0.0.0/8:排除內網IP |
option | redispatch | 當服務器不可用時,將請求重新分發到其他服務器(默認只重試一次) |
option http-keep-alive | 啟用HTTP長連接支持,即會話保持 | |
retries | 3 | 連接后端服務器失敗時的重試次數 |
timeout http-request | 10s | 等待客戶端請求完全被接收和處理的最長時間 |
timeout queue | 1m | 請求在隊列中等待的最長時間 |
timeout connect | 10s | 連接后端服務器的超時時間 |
timeout client | 1m | 客戶端空閑超時時間,即允許客戶端處于既不接收也不發送數據的非活動時間 |
timeout server | 1m | 服務器空閑超時時間,即允許服務器處于既不接收也不發送數據的非活動時間 |
timeout http-keep-alive | 10s | HTTP長連接的空閑超時時間 |
timeout check | 10s | 后端服務器健康檢查的超時時間 |
maxconn | 3000 | 每個進程允許的最大并發連接數 |
default-server | inter 1000 weight 3 | 為所有后端服務器設置默認參數 inter 1000 表示健康檢查間隔為 1秒 weight 3 表示默認權重為 3 |
frontend段
frontend namebind *:80mode httpuse_backend use_name
配置名 | 數值 | 功能 |
---|---|---|
frontend | xxx | 定義frontend的名字 |
bind | IP:Port,… | 指定Haproxy監聽地址;支持IPV4和IPV6;支持同時監聽多個端口 如果需要綁定在非本機的IP,需要開啟內核參數:net.ipv4.ip_nonlocal_bind=1 |
mode | http、tcp、udp… | 指定負載協議類型;frontend與調用的backend保持一致 |
use_backend | backend name | 將請求轉發到backend name后端 |
backlog | <back log> | 當前端服務器的連接數達到上限時,等待處理的連接請求的后援隊列長度 用于高并發場景下緩沖過量的連接請求,避免直接拒絕客戶端連接 不支持backend |
backend段
backend名稱必須唯一,且必須在listen或fronted中事先定義才能使用,否則服務報錯
backend namemode httpserver name 192.168.0.87:80 check inter 3s fall 3 rise 5server name 192.168.0.89:80 check inter 3s fall 3 rise 5
option參數 | 功能 |
---|---|
httpchk | 通過發送 HTTP 請求并驗證響應狀態碼來檢查服務健康 |
smtpchk | 通過 SMTP 協議握手驗證郵件服務器可用性 |
mysql-check | 通過 MySQL 協議驗證數據庫服務可用性 |
pgsql-check | 通過 PostgreSQL 協議驗證數據庫服務可用性 |
ssl-hello-chk | 驗證服務器是否能正常完成 SSL/TLS 握手,用于 HTTPS 服務 |
Server行
參數 | 功能 |
---|---|
name | 本行server的名字 |
addr | 指定server的IP,可以是專門的數據網段 |
port | 指定server的端口 |
check | 對當前server進行健康狀態檢查,默認不開啟檢查; 對相應的IP和端口利用TCP連接進行周期性健康險檢查 必須指定端口才能實現健康檢查 |
inter | 健康狀態檢查間隔時間,默認2000ms |
fall | 連續健康檢查失敗 n 次后標記為下線,默認 3 |
rise | 連續健康檢查成功 n 次后標記為上線,默認 2 |
weight | 默認為1,最大256;0 表示不參與負載均衡,但能接受持久連接 |
backup | 標記server為備份狀態;僅當其他服務器全部宕機時提供服務 |
disabled | 將server標記為不可用狀態,即維護狀態; 保留持久連接,不再接受新請求,狀態頁顯示深黃色 |
pedirect <preix> | 將請求臨時重定向到其他URL,只適用于HTTP模式 |
maxconn | 單server的最大并發連接數 |
listen段
通常只用于TCP協議的應用,是前兩者的結合配置
listen namebind 192.168.0.87:80mode httpbalance static-rr # 使用的負載均衡算法server mariadb1 192.168.0.87:3306 check inter 3s fall 3 rise 5server mariadb2 192.168.0.89:3306 check inter 3s fall 3 rise 5
socat工具
Socat 是 Linux 下的一個多功能的網絡工具
它可以在兩個數據流之間建立連接并轉發數據,且支持眾多協議和鏈接方式
可以對服務器權重和狀態進行動態調整
基本應用
修改配置文件后,才能正常使用,默認情況下只能查看,不能進行修改
當Haproxy使用特定負載算法時,無法動態調整服務器權重
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
# turn on stats unix socket
stats socket /var/lib/haproxy/stats mode 600 level admin
[root@Haproxy ~]# systemctl restart haproxy.service
[root@Haproxy ~]# yum install socat -y
# 查看幫助
[root@Haproxy ~]# echo "help" | socat stdio /var/lib/haproxy/stats
disable server: disable a server for maintenance # 下線服務器
enable server : enable a disabled server # 上線服務器
set server : change a server's state, weight or address # 修改狀態、權重、IP
get weight : report a server's current weight # 查看權重
set weight : change a server's weight (deprecated) # 修改權重
......
# 查看Haproxy全局信息(Uptime、Maxsock、CurrConns...)
echo "show info" | socat stdio /var/lib/haproxy/stats
# 查看集群狀態
echo "show servers state" | socat stdio /var/lib/haproxy/stats
# 查看集群權重
echo "get weight nginx/static" | socat stdio /var/lib/haproxy/stats
1 (initial 1) # 當前動態權重(配置文件中設置的初始權重)
# 設置權重(范圍為0 - 256)
echo "set weight nginx/static 3" | socat stdio /var/lib/haproxy/stats
3 (initial 1)
# 下線后端服務器
echo "disable server webcluster/web1" | socat stdio /var/lib/haproxy/stats
# 上線后端服務器
echo "enable server webcluster/web1" | socat stdio /var/lib/haproxy/stats
多進程處理
當Haproxy開啟多進程,那么對進程的Sock文件進行操作時,會導致操作是隨機,不夠準確
需要指定操作進程,需要用多sock文件方式解決
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg # turn on stats unix socketstats socket /var/lib/haproxy/stats1 mode 600 level admin process 1stats socket /var/lib/haproxy/stats2 mode 600 level admin process 2nbproc 2cpu-map 1 0cpu-map 2 1
# 經過設置后,每個進程都有對應的sock文件提供操作
[root@Haproxy ~]# ll /var/lib/haproxy/
ACL
格式
acl | aclname | criterion | flags | operator | value |
---|---|---|---|---|---|
acl | 名稱 | 匹配規范 | 匹配模式 | 具體操作符 | 操作對象 |
匹配規范
hdr string:提取HTTP請求報文的首部
hdr([<name>[,<occ>]]) | 完全匹配 | header的指定信息;occ表示在多值中使用的值出現的次數 |
---|---|---|
hdr_beg | 前綴匹配 | header中指定匹配內容的begin |
hdr_end | 后綴匹配 | header中指定匹配內容的end |
hdr_dom | 域名匹配 | header中的dom(host) |
hdr_dir | 路徑匹配 | header的 uri 路徑 |
hdr_len | 長度匹配 | header的長度匹配 |
hdr_reg | 正則表達式匹配 | 自定義表達式模糊匹配 |
hdr_sub | 子串匹配 | header中的 uri 模糊匹配 |
匹配規范還包括(base類、path類、url類)
base string:返回主機頭和請求的路徑部分的連接,請求從主機名開始,并在問號之前結束,對虛擬主機有用
<scheme>://<user>:<password>@#<host>:<port>/<path>;<params>#?<query>#<frag>
path:提取請求的URL路徑,此路徑從第一個斜杠開始,在問號之前結束(無主機部分)
url:提取請求中的整個URL
匹配模式
-i 不區分大小寫
-m 使用指定的正在表達式匹配方法
-n 不做DNS解析
-u 禁止ACL重名,否則多個同名ACL匹配或關系
具體操作符
整數比較
eq | 等于 |
---|---|
ge | 大于等于 |
gt | 大于 |
le | 小于等于 |
lt | 小于 |
字符比較
-m str | 提取的字符串必須與模式完全相同 |
---|---|
-m sub | 提取的字符串中包含指定子串 |
-m beg | 提取的字符串以指定模式開頭 |
-m end | 提取的字符串以指定模式結尾 |
-m dir | 路徑中的任一目錄部分匹配模式(用斜線 / 分隔的字符串) |
-m dom | 域名的任一組成部分匹配模式(用點 . 分隔字符串) |
操作對象
對象類型
Boolean | 布爾值 |
---|---|
Integer/Range | 整數或整數范圍 |
IP Address/Network | IP 地址 / IP 范圍 |
String | 字符串 |
-m str | 精確匹配 |
-m sub | 子串匹配 |
-m beg | 前綴匹配 |
-m end | 后綴匹配 |
-m dir | 路徑匹配 |
-m dom | 域名匹配 |
Regular Expression | 正則表達式 |
Hex Block | 十六進制 |
組合調用方式
多個ACL邏輯處理
與:默認使用
或:or 或 || 表示
否定:! 表示
多個ACL調用方式
if a1 a2 | 與關系,acl中a和b 都要滿足為true,默認調用方式 |
---|---|
if a1 || a2 if a1 or a2 | 或關系,acl中a1或a2滿足一個為true |
if !a1 | 非,取反,不滿足acl才為true |
算法
HAProxy通過固定參數 balance 指明對后端服務器的調度算法
balance 參數可以配置在listen或backend選項中
HAProxy的調度算法分為靜態和動態調度算法,有些算法可以根據參數在靜態和動態算法中相互轉換
靜態算法
按照事先定義好的規則輪詢公平調度,不關心后端服務器的當前負載、連接數和響應速度等,且無法實時修改權重,只能靠重啟 HAProxy 生效
static-rr
基于權重的輪詢調度,權重只能在配置文件中靜態設置
- 不支持權重動態調整
- 不支持服務器慢啟動
- 后端服務器沒有數量限制
慢啟動:服務器剛剛啟動時,先給一部分訪問,承受住后,再逐漸增加
cat /etc/haproxy/haproxy.cfg
listen nginxbind 172.25.254.100:80mode httpbalance static-rrserver rs1 192.168.0.87:80 weight 1 check inter 3s fall 3 rise 5server rs2 192.168.0.89:80 weight 1 check inter 3s fall 3 rise 5for i in {1..10}; do curl 172.25.254.100; done
first
根據服務器在列表中的位置,自上而下進行調度,當第一臺服務器的連接數達到上限,新請求才會分配給下一臺服務
- 忽略服務器權重
- 不支持權重動態調整
vim /etc/haproxy/haproxy.cfg
listen WebClusterbind 172.25.254.87:80mode httpbalance firstserver RS1 172.25.254.88:80 weight 1 maxconn 1 check inter 3s fall 3 rise 5server RS2 172.25.254.99:80 weight 3 check inter 3s fall 3 rise 5
# 一個終端一直訪問 while true; do curl 172.25.254.87; done
# 另一個終端也一樣 while true; do curl 172.25.254.87; done 可以觀察到有訪問到 172.25.254.99
......
Web-Server - 172.25.254.88
Web-Server - 172.25.254.99
Web-Server - 172.25.254.88
......
動態算法
-
基于后端服務器狀態進行調度適當調整
-
新請求將優先調度至當前負載較低的服務器
-
權重可以在haproxy運行時動態調整無需重啟
roundrobin
基于權重的輪詢動態調度算法
-
支持權重動態調整,不同于LVS中的 rr 輪詢模式
-
支持慢啟動(新加的服務器會逐漸增加轉發數)
-
默認調度算法,使用廣泛
其每個后端backend中最多支持4095個real server
vim /etc/haproxy/haproxy.cfg
listen WebClusterbind 172.25.254.87:80mode httpbalance roundrobinserver RS1 172.25.254.88:80 weight 1 check inter 3s fall 3 rise 5server RS2 172.25.254.99:80 weight 2 check inter 3s fall 3 rise 5for i in {1..10}; do curl 172.25.254.87; done
Web-Server - 172.25.254.99
Web-Server - 172.25.254.99
Web-Server - 172.25.254.99
Web-Server - 172.25.254.88
......# 動態調整權重
echo "set weight WebCluster/RS2 1" | socat stdio /var/lib/haproxy/stats
echo get weight WebCluster/RS2 | socat stdio /var/lib/haproxy/stats
1 (initial 2)
echo get weight WebCluster/RS1 | socat stdio /var/lib/haproxy/stats
1 (initial 1)
for i in {1..10}; do curl 172.25.254.87; done
Web-Server - 172.25.254.88
Web-Server - 172.25.254.99
......
leastconn
加權最少連接
- 根據當前連接數最少的后端服務器分配請求,而非權重
- 當服務器連接數相同,以權重為主
- 支持權重動態調整
- 支持服務器慢啟動
- 適合長連接的場景
其他算法
其它算法即可作為靜態算法,又可以通過選項成為動態算法
source
源地址哈希,默認為靜態方式
基于用戶源地址hash并將請求轉發到后端服務器,后續同一個源地址請求將被轉發至同一個后端Web服務器
但當后端服務器數據量發生變化時,會導致很多用戶的請求轉發至新的后端服務器
可以通過hash-type支持的選項更改運行模式
兩種轉發請求到后端服務器的計算方式,分別是取模法和一致性hash
當客戶端是一個家庭,所有家庭成員的訪問流量都會被定向到一臺服務器,這是source算法的缺陷
map-base
取模法
先對Source地址進行Hash計算,再基于服務器總權重的取模(取相除后的余數),最終結果會決定客戶端請求被分配到哪個后端服務器上
靜態算法:不支持在線調整權重,不支持慢啟動,可實現對后端服務器均衡調度
當服務器的總權重發生變化時,即有服務器上線或下線,都會因總權重發生變化而導致調度結果整體改變(導致已建立的會話內容全部丟失)
一致性hash
一致性哈希
當服務器的總權重發生變化時,對調度結果影響是局部的,不會引起大的變動
動態算法,支持使用socat等工具進行在線權重調整,支持慢啟動
逆時針方向,就近原則選取服務器
hash環偏斜問題:
當多個服務器IP經過Hash運算后,彼此的值相差不大,在環上呈現緊靠的現象,此時最小Hash值對應的服務器需要處理大部分的服務請求,這種現象稱為一致性Hash環傾斜
解決方案:
增加虛擬服務器IP數量,比如一個后端服務器根據權重為1生成1000個虛擬IP,再hash。而后端服務器權重為2則生成2000的虛擬IP,再bash,最終在hash環上生成3000個節點,從而解決hash環偏斜問題
uri
基于對用戶請求的URI的左半部分或整個uri做hash,再將hash結果對總權重進行取模后,根據最終結果將請求轉發到后端指定服務器
適用于后端是緩存服務器場景
默認是靜態算法,也可以通過hash-type指定map-based和consistent,決定使用取模法還是一致性hash
此算法基于應用層,所以只支持 mode http ,不支持 mode tcp
url_param
對用戶請求的url中的 params 部分中的一個參數key對應的value值作hash計算,并由服務器總權重相除以后派發至某挑出的服務器,后端搜索同一個數據會被調度到同一個服務器
通常用于追蹤用戶,以確保來自同一個用戶的請求始終發往同一個real server
如果沒有key,則會使用默認輪詢調度算法(roundrobin)
hdr
針對用戶每個http頭部(header)請求中的指定信息做hash
由 name 指定的 http首部 將會被取出并做hash計算
然后由服務器總權重取模以后派發至某挑出的服務器,如果無有效值,則會使用默認輪詢調度算法
算法總結
調度算法 | 適用協議 |
---|---|
static-rr | tcp/http |
first | tcp/http |
roundrobin | tcp/http |
leastconn | tcp/http |
source | tcp/http |
Uri | http |
url_param | http |
hdr | http |
應用
環境
主機版本:Linux-9_4.x86_64
主機名 | IP | 網卡 |
---|---|---|
Client | 172.25.254.88 | eth0 |
Haproxy | 172.25.254.100(公網) | eth0 |
192.168.0.100(私網) | eth1(僅主機模式) | |
RS1 | 192.168.0.87 | eth0(僅主機模式) |
RS2 | 192.168.0.89 | eth0(僅主機模式) |
安裝
軟件包:https://github.com/haproxy/wiki/wiki/Packages
[root@Haproxy ~]# yum install haproxy.x86_64 -y &> /dev/null
[root@Haproxy ~]# haproxy -v
[root@Haproxy ~]# systemctl enable --now haproxy.service
基本應用
[root@RS1/2 ~]# yum install nginx -y &> /dev/null
[root@RS1/2 ~]# echo "192.168.0.87" > /usr/share/nginx/html/index.html
[root@RS1/2 ~]# systemctl enable --now nginx.service
[root@RS1 ~]# curl 192.168.0.89
192.168.0.89
[root@RS2 ~]# curl 192.168.0.87
192.168.0.87
# 除global和defaults段,其他地方均要注釋掉
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
listen nginxbind 172.25.254.100:80mode httpbalance static-rrserver rs1 192.168.0.87:80 weight 1 checkserver rs2 192.168.0.89:80 weight 1 check
[root@Haproxy ~]# systemctl restart haproxy.service
[root@Client ~]# for i in {1..10}; do curl 172.25.254.100; done
高級應用
Haproxy 錯誤頁
對指定的報錯進行重定向,進行優雅的顯示錯誤頁面
使用 errorfile 和 errorloc 參數,實現自定義各種錯誤頁面
# Haproxy默認使用的錯誤頁面
[root@Haproxy ~]# rpm -ql haproxy | grep -E http$
自定義錯誤頁面
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
......maxconn 3000errorfile 503 /haproxy/errorpages/503page.http
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
[root@Haproxy ~]# mkdir /haproxy/errorpages/ -p
[root@Haproxy ~]# cp /usr/share/haproxy/503.http /haproxy/errorpages/503page.http[root@Haproxy ~]# cat /haproxy/errorpages/503page.http
HTTP/1.0 503 Service Unavailable^M
Cache-Control: no-cache^M
Connection: close^M
Content-Type: text/html;charset=UTF-8^M
^M
<html><body><h1>什么水果最讓人感到有壓力?</h1>
<h1>鴨梨,因為"壓力"(鴨梨)山大</h1>
</body></html>[root@Haproxy ~]# systemctl restart haproxy.service
[root@RS1/2 ~]# systemctl stop nginx.service
通過瀏覽器訪問172.25.254.100
重定向錯誤頁面
使用 errorloc 指令,遇到錯誤代碼時,重定向錯誤頁面
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
......maxconn 3000errorloc 503 https://www.baidu.com
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
[root@RS1/2 ~]# systemctl stop nginx
Haproxy HTTPS實現
[root@Haproxy ~]# mkdir /etc/haproxy/certs/[root@Haproxy ~]# openssl req -newkey rsa:2048 -nodes -sha256 -keyout /etc/haproxy/certs/ooovooo.org.key -x509 -days 365 -out /etc/haproxy/certs/ooovooo.org.crt# Country Name (2 letter code) [XX]:CN
# State or Province Name (full name) []:Shanghai
# Locality Name (eg, city) [Default City]:Shanghai
# Organization Name (eg, company) [Default Company Ltd]:QAQ
# Organizational Unit Name (eg, section) []:QWQ
# Common Name (eg, your name or your server's hostname) []:www.ooovooo.org
# Email Address []:admin@ovo.org[root@Haproxy ~]# cat /etc/haproxy/certs/ooovooo.org.key /etc/haproxy/certs/ooovooo.org.crt > /etc/haproxy/certs/ooovooo.org.pem[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen nginxbind *:443 ssl crt /etc/haproxy/certs/ooovooo.org.pemmode httpbalance static-rrserver rs1 192.168.0.87:80 weight 1 checkserver rs2 192.168.0.89:80 weight 1 check[root@Haproxy ~]# systemctl restart haproxy.service[root@RS1/2 ~]# systemctl restart nginx.service
全站加密
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend nginx-httpsbind *:80mode httpredirect scheme https if !{ ssl_fc }listen nginxbind *:443 ssl crt /etc/haproxy/certs/ooovooo.org.pemmode httpbalance static-rrserver rs1 192.168.0.87:80 weight 1 checkserver rs2 192.168.0.89:80 weight 1 check
[root@Haproxy ~]# systemctl restart haproxy.service
Haproxy 狀態頁
Haproxy自帶一個狀態頁,方便我們觀察服務器的健康狀態
參數 | 名稱 |
---|---|
stats enable | 基于默認的參數啟用stats page |
stats hide-version | 將狀態頁中haproxy版本隱藏 |
stats refresh <delay> | 設定自動刷新時間間隔,默認不自動刷新,過快耗費性能 |
stats uri <prefix> | 自定義stats page uri,默認值:/haproxy/status |
stats auth : <user>:<passwd> | 認證時的賬號和密碼,可定義多個用戶,每行指定一個用戶 默認:no authentication |
stats admin { if | unless } <cond> | 啟用stats page中的管理功能 |
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen statusmode httpbind *:7788stats enablestats uri /statusstats auth haproxy:7788
[root@Haproxy ~]# systemctl restart haproxy.service
基于Cookie的會話保持
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen nginxbind *:443 ssl crt /etc/haproxy/certs/ooovooo.org.pemmode httpbalance static-rrcookie QAQ-WebServer insert nocache indirectserver rs1 192.168.0.87:80 cookie est1 weight 1 checkserver rs2 192.168.0.89:80 cookie est2 weight 1 check
[root@Haproxy ~]# systemctl restart haproxy.service
IP透傳
NGinx日志:/var/log/nginx/access.log
Web服務器中需要記錄客戶端的真實IP地址,用于做訪問統計、安全防護、行為分析、區域排行等場景
四層透傳
Apache不支持原生四層透傳(TCP 轉發),可以在四層代理的配合下做到透傳
未配置透傳
# 將前面的配置刪掉,保證環境的干凈
[root@HAproxy ~]# vim /etc/haproxy/haproxy.cfg
listen nginxbind *:80mode tcpbalance roundrobinserver rs1 192.168.0.87:80 weight 1 checkserver rs2 192.168.0.89:80 weight 1 check
[root@HAproxy ~]# systemctl restart haproxy.service
[root@RS1 ~]# > /var/log/nginx/access.log
[root@Client ~]# for i in {1..10}; do curl 172.25.254.100; done# 不記錄客戶端真實 IP 地址
[root@RS1 ~]# cat /var/log/nginx/access.log
配置透傳
# 僅開啟RS2
[root@HAproxy ~]# vim /etc/haproxy/haproxy.cfg
listen WebServerbind *:80mode tcpbalance roundrobinserver rs1 192.168.0.87:80 weight 1 checkserver rs1 192.168.0.87:80 weight 1 check send-proxy # send-proxy 開啟透傳
[root@HAproxy ~]# systemctl restart haproxy.service
[root@Server2 ~]# vim /etc/nginx/nginx.conf
http {log_format main '$remote_addr - $remote_user [$time_local] "$request" ''"$proxy_protocol_addr"' # 新增行'$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';
......server {
# 沒有 proxy_protocol 參數無法訪問,只能通過四層代理訪問;
# 并且做七層透傳時 proxy_protocol 參數不能有listen 80 proxy_protocol;listen [::]:80;
[root@RS2 ~]# systemctl restart nginx.service[root@RS1/2 ~]# > /var/log/nginx/access.log
[root@Client ~]# for i in {1..10}; do curl 172.25.254.100; done
# 記錄客戶端真實 IP 地址
[root@RS1/2 ~]# cat /var/log/nginx/access.log
七層透傳
Nginx七層默認配置好透傳,而Apache則沒有,需要進行相應配置
[root@HAproxy ~]# vim /etc/haproxy/haproxy.cfg
listen WebServerbind *:80mode httpbalance roundrobinserver rs1 192.168.0.87:80 weight 1 checkserver rs2 192.168.0.89:80 weight 1 check
[root@HAproxy ~]# systemctl restart haproxy.service
# 還原配置
[root@RS2 ~]# vim /etc/nginx/nginx.conf
http {log_format main '$remote_addr - $remote_user [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent" "$http_x_forwarded_for"';
......server {listen 80;
[root@RS2 ~]# systemctl restart nginx.service[root@RS1 ~]# > /var/log/nginx/access.log
[root@Client ~]# for i in {1..10}; do curl 172.25.254.88; done
# Nginx 七層默認開啟透傳
[root@RS1 ~]# cat /var/log/nginx/access.log
# 關閉 Nginx 七層透傳
[root@HAproxy ~]# vim /etc/haproxy/haproxy.cfg
defaults
......
# 在轉發客戶端請求時,HAProxy會在HTTP請求頭中添加X-Forwarded-For字段,其中包含客戶端的真實IP地址
# 來自本地回環地址的請求,HAProxy 不會添加 X-Forwarded-For 頭
# option forwardfor except 127.0.0.0/8
[root@HAproxy ~]# systemctl restart haproxy.service
[root@RS1 ~]# > /var/log/nginx/access.log
[root@Client ~]# for i in {1..10}; do curl 172.25.254.100; done
[root@RS1 ~]# cat /var/log/nginx/access.log
Apache七層透傳
[root@RS1 ~]# systemctl stop nginx.service[root@RS1 ~]# dnf install httpd -y
[root@RS1 ~]# systemctl enable --now httpd
[root@RS1 ~]# echo 192.168.0.87 > /var/www/html/index.html
[root@RS1 ~]# curl 192.168.0.87
192.168.0.87
[root@RS1 ~]# > /etc/httpd/logs/access_log
[root@Client ~]# for i in {1..10}; do curl 172.25.254.100; done
# 默認關透傳
[root@RS1 ~]# cat /etc/httpd/logs/access_log
# 開透傳
# /etc/haproxy/haproxy.cfg中需要option forwardfor except 127.0.0.0/8未被注釋
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfgoption forwardfor except 127.0.0.0/8
[root@Haproxy ~]# systemctl restart haproxy.service[root@RS1 ~]# vim /etc/httpd/conf/httpd.conf
201 LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
202 LogFormat "%h %l %u %t \"%r\" %>s %b" common
[root@RS1 ~]# systemctl restart httpd[root@RS1 ~]# > /etc/httpd/logs/access_log
[root@Client ~]# for i in {1..10}; do curl 172.25.254.100; done
[root@RS1 ~]# cat /etc/httpd/logs/access_log
ACL-匹配訪問路徑實現動靜分離
注意:四層透傳下,無法完成此實驗
[root@RS1 ~]# yum remove httpd -y
[root@RS1/2 ~]# systemctl enable --now nginx.service
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend nginxbind *:80mode httpacl static path_sub -m sub staticacl php path_sub -m sub phpuse_backend php-server if phpdefault_backend default-server
backend php-servermode httpserver php 192.168.0.87:80 check
backend default-servermode httpserver nginx 192.168.0.89:80 check
[root@Haproxy ~]# systemctl restart haproxy.service[root@RS1 ~]# yum install php -y
[root@RS1 ~]# mkdir /usr/share/nginx/html/php -p
[root@RS1 ~]# vim /usr/share/nginx/html/php/index.php
<?phpphpinfo();
?>
[root@RS1 ~]# systemctl enable --now php-fpm.service[root@RS2 ~]# mkdir /usr/share/nginx/html/static -p
[root@RS2 ~]# echo static - 172.25.254.89 Nginx > /usr/share/nginx/html/static/index.html
Haproxy 四層負載
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen mysqlbind *:3306mode tcpbalance static-rrserver rs1 192.168.0.87:3306 checkserver rs2 192.168.0.89:3306 check
[root@Haproxy ~]# systemctl restart haproxy.service
[root@RS1/2 ~]# yum install mariadb-server -y
[root@RS1 ~]# vim /etc/my.cnf
!includedir /etc/my.cnf.d
[mysqld]
server-id=1
[root@RS2 ~]# vim /etc/my.cnf
!includedir /etc/my.cnf.d
[mysqld]
server-id=2
[root@RS1/2 ~]# systemctl enable --now mariadb
[root@RS1/2 ~]# mysql -e "grant all on *.* to ovo@'%' identified by 'aaa';"
[root@RS1/2 ~]# systemctl restart mariadb.service[root@Client ~]# yum install mariadb -y
[root@Client ~]# mysql -uovo -paaa -h 172.25.254.100 -e 'select @@server_id;'