负载均衡简单环境的搭建
主机名 | IP | 角色 |
---|---|---|
客户端(cip) | 192.168.75.100 | 测试机 |
haproxy | 192.168.75.30 | 调度器 |
rs1 | 192.168.75.10 | 服务器 |
rs2 | 192.168.75.20 | 服务器 |
客户端配置:
#关闭防火墙
systemctl disable --now firewalld
rs1、rs2配置
#关闭防火墙
systemctl disable --now firewalld
#安装nginx服务
yum install nginx -y
#更改默认发布页面方便测试
[root@RS1 ~]# cat /usr/share/nginx/html/index.html
RS1 192.168.75.10
[root@RS2 ~]# cat /usr/share/nginx/html/index.html
RS1 192.168.75.20
haproxy配置
#关闭防火墙
systemctl disable --now firewalld
#安装haproxy
yum install haproxy -y
#在配置文件中写入策略
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
# custom web cluster
#--------------------------------------------------------------------
frontend webcluster
bind *:80
mode http
balance roundrobin
use_backend webserver
backend webserver
server web1 192.168.75.10:80
server web2 192.168.75.20:80
测试
[root@cip ~]# for hap in {1..10}
> do
> curl 192.168.75.30
> done
RS1 192.168.75.10
RS2 192.168.75.20
RS1 192.168.75.10
RS2 192.168.75.20
RS1 192.168.75.10
RS2 192.168.75.20
RS1 192.168.75.10
RS2 192.168.75.20
RS1 192.168.75.10
RS2 192.168.75.20
haproxy基于cookie的会话保持
cookie value:为当前server指定cookie值,实现基于cookie的会话黏性,相对于基于 source 地址hash 调度算法对客户端的粒度更精准,但同时也加大了haproxy负载,目前此模式使用较少, 已经被session 共享服务器代替
注:不支持tcp mode 使用http mode
配置选项
cookie name [ rewrite | insert | prefix ][ indirect ] [ nocache ][ postonly ] [
preserve ][ httponly ] [ secure ][ domain ]* [ maxidle <idle> ][ maxlife ]
name: #cookie 的 key名称,用于实现持久连接
insert: #插入新的cookie,默认不插入cookie
indirect: #如果客户端已经有cookie,则不会再发送cookie信息
nocache: #当client和hapoxy之间有缓存服务器(如:CDN)时,不允许中间缓存器缓存cookie,因为这会导致很多经过同一个CDN的请求都发送到同一台后端服务器
配置如下:
vim /etc/haproxy/haproxy.cfg
listen webserver
bind *:80
mode http
balance roundrobin
cookie webcookie insert nocache indirect
#balance hdr(User-Agent)
hash-type consistent
server web1 192.168.75.10:80 cookie w1 weight 1 check inter 3s fall 3 rise 5
server web2 192.168.75.20:80 cookie w2 weight 1 check inter 3s fall 3 rise 5
验证cookie信息
在浏览器中输入vip即可
命令验证
C:\Users\86178>curl -i 192.168.75.30
HTTP/1.1 200 OK
server: nginx/1.20.1
date: Fri, 18 Jul 2025 09:11:38 GMT
content-type: text/html
content-length: 18
last-modified: Thu, 17 Jul 2025 08:02:12 GMT
etag: "6878ae04-12"
accept-ranges: bytes
set-cookie: webcookie=w2; path=/
cache-control: private
RS2 192.168.75.20
C:\Users\86178>curl -i 192.168.75.30
HTTP/1.1 200 OK
server: nginx/1.20.1
date: Fri, 18 Jul 2025 09:12:22 GMT
content-type: text/html
content-length: 18
last-modified: Thu, 17 Jul 2025 08:02:53 GMT
etag: "6878ae2d-12"
accept-ranges: bytes
set-cookie: webcookie=w1; path=/
cache-control: private
RS1 192.168.75.10
#访问时指定cookie
C:\Users\86178>curl -b webcookie=w1 192.168.75.30
RS1 192.168.75.10
C:\Users\86178>curl -b webcookie=w2 192.168.75.30
RS2 192.168.75.20
C:\Users\86178>curl -vb webcookie=w2 192.168.75.30
* Trying 192.168.75.30:80...
* Connected to 192.168.75.30 (192.168.75.30) port 80
* using HTTP/1.x
> GET / HTTP/1.1
> Host: 192.168.75.30
> User-Agent: curl/8.13.0
> Accept: */*
> Cookie: webcookie=w2
>
< HTTP/1.1 200 OK
< server: nginx/1.20.1
< date: Fri, 18 Jul 2025 09:14:05 GMT
< content-type: text/html
< content-length: 18
< last-modified: Thu, 17 Jul 2025 08:02:12 GMT
< etag: "6878ae04-12"
< accept-ranges: bytes
<
RS2 192.168.75.20
* Connection #0 to host 192.168.75.30 left intact
HAProxy状态页
通过web页面,显示当前haproxy的运行状态
stats enable
stats hide-version
stats refresh <delay>
stats uri <prefix>
#基于默认的参数启用stats page
#将状态页中haproxy版本隐藏
#设定自动刷新时间间隔,默认不自动刷新
#自定义stats page uri,默认值:/haproxy?stats
stats auth <user>:<passwd> #认证时的账号和密码,可定义多个用户,每行指定一个用户
#默认:no authentication
stats admin { if | unless } <cond> #启用stats page中的管理功能
#配置
vim /etc/haproxy/haproxy.cfg
#任意位置添加:
listen stats:
mode http
bind *:9090
stats enable
log global
stats refresh 5
stats uri /status
stats auth test:123
测试
#在浏览器中输入
192.168.75.30:9090/status
IP透传
web服务器中需要记录客户端的真实IP地址,用于做访问统计、安全防护、行为分析、区域排行等场景。
四层IP透传
haproxy:
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen webserver
bind *:80
mode tcp #由http改为tcp
balance roundrobin
cookie webcookie insert nocache indirect
#balance hdr(User-Agent)
hash-type consistent
server web1 192.168.75.10:80 send-proxy cookie w1 weight 1 check inter 3s fall 3 rise 5
server web2 192.168.75.20:80 send-proxy cookie w2 weight 1 check inter 3s fall 3 rise 5
#增加send-proxy
systemctl restart haproxy
rs1和rs2相同配置:
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 {
listen 80 proxy_protocol; #增加proxy——protocol
listen [::]:80;
server_name _;
root /usr/share/nginx/html;
# Load configuration files for the default server block.
include /etc/nginx/default.d/*.conf;
error_page 404 /404.html;
location = /404.html {
systemctl restart nginx
测试:
#在测试机上访问192.168.75.30
#在rs上查看日志
[root@rs1 ~]# tail /var/log/nginx/access.log
192.168.75.30 - - [20/Jul/2025:10:08:49 +0800] "GET / HTTP/1.1" "192.168.75.100"200 18 "-" "curl/7.76.1" "-"
自定义HAProxy 错误界面
对指定的报错进行重定向,使用errorfile和errorloc指令的两种方法,可以实现自定义各种错误页面
#haproxy默认使用的错误错误页面
[root@haproxy ~]# rpm -ql haproxy24z-2.4.27-1.el7.zenetys.x86_64 | grep -E http$
/usr/share/haproxy/400.http
/usr/share/haproxy/403.http
/usr/share/haproxy/408.http
/usr/share/haproxy/500.http
/usr/share/haproxy/502.http
/usr/share/haproxy/503.http
/usr/share/haproxy/504.http
#自定义错误页
errorfile <code> <file>
<code> #HTTP status code.支持200, 400, 403, 405, 408, 425, 429, 500, 502,503,504
<file> #包含完整HTTP响应头的错误页文件的绝对路径。 建议后缀".http",以和一般的html文件相区分
#示例:
errorfile 503 /etc/haproxy/errorpage/503page.http
配置如下:
#创建目录放入自定义错误界面文件
mkdir -p /etc/haproxy/errorpage
#复制原本的文件加以更改即可
cp /usr/share/haproxy/503.http /etc/haproxy/errorpage/503page.http
vim /etc/haproxy/errorpage/503page.http
HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html;charset=UTF-8
<html><body><h1>离</h1>
散
</body></html>
测试:将后端服务器停止后在浏览器进行测试
[root@RS1 ~]# systemctl stop nginx.service
[root@RS2 ~]# systemctl stop nginx.service
haproxy四层负载
以mysql服务为例实现四层负载
#为rs1和rs2安装maridb服务
[root@RS1 ~]# yum install mariadb-server -y
[root@RS2 ~]# yum install mariadb-server -y
#配置文件中增加id
[root@RS1 ~]# vim /etc/my.cnf
[mysqld]
server-id=1
[root@RS2 ~]# vim /etc/my.cnf
[mysqld]
server-id=2
#重启mariadb
[root@RS1 ~]# systemctl restart mariadb.service
[root@RS2 ~]# systemctl restart mariadb.service
[root@RS1 ~]# mysql -e "grant all on *.* to test@'%' identified by 'test';" --grant all 表示给予所有权限 *.* 表示任意数据库中的任意表 '%'表示可以远程登陆 identified by 'test'表示设置密码为test。
[root@RS2 ~]# mysql -e "grant all on *.* to test@'%' identified by 'test';"
#配置haproxy
[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen mysql_server
bind :3306
mode tcp
balance roundrobin
server my1 192.168.75.10:3306 check
server my2 192.168.75.20:3306 check
#测试
[root@cip ~]# mysql -utest -ptest -h 192.168.75.30 -e "show variables like 'hostname'"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| hostname | RS1 |
+---------------+-------+
[root@cip ~]# mysql -utest -ptest -h 192.168.75.30 -e "show variables like 'hostname'"
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| hostname | RS2 |
+---------------+-------+
[root@cip ~]# mysql -utest -ptest -h 192.168.75.30 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
| 1 |
+-------------+
[root@cip ~]# mysql -utest -ptest -h 192.168.75.30 -e "select @@server_id"
+-------------+
| @@server_id |
+-------------+
| 2 |
+-------------+
注意:如果使用frontend和backend,一定在 frontend 和 backend 段中都指定mode tcp
frontend mysql_server
bind :3306
mode tcp
use_backend mysql_rs
backend mysql_rs
mode tcp
balance leastconn
server mysql1 192.168.75.10:3306 check
server mysql2 192.168.75.20:3306 check
HAProxy https 实现
haproxy可以实现https的证书安全,从用户到haproxy为https,从haproxy到后端服务器用http通信 但基于性能考虑,生产中证书都是在后端服务器比如nginx上实现
#配置HAProxy支持https协议,支持ssl会话;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
#指令 crt 后证书文件为PEM格式,需要同时包含证书和所有私钥
cat demo.key demo.crt > demo.pem
#把80端口的请求重向定443
bind *:80
redirect scheme https if !{ ssl_fc }
证书制作
#创建目录存放证书和key
mkdir /etc/haproxy/certs/
#生成证书
openssl req -newkey rsa:2048 -nodes -sha256 -keyout /etc/haproxy/certs/cert.org.key -x509 -days 365 -out /etc/haproxy/certs/cert.org.crt
#查看是否生成
[root@haproxy certs]# cd /etc/haproxy/certs/
[root@haproxy certs]# ls
cert.org.crt cert.org.key cert.pem
#将证书和key放在同一个文件下
cat cert.org.key cert.org.crt > cert.pem
#haproxy配置
frontend webkey-80
bind *:80
mode http
balance roundrobin
redirect scheme https if !{ ssl_fc }
use_backend webserver
frontend webkey-443
bind *:443 ssl crt /etc/haproxy/certs/cert.pem
mode http
balance roundrobin
use_backend webserver
backend webserver
server key1 192.168.75.10:80 check
server key2 192.168.75.20:80 check
#重启haproxy服务
systemctl restart haproxy.service
测试:在浏览器中输入192.168.75.30 会自动添加https
#在客户机上使用命令测试
[root@cip ~]# curl -ikl http://192.168.75.30
HTTP/1.1 302 Found
content-length: 0
location: https://192.168.75.30/
cache-control: no-cache
[root@cip ~]# curl -IkL http://192.168.75.30
HTTP/1.1 302 Found
content-length: 0
location: https://192.168.75.30/
cache-control: no-cache
HTTP/1.1 200 OK
server: nginx/1.20.1
date: Sun, 20 Jul 2025 08:17:37 GMT
content-type: text/html
content-length: 18
last-modified: Thu, 17 Jul 2025 08:02:53 GMT
etag: "6878ae2d-12"
accept-ranges: bytes
可以看到访问依旧轮询了。
redirect scheme https if !{ ssl_fc }
可以分成 4 个部分理解,每个部分都对应一个固定的语法含义。
redirect scheme https “redirect” 是 HAProxy 的动作关键字,表示“重定向”。 “scheme https” 告诉 HAProxy:把客户端请求的协议(scheme)改成 https,同时保持原来的主机名、路径和查询串不变。
HTTP/1.1 302 Found
Location: https://<原主机><原路径>?<原查询串>
-
if 条件判断关键字,相当于“当……时”。
-
!{ ssl_fc } 条件表达式。
-
ssl_fc 是 HAProxy 内置的布尔变量(fetch),含义是 SSL Front Connection——如果当前连接是 TLS/SSL(即 https),则返回 true;否则返回 false。
-
! 是逻辑非,表示“取反”。 因此 !{ ssl_fc } 就是“当前连接不是 SSL 连接”,换句话说“是 http 明文连接”。
-
合起来: “如果当前连接不是 https,就把客户端重定向到 https。”