企業級反向代理 HAProxy

战斗小人發表於2024-09-26

企業級反向代理 HAProxy

haproxy只做代理,不提供其他功能。可以做四層,七層代理。有些公司會用haproxy做四層代理, haproxy比lvs好在功能更強大

2 HAProxy 簡介

企業版(收費)

社群版

社群版網站:http://www.haproxy.org/
github:https://github.com/haproxy
#選偶數版本,長期支援版本,不要選dev開發版
點版本下載的是原始碼,需要編譯安裝

3 HAProxy 安裝

3.1 Ubuntu 包安裝

haproxy ubuntu自帶了,如果要裝最新的包,就在社群版網站左側點debian包,選擇對應版本,會出現命令
根據命令執行,第一步不用,第二部實際上是新增倉庫

3.2 編譯安裝 HAProxy

#紅帽系列沒有提供包安裝,那就採用原始碼編譯安裝吧

#注意需要lua支援,centos7的lua版本太低,需要先編譯lua,在編譯安裝haproxy
#範例:Ubuntu
#安裝依賴包(這裡以為依賴順便把lua裝上了)
[root@ubuntu2204 ~]#apt update && apt -y install gcc make libssl-dev libpcre3 libpcre3-dev zlib1g-dev libreadline-dev libsystemd-dev liblua5.4-dev
#下載
[root@ubuntu2204 ~]#wget http://www.haproxy.org/download/2.8/src/haproxy-2.8.0.tar.gz
[root@ubuntu2204 ~]#tar xf haproxy-2.8.0.tar.gz;cd haproxy-2.8.0/
#編譯安裝 (-j表示多程序並行編譯)
[root@ubuntu2204 haproxy-2.8.0]#make -j 2 ARCH=x86_64 TARGET=linux-glibc 
USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_PROMEX=1 USE_LUA=1
[root@ubuntu2204 haproxy-2.8.0]#make install PREFIX=/apps/haproxy

配置檔案

#準備配置檔案
[root@centos7 ~]# mkdir /etc/haproxy

#方式1:複製原始碼中的範例配置檔案做為初始配置檔案  (必須cfg結尾)
[root@haproxy haproxy-2.8.3]#cp examples/quick-test.cfg /etc/haproxy/haproxy.cfg

準備使用者

#設定使用者和目錄許可權
[root@centos7 ~]# useradd -m -r -s /sbin/nologin -d /var/lib/haproxy haproxy

準備HAProxy啟動檔案 (service檔案)

#建立service檔案
[root@centos7 ~]#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 /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
LimitNOFILE=100000        #HAProxy能開啟的檔案個數

[Install]
WantedBy=multi-user.target

[root@centos7 ~]#systemctl daemon-reload
[root@centos7 ~]#systemctl status haproxy.service
#開機啟動
[root@centos7 ~]#systemctl enable --now haproxy.service

啟用狀態頁

#修改配置檔案(下面追加)
[root@centos7 ~]#vim /etc/haproxy/haproxy.cfg
#啟用狀態頁功能
listen stats
   mode http
   bind 0.0.0.0:9999    #狀態頁埠
   stats enable
   log global
   stats uri     /haproxy-status    #狀態頁地址
   stats auth   admin:123456        #狀態頁使用者密碼
[root@centos7 ~]#systemctl reload haproxy.service

#瀏覽器上檢視狀態頁
10.0.0.200:9999/haproxy-status

3.3 基於 Docker 部署

Haproxy 官方映象
https://hub.docker.com/_/haproxy/

範例: 基於 Docker 安裝 Haproxy
#cat haproxy.cfg
global
maxconn 100000
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon
pidfile /var/lib/haproxy/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 admin:123456
  
#新版
docker run -d --name my-running-haproxy -v
/root/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro -p 9999:9999  --sysctl
net.ipv4.ip_unprivileged_port_start=0 haproxy:2.8.2-alpine3.18
#舊版
docker run -d --name my-running-haproxy -v
/root/haproxy.cfg:/usr/local/etc/haproxy/haproxy.cfg:ro -p 9999:9999  --sysctl
net.ipv4.ip_unprivileged_port_start=0 haproxy:2.6.0-alpine3.16

#ip_unprivileged_port_start是最佳化,正常特權埠是1024以內埠,這裡設0表示所有埠都非特權埠,都能使用

4 HAProxy 基礎配置

HAProxy 的配置檔案haproxy.cfg由兩大部分組成,分別是global和proxies部分
global:全域性配置段

proxies:代理配置段

4.1 Global配置

Global 配置引數說明

常見配置指令

chroot /apps/haproxy #鎖定執行目錄(安全,只能訪問這個目錄下,被駭客控制也只能在這個目錄下)
deamon               #以守護程序執行
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin  #socket檔案,並可以透過此檔案管理,新版不再支援多程序
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin process 1
#socket檔案,並可以透過此檔案管理,舊版指定程序
user, group, uid, gid  #執行haproxy對應worker程序的使用者身份
#nbproc   n   #開啟的haproxy worker 程序數,預設程序數是一個, nbproc從HAProxy 2.5開始不再支援
nbthread  1 #預設值auto,和多程序 nbproc配置互斥(版本有關,CentOS8的haproxy1.8無此問題),指定每個haproxy程序開啟的執行緒數,預設為每個程序一個執行緒

#如果同時啟用nbproc和nbthread 會出現以下日誌的錯誤,無法啟動服務,此項不指定,預設為auto,即也可以實現自動生成和CPU核數相同的執行緒數
Apr  7 14:46:23 haproxy haproxy: [ALERT] 097/144623 (1454) : config : cannot 
enable multiple processes if multiple threads are configured. Please use either 
nbproc or nbthread but not both.

#注意:下面方式不支援執行緒繫結
#cpu-map 1 0   #繫結haproxy worker 程序至指定CPU,將第1個worker程序繫結至0號CPU
#cpu-map 2 1     #繫結haproxy worker 程序至指定CPU,將第2個worker程序繫結至1號CPU

cpu-map auto:1/1-8 0-7 #haproxy2.4中啟用nbthreads,在global配置中新增此選項,可以進行自動的執行緒和CPU的繫結,nbproc選項2.5版本中將會刪除,每個程序中1-8個執行緒分別繫結0-7號CPU,注意:新版用此項進行執行緒繫結

maxconn n   #每個haproxy程序的最大併發連線數
maxsslconn n   #每個haproxy程序ssl最大連線數,用於haproxy 配置了證書的場景下
maxconnrate n   #每個程序每秒建立的最大連線數量
#haproxy可以主動檢查,nginx只能被動檢查(訪問了再檢查)。下面引數可以讓檢查請求前後時間錯開
spread-checks n #後端server狀態check隨機提前或延遲百分比時間,建議2-5(20%-50%)之間,預設值0
pidfile #指定pid檔案路徑
log 127.0.0.1 local2 info #定義全域性的syslog伺服器;日誌伺服器需要開啟UDP協議,最多可以定義兩個
#語法檢查
/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg  -c -q

#修改haproxy對應worker程序的使用者身份(縮排沒關係)
[root@ubuntu ~]#vim /etc/haproxy/haproxy.cfg
global
    user haproxy
    group haproxy

[root@ubuntu ~]#systemctl reload haproxy.service
#檢視是否生效
[root@ubuntu ~]#ps auxf|grep haproxy

HAProxy日誌配置

HAproxy預設本身不記錄客戶端的訪問日誌.此外為減少伺服器負載,一般生產中HAProxy不記錄日誌.

HAProxy 支援利用rsyslog服務記錄日誌到指定日誌檔案中

HAProxy配置

#在global配置項定義:
log 127.0.0.1:514 local{0-7} info #基於syslog記錄日誌到指定裝置,級別包括:err、warning、info、debug   透過514埠接受日誌   local自定義日誌,用0-7中的某一個
#例:
log 127.0.0.1:514 local6 info

listen web_port
 bind 127.0.0.1:80
 mode http
 log global #開啟當前web_port的日誌功能,預設不記錄日誌
 server web1  127.0.0.1:8080 check inter 3000 fall 2 rise 5
  
# systemctl reload haproxy.service

Rsyslog配置

vim /etc/rsyslog.conf 
$ModLoad imudp
$UDPServerRun 514    #監聽514
......
local6.info   /var/log/haproxy.log    #日誌寫入位置(這個配置也可以寫在只配置檔案中)
......

# systemctl restart rsyslog

4.2 Proxies 配置

Proxies 配置塊

defaults [<name>] #預設配置項,針對以下的frontend、backend和listen生效,可以多個name也可以沒有name
listen   <name>   #將frontend和backend合併在一起配置,相對於frontend和backend配置更簡潔,生產常用
frontend <name>   #前端servername,類似於Nginx的一個虛擬主機 server和LVS服務叢集。
backend <name>   #後端伺服器組,等於nginx的upstream和LVS中的RS伺服器

Proxies配置 listen

listen生產示例:

[root@ubuntu ~]#vim /etc/rsyslog.conf 
global
    ...
listen webservers    #起個名字
    bind 192.168.10.200:80    #本機監聽地址
    server web1 10.0.0.201:80
    server web2 10.0.0.202:80
    
[root@ubuntu ~]#systemctl reload haproxy.service

#注意這時候,如果一個後端掛了,haproxy不會去監測,依然會把請求打上去

#追加健康檢查
[root@ubuntu ~]#vim /etc/rsyslog.conf 
listen webservers
    bind 192.168.10.200:80    #本機監聽地址
    server web1 10.0.0.201:80    check #自動定期檢查後端,預設2s(L4只查埠開沒開,不嚴謹)
    #每1s檢查後端,5次失敗就異常,3次成功才算恢復正常,權重3,最大連線數10000
    server web2 10.0.0.202:80    check inter 1000 fall 1 rise 3 weight 3 maxconn 10000
    server localhost 127.0.0.1:80 redir http://www.baidu.com    #重定向到百度
    
[root@ubuntu ~]#systemctl reload haproxy.service

server配置

#針對一個server配置
check #對指定real進行健康狀態檢查,如果不加此設定,預設不開啟檢查,只有check後面沒有其它配置也可以啟用檢查功能
     #預設對相應的後端伺服器IP和埠,利用TCP連線進行週期性健康性檢查,注意必須指定埠才能實現健康性檢查
   addr <IP>   #可指定的健康狀態監測IP,可以是專門的資料網段,減少業務網路的流量
   port <num> #指定的健康狀態監測埠
   inter <num> #健康狀態檢查間隔時間,預設2000 ms
   fall <num>   #後端伺服器從線上轉為線下的檢查的連續失效次數,預設為3
   rise <num>   #後端伺服器從下線恢復上線的檢查的連續有效次數,預設為2
weight <weight> #預設為1,最大值為256,0(狀態為藍色)表示不參與負載均衡,但仍接受持久連線
backup #將後端伺服器標記為備份狀態,只在所有非備份主機down機時提供服務,類似Sorry Server
disabled #將後端伺服器標記為不可用狀態,即維護狀態,除了持久模式,將不再接受連線,狀態為深黃色,支援優雅平滑下線,繼續處理舊請求,不接受新請求
maxconn <maxconn> #指定每個後端server的最大併發連線數,放在,放在server 指令後面
redir http://www.baidu.com       #將請求臨時(302)重定向至其它URL,只適用於http模式,放在server 指令後面

redirect 配置

#注意:此指令和redir功能相似,但不屬於server指令後面,是獨立存放在listen,frontend,backend語句塊
redirect prefix http://www.baidu.com/ #將請求臨時(302)重定向至其它URL,只適用於http模式

Proxies配置 frontend ,backen

#把listen拆成前端frontend,後端backen
[root@ubuntu ~]#vim /etc/rsyslog.conf 
frontend web-http-80
    bind 192.168.10.200:80    #本機監聽地址
    use_backend httpservers1    #排程到指定後端

backend httpservers1    #後端有兩臺
    server web1 10.0.0.201:80 check
    server web2 10.0.0.202:80 check
    
backend httpservers2    #可以寫多組後端
    server web2 10.0.0.202:80 check
[root@ubuntu ~]#systemctl reload haproxy.service

4.3 使用子配置檔案

#存放業務配置
[root@ubuntu ~]#mkdir /etc/haproxy/conf.d
[root@ubuntu ~]#vim /etc/haproxy/conf.d/www.magedu.org.cfg

#修改service檔案
[root@centos7 ~]#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 -f /etc/haproxy/conf.d -c -q
#追加配置檔案目錄
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -f /etc/haproxy/conf.d -p /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

[root@centos7 ~]#systemctl daemon-reload
[root@centos7 ~]#systemctl restart haproxy.service

5 HAProxy 排程演算法

HAProxy靜態: 不能動態修改後端伺服器的權重

HAProxy動態: 可以動態修改後端伺服器的權重,平滑修改

動態修改用Socat工具控制 (透過socket連線)

5.1 Socat 工具

#提前配置socket檔案路徑
[root@ubuntu2204 ~]#vim /etc/haproxy/haproxy.cfg
global
   stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
[root@ubuntu2204 ~]#systemctl reload haproxy.service

#安裝socat
[root@ubuntu1804 ~]#apt update && apt -y install socat
[root@centos ~]#yum -y install socat

#檢視當前socket支援的指令
[root@centos7 ~]#echo "help" | socat stdio /var/lib/haproxy/haproxy.sock

[root@centos7 ~]#echo "show version" | socat stdio /var/lib/haproxy/haproxy.sock
#顯示當前執行的任務
[root@centos7 ~]#echo "show tasks" | socat stdio /var/lib/haproxy/haproxy.sock
#檢視後端
[root@centos7 ~]#echo "show backend" | socat stdio /var/lib/haproxy/haproxy.sock
#顯示資訊
[root@centos7 ~]#echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
#檢視server狀態        ..."show servers state"
#獲取權重(伺服器分組名/服務名)         ..."get weight webservers/web1"
#修改權重        ..."set weight webservers/web1 6"
#禁用服務            ..."disable server webservers/web1"
#恢復服務            ..."enable server webservers/web1"

5.2 靜態演算法

static-rr 演算法

first 演算法: 一臺機器只要沒出問題,就一直訪問那一臺

5.3 動態演算法: 支援Socat 工具動態修改

roundrobin 演算法

leastconn 演算法: 加權的最少連線的動態,連線數少的優先收到請求

random 演算法: 預設配置

5.4 其他演算法

source 演算法: 源地址hash

uri 演算法

url_param 演算法

hdr 演算法

rdp-cookie 演算法

6 HAProxy 高階功能

6.1 基於 Cookie 的會話保持

6.2 HAProxy 狀態頁

6.3 IP透傳

四層透傳沒意義,後面nginx無法解析

6.4 報文修改

6.5 自定義日誌格式

6.6 壓縮功能

6.7 後端伺服器健康性監測

6.8 ACL (比nginx和lvs強大的地方)

frontend httpserver
    bind 192.168.10.100:80
    acl acl_static path_beg -i /static
    http-request deny if HTTP_1.0    #拒絕http1.0
    use_backend pc_hosts if acl_static
    default_backend mobile_hosts
    
backend pc_hosts
    server web01 10.0.0.201:80

backend mobile_hosts
    server web02 10.0.0.202:80

6.9 自定義 HAProxy 錯誤介面

注意:頁面檔案格式錯誤可能會導致Haproxy服務無法啟動

defaults
#option forwardfor
#no option http-use-htx 支援html檔案,此設定和版本有關,2.1不支援
#...... 
#加下面行
errorfile 500 /usr/local/haproxy/html/500.http
errorfile 502 /usr/local/haproxy/html/502.http
errorfile 503 /usr/local/haproxy/html/503.http

#範例:
[root@centos7 ~]#vim /etc/haproxy/haproxy.cfg
defaults
...
errorfile 503 /apps/haproxy/html/503.http  

listen
.......

[root@centos7 ~]#vim /apps/haproxy/html/503.http 
HTTP/1.1 503 Service Unavailable
Content-Type:text/html;charset=utf-8

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>報錯頁面</title>
</head>
<body>
<center><h1>網站維護中......請稍候再試</h1></center>
<center><h2>聯絡電話:400-123-4567</h2></center>
<center><h3>503 Service Unavailable</h3></center>
</body>

[root@centos7 ~]#systemctl restart haproxy
#將後端伺服器down,可以觀察到以下頁面

6.10 HAProxy 四層負載

注意:如果使用frontend和backend,一定在 frontend 和 backend 段中都指定mode tcp

listen redis-port
   bind 10.0.0.7:6379
   mode tcp
   balance leastconn
   server server1 10.0.0.17:6379 check
   server server2 10.0.0.27:6379 check backup

範例:對 MySQL 服務實現四層負載

[root@centos7 ~]#vim /etc/haproxy/haproxy.cfg
listen wang_mysql
     bind 10.0.0.7:3306
     mode tcp
     balance leastconn
     server mysql1 10.0.0.17:3306 check  
     server mysql2 10.0.0.27:3306 check           #如果不寫埠號,可以轉發,但無法check狀態
   
#或者使用frontend和backend實現
frontend mysql
       bind :3306
       mode tcp   #必須指定tcp模式
       default_backend mysqlsrvs
backend mysqlsrvs
       mode tcp #必須指定tcp模式
       balance leastconn
       server mysql1 10.0.0.17:3306
       server mysql2 10.0.0.27:3306
       
[root@centos7 ~]#systemctl restart haproxy

#在後端伺服器安裝和配置mariadb服務
[root@centos7 ~]#yum -y install mariadb-server
[root@centos7 ~]#mysql -e "grant all on *.* to test@'10.0.0.%' identified by '123456'"
[root@centos7 ~]#vim /etc/my.cnf
[mysqld]
server-id=17 #在另一臺主機為27
[root@centos7 ~]#systemctl start mariadb

6.11 HAProxy Https 實現

Https 配置示例

[root@centos7 ~]#cat /etc/haproxy/conf.d/test.cfg
frontend wang_http_port
 bind 10.0.0.7:80
###################### https setting ##############################  
 bind 10.0.0.7:443 ssl crt /etc/haproxy/certs/haproxy.pem
 redirect scheme https if !{ ssl_fc }        # 注意{ }內的空格
 default_backend pc_hosts 

backend mobile_hosts
 server web1 10.0.0.17:80
 
backend pc_hosts
 server web2 10.0.0.27:80

相關文章