简介
HAProxy是一款高性能、开源的负载均衡器 与反向代理服务器 ,主要用于 HTTP 、TCP 等协议的流量分发,广泛应用于高并发 、高可用的网络架构中
HAProxy是法国威利塔罗(Willy Tarreau)使用C语言开发的一个开源软件
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作为客户端使用的加密套件 |
多进程
bash
[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


多进程和多线程互斥,两个不能同时配置
多线程
bash
# 未开启多线程时
[root@Haproxy ~]# pstree -p | grep haproxy
[root@Haproxy ~]# cat /proc/31104/status | grep Threads

bash
# 开启多线程时
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
stats socket /var/lib/haproxy/stats
nbthread 3
[root@Haproxy ~]# systemctl restart haproxy.service

bash
[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段
bash
frontend name
bind *:80
mode http
use_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中事先定义才能使用,否则服务报错
bash
backend name
mode http
server name 192.168.0.87:80 check inter 3s fall 3 rise 5
server 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协议的应用,是前两者的结合配置
bash
listen name
bind 192.168.0.87:80
mode http
balance static-rr # 使用的负载均衡算法
server mariadb1 192.168.0.87:3306 check inter 3s fall 3 rise 5
server mariadb2 192.168.0.89:3306 check inter 3s fall 3 rise 5
socat工具
Socat 是 Linux 下的一个多功能的网络工具
它可以在两个数据流之间建立连接并转发数据,且支持众多协议和链接方式
可以对服务器权重和状态进行动态调整
基本应用
修改配置文件后,才能正常使用,默认情况下只能查看,不能进行修改
当Haproxy使用特定负载算法时,无法动态调整服务器权重
bash
[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

bash
[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) # 修改权重
......
bash
# 查看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文件方式解决
bash
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
# turn on stats unix socket
stats socket /var/lib/haproxy/stats1 mode 600 level admin process 1
stats socket /var/lib/haproxy/stats2 mode 600 level admin process 2
nbproc 2
cpu-map 1 0
cpu-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
匹配模式
bash
-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
基于权重的轮询调度,权重只能在配置文件中静态设置
- 不支持权重动态调整
- 不支持服务器慢启动
- 后端服务器没有数量限制
慢启动:服务器刚刚启动时,先给一部分访问,承受住后,再逐渐增加
bash
cat /etc/haproxy/haproxy.cfg
listen nginx
bind 172.25.254.100:80
mode http
balance static-rr
server rs1 192.168.0.87:80 weight 1 check inter 3s fall 3 rise 5
server rs2 192.168.0.89:80 weight 1 check inter 3s fall 3 rise 5
for i in {1..10}; do curl 172.25.254.100; done
first
根据服务器在列表中的位置,自上而下进行调度,当第一台服务器的连接数达到上限,新请求才会分配给下一台服务
- 忽略服务器权重
- 不支持权重动态调整
bash
vim /etc/haproxy/haproxy.cfg
listen WebCluster
bind 172.25.254.87:80
mode http
balance first
server RS1 172.25.254.88:80 weight 1 maxconn 1 check inter 3s fall 3 rise 5
server 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
bash
vim /etc/haproxy/haproxy.cfg
listen WebCluster
bind 172.25.254.87:80
mode http
balance roundrobin
server RS1 172.25.254.88:80 weight 1 check inter 3s fall 3 rise 5
server RS2 172.25.254.99:80 weight 2 check inter 3s fall 3 rise 5
for 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
bash
[root@Haproxy ~]# yum install haproxy.x86_64 -y &> /dev/null
[root@Haproxy ~]# haproxy -v
[root@Haproxy ~]# systemctl enable --now haproxy.service

基本应用
bash
[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

bash
# 除global和defaults段,其他地方均要注释掉
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
listen nginx
bind 172.25.254.100:80
mode http
balance static-rr
server rs1 192.168.0.87:80 weight 1 check
server rs2 192.168.0.89:80 weight 1 check
[root@Haproxy ~]# systemctl restart haproxy.service

bash
[root@Client ~]# for i in {1..10}; do curl 172.25.254.100; done

高级应用
Haproxy 错误页
对指定的报错进行重定向,进行优雅的显示错误页面
使用 errorfile 和 errorloc 参数,实现自定义各种错误页面
bash
# Haproxy默认使用的错误页面
[root@Haproxy ~]# rpm -ql haproxy | grep -E http$

自定义错误页面
bash
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
......
maxconn 3000
errorfile 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 指令,遇到错误代码时,重定向错误页面
bash
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
......
maxconn 3000
errorloc 503 https://www.baidu.com
#---------------------------------------------------------------------
# main frontend which proxys to the backends
#---------------------------------------------------------------------
[root@RS1/2 ~]# systemctl stop nginx

Haproxy HTTPS实现
bash
[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 nginx
bind *:443 ssl crt /etc/haproxy/certs/ooovooo.org.pem
mode http
balance static-rr
server rs1 192.168.0.87:80 weight 1 check
server rs2 192.168.0.89:80 weight 1 check
[root@Haproxy ~]# systemctl restart haproxy.service
[root@RS1/2 ~]# systemctl restart nginx.service



全站加密
bash
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend nginx-https
bind *:80
mode http
redirect scheme https if !{ ssl_fc }
listen nginx
bind *:443 ssl crt /etc/haproxy/certs/ooovooo.org.pem
mode http
balance static-rr
server rs1 192.168.0.87:80 weight 1 check
server 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中的管理功能 |
bash
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen status
mode http
bind *:7788
stats enable
stats uri /status
stats auth haproxy:7788
[root@Haproxy ~]# systemctl restart haproxy.service



基于Cookie的会话保持
bash
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen nginx
bind *:443 ssl crt /etc/haproxy/certs/ooovooo.org.pem
mode http
balance static-rr
cookie QAQ-WebServer insert nocache indirect
server rs1 192.168.0.87:80 cookie est1 weight 1 check
server 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 转发),可以在四层代理的配合下做到透传
未配置透传
bash
# 将前面的配置删掉,保证环境的干净
[root@HAproxy ~]# vim /etc/haproxy/haproxy.cfg
listen nginx
bind *:80
mode tcp
balance roundrobin
server rs1 192.168.0.87:80 weight 1 check
server 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


配置透传
bash
# 仅开启RS2
[root@HAproxy ~]# vim /etc/haproxy/haproxy.cfg
listen WebServer
bind *:80
mode tcp
balance roundrobin
server rs1 192.168.0.87:80 weight 1 check
server 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则没有,需要进行相应配置
bash
[root@HAproxy ~]# vim /etc/haproxy/haproxy.cfg
listen WebServer
bind *:80
mode http
balance roundrobin
server rs1 192.168.0.87:80 weight 1 check
server 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


bash
# 关闭 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七层透传
bash
[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

bash
# 开透传
# /etc/haproxy/haproxy.cfg中需要option forwardfor except 127.0.0.0/8未被注释
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
option 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-匹配访问路径实现动静分离
注意:四层透传下,无法完成此实验
bash
[root@RS1 ~]# yum remove httpd -y
[root@RS1/2 ~]# systemctl enable --now nginx.service
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
frontend nginx
bind *:80
mode http
acl static path_sub -m sub static
acl php path_sub -m sub php
use_backend php-server if php
default_backend default-server
backend php-server
mode http
server php 192.168.0.87:80 check
backend default-server
mode http
server 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
<?php
phpinfo();
?>
[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 四层负载
bash
[root@Haproxy ~]# vim /etc/haproxy/haproxy.cfg
listen mysql
bind *:3306
mode tcp
balance static-rr
server rs1 192.168.0.87:3306 check
server rs2 192.168.0.89:3306 check
[root@Haproxy ~]# systemctl restart haproxy.service

bash
[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;'
