Haproxy

1 HAProxy入門

1.1 負載均衡

什麼是負載均衡

負載均衡(Load Balance,簡稱LB)是一種服務或基於硬件設備等實現的高可用反向代理技術,負載均衡將特定的業 務(web服務、網絡流量等)分擔給指定的一個或多個後端特定的服務器或設備,從而提高了公司業務的並發處理能 力、保證了業務的高可用性、方便了業務後期的水平動態擴展。

為什麼使用負載均衡

Web服務器的動態水平擴展-->對用戶無感知 

增加業務並發訪問及處理能力-->解決單服務器瓶頸問題 

節約公網IP地址-->降低IT支出成本 

隱藏內部服務器IP-->提高內部服務器安全性 

配置簡單-->固定格式的配置文件 

功能豐富-->支持四層和七層,支持動態下線主機 

性能較強-->並發數萬甚至數十萬

負載均衡的分類

四層(OSI的傳輸層)負載均衡:

  • LVS(Linux Virtual Server)
  • HAProxy(High Availability Proxy)
  • Nginx(1.9之後版本)

七層負載均衡:

  • HAProxy
  • Nginx

也有硬件負載均衡,其功能比軟件更強大,而且負載能力也高於軟件負載:

  • F5
  • 深信服

1.2 HAProxy介紹

HAProxy是法國開發者 威利塔羅(Willy Tarreau) 在2000年使用C語言開發的一個開源軟件,是一款具備高並發(一萬 以上)、高性能的TCP和HTTP負載均衡器,支持基於cookie的持久性,自動故障切換,支持正則表達式及web狀態 統計,目前最新TLS版本為2.0

HAProxy分為社區版和企業版:

企業版版加入了Web應用防火牆 、HTTP協議驗證、ACL,映射和TLS票證密鑰同步等新功能,同時提供技術支持。不過文章內容是圍繞社區版展開。

1.2.1 HAProxy功能

HAProxy功能:

  • TCP和HTTP反向代理
  • SSL/TSL服務器
  • 可以針對HTTP請求添加cookie,進行路由後端服務器
  • 可平衡負載至後端服務器,並支持持久連接
  • 支持所有主服務器故障切換至備用服務器
  • 支持專用端口實現監控服務
  • 支持不影響現有連接情況下停止接受新連接請求
  • 可以在雙向添加,修改或刪除HTTP報文首部
  • 響應報文壓縮
  • 支持基於pattern實現連接請求的訪問控制
  • 通過特定的URI為授權用戶提供詳細的狀態信息

HAProxy不具備功能:

  • 正向代理
  • 緩存代理
  • Web服務器
  • UDP協議支持
  • 單機性能相比LVS性能差

1.2.2 HAProxy工作方式

HAProxy藉助於OS上幾種常見的技術來實現性能的最大化。

  • 單進程、事件驅動模型顯著降低了上下文切換的開銷及內存佔用。
  • 內存分配器在固定大小的內存池中可實現即時內存分配,這能夠顯著減少創建一個會話的時長
  • 精心地降低了昂貴的系統調用,大部分工作都在用戶空間完成,如時間讀取、緩衝聚合及文件描述符的啟用和禁用等

當HAProxy啟動後,會負責下面任務:

  • 接收請求
  • 定時檢查服務器狀態
  • 和其他HAProxy節點交換信息

2 HAProxy安裝和基礎配置

2.1 Centos安裝

2.1.1 默認yum源安裝

默認的base倉庫中包含haproxy的安裝包文件,但是版本比較舊,是1.5.18的版本,距離當前版本已經有較長時間 沒有更新,由於版本比較舊所以有很多功能不支持,如果對功能和性能沒有要求可以使用此版本,否則推薦使用新 版本。

[root@localhost ~]# yum install haproxy -y
[root@localhost ~]# yum info haproxy
Loaded plugins: fastestmirror
Repodata is over 2 weeks old. Install yum-cron? Or run: yum makecache fast
Loading mirror speeds from cached hostfile
Available Packages
Name        : haproxy
Arch        : x86_64
Version     : 1.5.18
Release     : 9.el7_9.1
Size        : 835 k
Repo        : updates/7/x86_64
Summary     : TCP/HTTP proxy and load balancer for high availability environments
URL         : //www.haproxy.org/
License     : GPLv2+

2.1.2 第三方包安裝

安裝包下載://pkgs.org/download/haproxy

[root@localhost ~]# rpm -ivh cheese-release-7-1.noarch.rpm
[root@localhost ~]# yum install haproxy-1.8.14-1.el7.x86_64.rpm -y

# 驗證版本
[root@localhost ~]# haproxy -v

2.1.3 編譯安裝HAProxy

編譯安裝haproxy-2.2.19版本,源碼包下載://www.haproxy.org/download/

[root@localhost src]# ls
haproxy-2.2.19.tar.gz
[root@localhost src]# tar -xf haproxy-2.2.19.tar.gz
[root@localhost src]# cd haproxy-2.2.19

由於centos自帶的lua版本比較低並不符合HAProxy要求的lua最低版本(5.3)的要求,因此需要編譯安裝較新版本的 lua環境,然後才能編譯安裝HAProxy

[root@localhost src]# wget //www.lua.org/ftp/lua-5.3.5.tar.gz

# 安裝依賴包
[root@localhost src]# yum install libtermcap-devel ncurses-devel libevent-devel readline-devel
[root@localhost src]# tar xf lua-5.3.5.tar.gz 
[root@localhost src]# cd lua-5.3.5
# 一條命令完成編譯和安裝lua
[root@localhost lua-5.3.5]# make linux install
[root@localhost lua-5.3.5]# lua -v
Lua 5.3.5  Copyright (C) 1994-2018 Lua.org, PUC-Rio

現在可以繼續安裝haproxy

[root@localhost haproxy-2.2.19]#yum -y install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel \
systemd-devel net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof \
tcpdump wget ntpdate

# 第一次編譯出現下面告警
make: warning:  Clock skew detected.  Your build may be incomplete
# 還原虛擬機快照導致時間錯誤,同步一次時間再次編譯即可解決報錯
[root@localhost haproxy-2.2.19]# ntpdate cn.pool.ntp.org
[root@localhost haproxy-2.2.19]# make -j 4 ARCH=x86_64 TARGET=linux-glibc USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 USE_LUA=1 LUA_INC=/usr/local/src/lua-5.3.5/src/ LUA_LIB=/usr/local/src/lua-5.3.5/src PREFIX=/usr/local/haproxy
[root@localhost haproxy-2.2.19]# make install PREFIX=/usr/local/haproxy

# 完成編譯安裝後查看安裝目錄
[root@localhost haproxy-2.2.19]# ls /usr/local/haproxy/
doc  sbin  share
[root@localhost haproxy-2.2.19]# ls /usr/local/haproxy/sbin/
haproxy

# 由於只有一個二進制程序,所以可以拷貝到環境變量目錄中
[root@localhost haproxy-2.2.19]# cp /usr/local/haproxy/sbin/haproxy /usr/sbin/

# 驗證haproxy版本
[root@localhost haproxy-2.2.19]# haproxy -v
HA-Proxy version 2.2.19-7ea3822 2021/11/29 - //haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2025.
Known bugs: //www.haproxy.org/bugs/bugs-2.2.19.html
Running on: Linux 3.10.0-1160.el7.x86_64 #1 SMP Mon Oct 19 16:18:59 UTC 2020 x86_64

創建systemctl管理服務文件

[root@localhost local]# 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

[Install]
WantedBy=multi-user.target

創建相關文件

# 創建配置文件
[root@localhost local]# cat /etc/haproxy/haproxy.cfg 
global
maxconn 100000
chroot /usr/local/haproxy
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
uid 99
gid 99
daemon

# 創建PID目錄
[root@localhost local]# mkdir /var/lib/haproxy
[root@localhost local]# chown 99.99 /var/lib/haproxy/ -R
[root@localhost local]# systemctl start haproxy

2.2 基礎配置詳解

HAPrpxy的配置文件haproxy.cfg由兩大部分組成,分別是global和proxies部分。

2.2.1 全局配置參數

常用配置選項示例

# 鎖定運行目錄
chroot 
# 以守護進程運行
deamon 
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin # 綁定socket文件
# 運行haproxy的用戶身份
user, group, uid, gid 
# 開啟的haproxy進程數,與CPU保持一致
nbproc 
# 指定每個haproxy進程開啟的線程數,默認為每個進程一個線程
nbthread 
# 綁定haproxy 進程至指定CPU
cpu-map 1 0   
# 每個haproxy進程的最大並發連接數
maxconn  
# 每個haproxy進程ssl最大連接數,用於haproxy配置了證書的場景下
maxsslconn   
# 每個進程每秒創建的最大連接數量
maxconnrate  
# 後端server狀態check隨機提前或延遲百分比時間,建議2-5(20%-50%)之間
spread-checks 
# 指定pid文件路徑
pidfile 
# 定義全局的syslog服務器;最多可以定義兩個,Facility字段中local0到local7是給用戶使用的,用於自定義應用日誌   存儲,在/etc/rsyslog.conf 中設置Facility字段對應日誌存儲的位置。
log 127.0.0.1 local3 info 

2.2.2 Proxies配置

代理配置段

# 默認配置項,針對以下的frontend、backend和lsiten生效,可以多個name也可以沒有name
defaults [<name>] 
# 前端servername,類似於Nginx的一個虛擬主機 server。
frontend <name>   
# 後端服務器組,等於nginx的upstream
backend <name>   
# 將frontend和backend合併在一起配置
listen   <name>  

# name字段只能使用」-」、」_」、」.」、和」:」,並且嚴格區分大小寫,例如:Web和web是完全不同的兩組服務器。

defaults 配置參數:

option redispatch     	# 當server Id對應的服務器掛掉後,強制定向到其他健康的服務器,重新派發
option abortonclose   	# 當服務器負載很高的時候,自動結束掉當前隊列處理比較久的鏈接,關閉
option http-keep-alive 	# 開啟與客戶端的會話保持
option forwardfor     	# 透傳客戶端真實IP至後端web服務器
mode http 					# 設置默認工作類型
timeout http-keep-alive 120s # session 會話保持超時時間,範圍內會轉發到相同的後端服務器
timeout connect 120s 	# 客戶端請求從haproxy到後端server的最長連接等待時間(TCP之前)
timeout server 600s 		# 客戶端請求從haproxy到後端服務端的請求處理超時時長(TCP之後)
timeout client 600s 		# 設置haproxy與客戶端的最長非活動時間
timeout check   5s   	# 對後端服務器的默認檢測超時時間

frontend配置參數:

bind:指定HAProxy的監聽地址,可以是IPV4或IPV6,可以同時監聽多個IP或端口,可同時用於listen字段中
bind [<address>]:<port_range> [, ...] [param*]
# 監聽http的多個IP的多個端口和sock文件
listen http_proxy 
   bind :80,:443,:8801-8810
   bind 10.0.0.1:10080,10.0.0.1:10443
   bind /var/run/ssl-frontend.sock user root mode 600 accept-proxy

# https監聽
listen http_https_proxy 
   bind :80
   bind :443 ssl crt /etc/haproxy/site.pem

# 監聽ipv6、ipv4和unix sock文件
listen http_https_proxy_explicit 
   bind ipv6@:80
   bind ipv4@public_ssl:443 ssl crt /etc/haproxy/site.pem
   bind [email protected] user root mode 600 accept-proxy
   
# 監聽file descriptor
listen external_bind_app1 
   bind "fd@${FD_APP1}"

backend配置參數:

# 指定負載協議類型
mode http/tcp   

# 配置選項,後面加httpchk,smtpchk,mysql-check,pgsql-check方法,可用於實現更多應用層檢測功能。
option 

# 定義後端real server
server   

check 			# 對指定real進行健康狀態檢查,默認不開啟
    addr IP   	# 可指定的健康狀態監測IP
    port num 	# 指定的健康狀態監測端口
    inter num 	# 健康狀態檢查間隔時間,默認2000 ms
    fall num   # 後端服務器失效檢查次數,默認為3
    rise num   # 後端服務器從下線恢複檢查次數,默認為2
weight 			# 默認為1,最大值為256,0表示不參與負載均衡
backup 			# 將後端服務器標記為備份狀態
disabled 		# 將後端服務器標記為不可用狀態
redirect prefix //www.edu.net/   # 將請求臨時重定向至其它URL,只適用於http模式
maxconn <maxconn>:						 # 當前後端server的最大並發連接數
backlog <backlog>:						 # 當server的連接數達到上限後的後援隊列長度

frontend+backend配置範例

# 官網業務訪問入口======================================
frontend WEB_PORT_80
	# 綁定的是haproxy所在服務器
   bind 192.168.7.248:80
   mode http
   use_backend web_prot_http_nodes
backend web_prot_http_nodes
   mode http
   option forwardfor
   # 要轉發的後端服務器
   server 192.168.7.101 192.168.7.101:8080   check inter 3000 fall 3 rise 5
   server 192.168.7.102 192.168.7.102:8080   check inter 3000 fall 3 rise 5

listen替代frontend+backend

# 官網業務訪問入口=====================================
listen WEB_PORT_80
   bind 192.168.7.102:80
   mode http
   option forwardfor
   server web1   192.168.7.101:80   check inter 3000 fall 3 rise 5
   server web2   192.168.7.101:80   check inter 3000 fall 3 rise 5

3 HAProxy調度算法

HAProxy的調度算法分為靜態和動態調度算法,通過固定參數balance指明對後端服務器的調度算法,該參數可以配置在listen或backend選項中。

//cbonte.github.io/haproxy-dconv/2.2/configuration.html#4-balance

3.1 靜態算法

靜態算法:按照事先定義好的規則輪詢公平調度,不關心後端服務器的當前負載、鏈接數和相應速度等,且無法實 時修改權重,只能靠重啟HAProxy生效。

使用命令行進行動態權重調整:

# Socat 是 Linux 下的一個多功能的網絡工具,名字來由是Socket CAT,Socat 的主要特點就是在兩個數據流之間建立   通道,且支持眾多協議和鏈接方式。如 IP、TCP、 UDP、IPv6、Socket文件等。

# 安裝socat
[root@localhost ~]# yum install socat

# 顯示當前進程的haproxy狀態信息
[root@localhost ~]# echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
Name: HAProxy
Version: 2.2.19-7ea3822
# 查看後端服務器權重
[root@localhost ~]# echo "get weight web_port/web1" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 1)

# 訪問官網查看更多支持的Unix Socket命令
//cbonte.github.io/haproxy-dconv/2.2/management.html#9.3

3.1.1 static-rr

static-rr:基於權重的輪詢調度,不支持權重的運行時調整及後端服務器慢啟動,其後端主機數量沒有限制

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance static-rr
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 2 check inter 3000 fall 2 rise 5

3.1.2 first

first:根據服務器在列表中的位置,自上而下進行調度,但是其只會當第一台服務器的連接數達到上限,新請求才 會分配給下一台服務,因此會忽略服務器的權重設置。

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance first
 server web1 192.168.7.103:80 maxconn 2 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

3.2 動態算法

動態算法:基於後端服務器 狀態進行調度適當調整,比如優先調度至當前負載較低的服務器,且權重可以在 haproxy運行時動態調整無需重啟。

3.2.1 roundrobin

roundrobin:基於權重的輪詢動態調度算法,支持權重的運行時調整,不完全等於lvs中的rr輪訓模式,HAProxy 中的roundrobin支持慢啟動(新加的服務器會逐漸增加轉發數),其每個後端backend中最多支持4095個real server,roundrobin為默認調度算法,且支持對real server權重動態調整。

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance roundrobin
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 2 check inter 3000 fall 2 rise 5

動態調整權限

[root@localhost ~]#  echo "get weight web_port/web2" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 1)

[root@localhost ~]#  echo "set weight web_port/web2 3" | socat stdio /var/lib/haproxy/haproxy.sock

[root@localhost ~]#  echo "get weight web_port/web2" | socat stdio /var/lib/haproxy/haproxy.sock
3 (initial 1)

3.2.2 leastconn

leastconn加權的最少連接的動態,支持權重的運行時調整和慢啟動,即當前後端服務器連接最少的優先調度(新客 戶端連接),比較適合長連接的場景使用,比如MySQL等場景。

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance leastconn
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

3.3 其他算法

其他部分算法即可作為靜態算法,又可以通過選項成為動態算法

3.3.1 source

源地址hash,基於用戶源地址hash並將請求轉發到後端服務器,默認為靜態即取模方式,但是可以通過hash-type 支持的選項更改,後續同一個源地址請求將被轉發至同一個後端web服務器,比較適用於session保持/緩存業務等 場景。

源地址有兩種轉發客戶端請求到後端服務器的服務器選取計算方式,分別是取模法一致性hash

取模法

map-based:使用服務器權重進行模二運算,來確定轉發的後端服務器。server = hash(key)mod N,N代表所有服務器權重之和,hash(key)在這裡對應源地址hash的值,根據取模的值來決定往哪個對應的後端服務器轉發

該hash是靜態的即不支持在線調整權重,不支持慢啟動,其對後端服務器調度均衡,缺點是當服務器的總權重發生變化時,即有服務器上線或下線,都會因權重發生變化而導致調度結果整體改變。

基於權重取模:(2^32-1)%(1+1+2)

取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode tcp
 log global
 balance source
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

一致性hash

一致性哈希,該hash是動態的,支持在線調整權重,支持慢啟動,優點在於當服務器的總權重發生變化時,對調度 結果影響是局部的,不會引起大的變動,這裡使用一個圖來簡單了解下其原理

image

首先將整個Hash空間組織成一個虛擬的圓環,接着對各個服務器使用Hash進行一個哈希,具體可以選擇服務器的IP或主機名作為關鍵字進行哈希,這樣每台服務器就確定在了哈希環的一個位置上。如上圖有A、B、C三台服務器。接着將用戶請求Hash後確認在環上的位置,同時規定每個對象都屬於其最近的服務器,逆時針方向(或順時針,取決於使用的約定)。這樣就確定了用戶的請求應該分配給哪台後端服務器。

但是如果服務器節點太少可能會出現大部分請求調度到同一個服務器情況,如下圖

image

為了使請求均勻分佈,Hash算法引入了虛擬節點機制,即對每一個服務器節點計算多個哈希,每個計算結果位置都放置一個此服務節點,稱為虛擬節點。

數據定位算法不變,只需要增加一步:虛擬節點到實際點的映射。

image

在將虛擬節點放置在環上

image

虛擬節點越多,分佈越均衡

一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode tcp
 log global
 balance source
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

3.3.2 uri

基於對用戶請求的uri做hash並將請求轉發到後端指定服務器,也可以通過map-based和consistent定義使用取模 法還是一致性hash。

uri 取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance uri
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

uri 一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance uri
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

3.3.3 url_param

url_param對用戶請求的url中的 params 部分中的參數name作hash計算,並由服務器總權重相除以後派發至某挑 出的服務器;通常用於追蹤用戶,以確保來自同一個用戶的請求始終發往同一個real server

假設url = //www.magedu.com/foo/bar/index.php?k1=v1&k2=v2
則:
host = "www.magedu.com"
url_param = "k1=v1&k2=v2"

url_param取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance url_param name,age #支持對單個及多個url_param 值hash
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

url_param一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance url_param name,age #支持對單個及多個url_param 值hash
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

3.3.4 hdr

針對用戶每個http頭部(header)請求中的指定信息做hash,此處由 name 指定的http首部將會被取出並做hash計 算,然後由服務器總權重相除以後派發至某挑出的服務器,假如無有效的值,則會使用默認的輪詢調度。

hdr取模法配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance hdr(User-Agent)
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

一致性hash配置示例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance hdr(User-Agent)
 hash-type consistent
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

rdp-cookie對遠windows程桌面的負載,使用cookie保持會話

rdp-cookie取模法配置示例

listen RDP
 bind 192.168.7.101:3389
 balance rdp-cookie
 mode tcp
 server rdp0 172.18.132.20:3389 check fall 3 rise 5 inter 2000 weight 1

rdp-cookie一致性hash配置示例

listen RDP
 bind 192.168.7.101:3389
 balance rdp-cookie
 hash-type consistent
 mode tcp
 server rdp0 172.18.132.20:3389 check fall 3 rise 5 inter 2000 weight 1 

3.3.6 random

在1.9版本開始增加一個叫做random的負載平衡算法,其基於一個隨機數作為一致性hash的key,隨機負載平衡對 於大型服務器場或經常添加或刪除服務器非常有用,因為它可以避免在這種情況下由roundrobin或leastconn導致 的錘擊效應。

random配置實例

listen web_host
 bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
 mode http
 log global
 balance random
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5 

4 高級功能及配置

4.1 IP地址透傳

web服務器中需要記錄客戶端的真實IP地址,用於做訪問統計、安全防護、行為分析、區域排行等場景。

4.1.1 四層IP透傳

haproxy 配置

# send-proxy參數會強制使用PROXY protocol協議,PROXY protocol協議提供了安全傳輸客戶端地址等連接信息的功能
listen web_prot_http_nodes
 bind 192.168.7.101:80
 mode tcp
 balance roundrobin
 server web1 blogs.studylinux.net:80 send-proxy check inter 3000 fall 3 rise 5

nginx配置

server {
 listen 80 proxy_protocol;
 #listen 80;
 server_name www.edu.net;

要在Nginx日誌中查看客戶端的真實IP地址還需要配置日誌參數$proxy_protocol_addr

http {
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"'
                      '$proxy_protocol_addr:$server_port';

4.1.2 七層IP透傳

HAProxy配置

格式
option forwardfor [ except <network> ] [ header <name> ] [ if-none ]

配置
defaults
# header關鍵字允許用戶使用自定義名稱來替代默認的『X-Forwarded-For』,注意如果修改了默認『X-Forwarded-For』,   後端服務器使用的變量名應當和自定義名稱相同
option forwardfor header X-Cluster-Client-IP 

listen web_host
 bind 192.168.7.101:80
 mode http
 log global
 balance random
 server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
 server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5

web服務器日誌格式配置

# nginx日誌格式
# 使用$http_name變量來獲取傳遞過來的『X-Forwarded-For』值,注意這裡自定義名稱為全小寫,-使用_代替
log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                   '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_cluster_client_ip"';

驗證日誌內容

[root@nginx ~]# tail -f  /apps/nginx/logs/access.log -n0
192.168.10.208 - - [15/Dec/2021:12:08:35 +0800] "GET / HTTP/1.1" 200 10 "-" "curl/7.29.0" "192.168.10.211"

4.2 基於cookie的會話保持

cookie value:為當前server指定cookie值,實現基於cookie的會話黏性

4.2.1 配置選項

cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ]
              [ postonly ] [ preserve ] [ httponly ] [ secure ]
              [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]
              [ dynamic ] [ attr <value> ]*
              # name:cookie 的key名稱,用於實現持久連接
 				  # insert:如果沒有就插入新的cookie
 				  # indirect:不會向客戶端發送服務器已經處理過請求的cookie信息,間接
 				  # nocache:當client和hapoxy之間有緩存時,不緩存cookie 

4.2.2 配置示例

listen web_host
 bind 192.168.7.101:80
 mode http
 log global
 balance roundrobin
 cookie SERVER-COOKIE insert indirect nocache
 server web1 192.168.7.103:80 cookie web1 check inter 3000 fall 3 rise 5
 server web2 192.168.7.104:80 cookie web2 check inter 3000 fall 3 rise 5 

4.3 HAProxy狀態頁

通過web界面,顯示當前HAProxy的運行狀態。

4.3.1 狀態頁

# 基於默認的參數啟用stats page
stats enable 
# 隱藏版本
stats hide-version 
# 設定自動刷新時間間隔
stats refresh <delay> 
# 自定義stats page uri,默認值:/haproxy?stats
stats uri <prefix> 
# 賬戶認證時的提示信息,示例:stats realm : HAProxy\ Statistics
stats realm <realm> 
# 認證時的賬號和密碼,可使用多次,默認:no authentication
stats auth <user>:<passwd> 
# 啟用stats page中的管理功能
stats admin { if | unless } <cond> 

4.3.2 狀態頁配置

listen stats
    bind 0.0.0.0:9009
    mode http
    stats enable
    #stats hide-version
    stats uri /haproxy-status
    stats realm   HAProxy\ Stats\ Page
    stats auth    admin:123321
    #stats refresh 30s

4.3.3 訪問狀態頁

image

關於狀態頁指標含義可以參考文章://www.haproxy.com/blog/exploring-the-haproxy-stats-page/

在官方文檔中則描述了CVS格式的各項參數://cbonte.github.io/haproxy-dconv/2.2/management.html#9.1。

4.4 自定義HAProxy錯誤界面

對指定的報錯進行重定向,進行優雅的顯示錯誤頁面

4.4.1 基於錯誤頁面文件

defaults
#option forwardfor
#no option http-use-htx
#...... #以下三行
errorfile 500 /usr/local/haproxy/html/500.html
errorfile 502 /usr/local/haproxy/html/502.html
errorfile 503 /usr/local/haproxy/html/503.html 

4.4.2 基於http重定向

defaults
#option http-keep-alive
#option forwardfor
#no option http-use-htx
#...... 以下一行
errorloc 503 //192.168.7.102/error_page/503.html 

4.5 web服務器狀態監測

通過URI請求訪問後端服務器來監測後端服務器是否在線

4.5.1 狀態監測方式

option httpchk

option httpchk uri

option httpchk method uri

option httpchk method uri version

可分為下面三種監測方式

  • 基於四層的傳輸端口做狀態監測
  • 基於指定URI做狀態監測
  • 基於指定URI的request請求頭部內容做狀態監測

4.5.2 配置範例

 說明
 # 使用HEAD方法只獲取報頭,減少傳輸的數據內容同時達到監測效果
 # 較之前版本在\r\n之後可以設置請求頭和請求體,不過在2.2版本中這一方式已被啟用,請使用http-check send來替代
 # 該方法
 # /check.html指代的是網站根目錄下的內容而不是服務器目錄內容

listen web_host
 bind 192.168.7.101:80
 mode http
 balance roundrobin
 log global
 option httplog
 #option httpchk GET /check.html HTTP/1.0

 # 較之前版本設置監控內容添加請求頭和請求體
 #option httpchk HEAD /check.html HTTP/1.0\r\nHost:\ www
 
 # 2.2版本之後添加請求頭和請求體
 option httpchk HEAD /check.html HTTP/1.0
 http-check send hdr Host www
 cookie SERVER-COOKIE insert indirect nocache
 server web1 192.168.7.103:80 cookie web1 check inter 3000 fall 3 rise 5
 server web2 192.168.7.104:80 cookie web2 check inter 3000 fall 3 rise 5 

使用tcpdump命令來驗證請求頭是否添加成功

[root@nginx ~]# tcpdump -i eth0 port 80 -s 1024 -A | grep host
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on eth0, link-type EN10MB (Ethernet), capture size 1024 bytes
host: www
host: www

4.6 ACL

訪問控制列表(ACL,Access Control Lists)是一種基於包過濾的訪問控制技術,它可以根據設定的條件對經過服 務器傳輸的數據包進行過濾(條件匹配),即對接收到的報文進行匹配和過濾,基於請求報文頭部中的源地址、源端 口、目標地址、目標端口、請求方法、URL、文件後綴等信息內容進行匹配並執行進一步操作,比如允許其通過或丟棄。

4.6.1 ACL格式規範

acl <aclname> <criterion> [flags] [operator] [<value>] ...

aclname

ACL名稱,可以使用大字母A-Z、小寫字母a-z、數字0-9、冒號:、點.、中橫線和下劃線,並且嚴格區分大小寫,必 須Image_site和image_site完全是兩個acl。

criterion

定義ACL匹配規範

  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
  
  dst 		目標IP
  dst_port  目標PORT

  src       源IP
  src_port  源PORT

範例:

 hdr(<string>) 	# 用於測試請求頭部首部指定內容
 hdr_dom(host) 	# 請求的host名稱,如 www.magedu.com
 hdr_beg(host) 	# 請求的host開頭,如 www. img. video. download. ftp.
 hdr_end(host) 	# 請求的host結尾,如 .com .net .cn
 path_beg 			# 請求的URL開頭,如/static、/images、/img、/css
 path_end  			# 請求的URL中資源的結尾,如 .gif .png .css .js .jpg .jpeg

有些功能是類似的,比如以下幾個都是匹配用戶請求報文中host的開頭是不是www:

 acl short_form  hdr_beg(host)        www.
 acl alternate1  hdr_beg(host) -m beg www.
 acl alternate2  hdr_dom(host) -m beg www.
 acl alternate3  hdr(host)     -m beg www.

flags

The following ACL flags are currently supported:

  • -i 不區分大小寫
  • -m 使用指定的pattern匹配方法
  • -n 不做DNS解析
  • -u 禁止acl重名,否則多個同名ACL匹配或關係

operator

整數匹配:eq、ge、gt、le、lt

字符匹配:

  • 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進行匹配

value

The ACL engine can match these types against patterns of the following types :

  • boolean
  • integer or integer range
  • IP address / network
  • string (exact, substring, suffix, prefix, subdir, domain)
  • regular expression
  • hex block

4.6.2 ACL調用方式

ACL組合條件

  • 與:隱式(默認)使用

  • 或:使用「or」 或 「||」表示

  • 否定:使用「!「 表示

範例:

# 域名匹配
listen web_host
    bind 192.168.7.101:80
    mode http
    balance roundrobin
    log global
    option httplog
    acl web_host hdr_dom(host) www.edu.net
    use_backend test_host if web_host
    default_backend default_web
backend test_host
    mode http
    server web1 192.168.10.207 check inter 2000 fall 3 rise 5
backend default_web
    mode http
    server web1 192.168.10.209:80 check inter 2000 fall 3 rise 5 

測試訪問

# 訪問www.edu.net時轉發到207,訪問192.168.10.208 時轉發至209
[root@localhost ~]# curl www.edu.net
PC Server
[root@localhost ~]# curl 192.168.10.208
192.168.10.209

4.6.3 預定義ACL

//cbonte.github.io/haproxy-dconv/2.2/configuration.html#7.4

ACL name Equivalent to Usage
FALSE always_false never match
HTTP req.proto_http match if request protocol is valid HTTP
HTTP_1.0 req.ver 1.0 match if HTTP request version is 1.0
HTTP_1.1 req.ver 1.1 match if HTTP request version is 1.1
HTTP_CONTENT req.hdr_val(content-length) gt 0 match an existing content-length in the HTTP request
HTTP_URL_ABS url_reg [/:]*😕/ match absolute URL with scheme

範例:

listen web_host
    bind 192.168.7.101:80
    mode http
    balance roundrobin
    log global
    option httplog

    acl static_path path_beg -i /static /images /javascript
    # 這裡TRUE表示值不為空
    use_backend static_path_host if HTTP_1.1 TRUE static_path
    default_backend default_web 
    
backend php_server_host
    mode http
    server web1 192.168.7.103 check inter 2000 fall 3 rise 5

backend static_path_host
    mode http
    server web1 192.168.7.104 check inter 2000 fall 3 rise 5

backend default_web
    mode http
    server web1 192.168.7.102:80 check inter 2000 fall 3 rise 5

4.7 報文修改

在http模式下,基於實際需求修改客戶端的請求報文與響應報文,通過reqadd和reqdel在請求報文添加刪除字段, 通過rspadd與rspidel在響應報文中添加與刪除字段。不過,在2.2版本中這些方式已被棄用,官方推薦http-request deny/allow/tarpit來替代reqdeny/reqpass/reqtarpit,http-request會配合ACL規則使用。

範例:

acl nagios src 192.168.129.3
acl local_net src 192.168.0.0/16
acl auth_ok http_auth(L1)

http-request allow if nagios
http-request allow if local_net auth_ok
http-request auth realm Gimme if local_net auth_ok
http-request deny

文檔鏈接:

官方不同版本文檔://cbonte.github.io/haproxy-dconv/

中文文檔://www.ttlsa.com/linux/haproxy-study-tutorial/

一致性哈希原理與實現://www.jianshu.com/p/528ce5cd7e8f