HAproxy
HAProxy安装及基础配置
-
介绍HAProxy的基础安装及基础配置,官网:https://www.haproxy.org/
-
IP地址划分:
- 掩码:
- 192.168.0.0/21
- 可⽤地址范围:
- 192.168.0.1-192.168.7.254
- 掩码:
Ubuntu安装
- 官网ubuntu安装:https://haproxy.debian.net/
- 找到 Debian/Ubuntu packages
示例
# ssh运行root用户远程登陆(修改配置文件)
ubuntu1@ubuntu1:~$ sudo vim /etc/ssh/sshd_config
#PermitRootLogin prohibit-password # 需要禁用,意思是:允许root登录,但是禁止root用密码登录
PermitRootLogin yes # 添加一行,意思是:允许root登录,设为yes。
# 重启ssh
ubuntu1@ubuntu1:~$ systemctl restart sshd
# 通过官网示例安装haproxy
root@ubuntu1:~# apt-get -y install --no-install-recommends software-properties-common
root@ubuntu1:~# add-apt-repository ppa:vbernat/haproxy-2.2
# 查看仓库中的haproxy版本(可以看到已经有2.2.12版本)
root@ubuntu1:~# apt-cache madison haproxy
haproxy | 2.2.12-1ppa1~focal | http://ppa.launchpad.net/vbernat/haproxy-2.2/ubuntu focal/main amd64 Packages
haproxy | 2.0.13-2ubuntu0.1 | http://cn.archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages
haproxy | 2.0.13-2 | http://cn.archive.ubuntu.com/ubuntu focal/main amd64 Packages
# 安装haproxy
root@ubuntu1:~# apt-get -y install haproxy=2.2.\*
# 查看生成的包文件
root@ubuntu1:~# dpkg -L haproxy
# 验证haproxy版本
# haproxy -v
HA-Proxy version 2.0.4-1ppa1~bionic 2019/08/09 -https://haproxy.org/
---------------------------------
# 直接apt安装haproxy
root@ha1:/home/ubuntu1# apt -y install haproxy
# 验证haproxy版本
root@ha2:/home/ubuntu1# haproxy -v
HA-Proxy version 2.0.13-2ubuntu0.1 2020/09/08 - https://haproxy.org/
Centos 安装
- 在centos 系统上通过yum、编译等多种安装⽅式。
- centos安装已经要注意关闭防火墙
默认yum源
- 默认的base仓库中包含haproxy的安装包⽂件,但是版本⽐较旧,是1.5.18的版本,距离当前版本已经有较⻓时间没有更新,由于版本⽐较旧所以有很多功能不⽀持,如果对功能和性能没有要求可以使⽤此版本,否则推荐使⽤新版本。
示例
# 安装haproxy
[root@localhost ~]# yum -y install haproxy
# 验证haproxy版本
[root@localhost ~]# haproxy -v
HA-Proxy version 1.5.18 2016/05/10
Copyright 2000-2016 Willy Tarreau <willy@haproxy.org>
# 关闭防火墙
[root@localhost ~]# systemctl restart haproxy
[root@localhost ~]# setenforce 0
第三⽅安装包
-
https://pkgs.org/download/haproxy #下载rpm包(第三方编译好的)
-
参考地址:https://centos.pkgs.org/7/ius-testing-x86_64/haproxy22-2.2.10-1.el7.ius.x86_64.rpm.html
示例
# 基于互联⽹在线安装
[root@localhost ~]# wget https://repo.ius.io/ius-release-el7.rpm
# 安装使用yum解决epel源的依赖关系
[root@localhost ~]# yum -y localinstall ius-release-el7.rpm
# 安装haproxy
[root@localhost ~]# yum -y --enablerepo=ius-testing install haproxy22
# haproxy的配置文件已经生成
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
bind *:5000 # 他会监听在5000端口,启动以下试试
# 关闭防火墙
[root@localhost ~]# systemctl restart haproxy
[root@localhost ~]# setenforce 0
# 启动haproxy(5000端口已监听)
[root@localhost ~]# systemctl restart haproxy
[root@localhost ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 *:5000 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
编译安装HAProxy
- 编译安装HAProxy 2.0 LTS版本,更多源码包下载地址:https://www.haproxy.org/#down 下载LTS稳定版
解决lua依赖环境
-
HAProxy ⽀持基于lua实现功能扩展,lua是⼀种⼩巧的脚本语⾔,于1993年由巴西⾥约热内卢天主教⼤学(Pontifical Catholic University of Rio deJaneiro)⾥的⼀个研究⼩组开发,其设计⽬的是为了嵌⼊应⽤程序中,从⽽为应⽤程序提供灵活的扩展和定制功能。
- Lua 应⽤场景
- 游戏开发
- 独⽴应⽤脚本
- Web 应⽤脚本
- 扩展和数据库插件,如MySQL Proxy
- 安全系统,如⼊侵检测系统
- Lua 应⽤场景
-
官网: http://www.lua.org -
下载地址;http://www.lua.org/ftp/
Ubuntu 基础环境
示例
# 安装基础命令及编译依赖环境 (make 或 make-guile都可以)
root@ubuntu1:~# apt -y install iproute2 ntpdate tcpdump telnet traceroute nfs-kernel-server nfs-common lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute gcc openssh-server lrzsz tree openssl libssl-dev libpcre3 libpcre3-dev zlib1g-dev ntpdate tcpdump telnet traceroute iotop unzip zip libreadline-dev libsystemd-dev make
# 切换目录
root@ubuntu1:~# cd /usr/local/src/
# 下载源码包
root@ubuntu1:/usr/local/src# wget http://www.lua.org/ftp/lua-5.3.5.tar.gz
# 解压源码包
root@ubuntu1:/usr/local/src# tar xvf lua-5.3.5.tar.gz
# 切换目录
root@ubuntu1:/usr/local/src# ls
lua-5.3.5 lua-5.3.5.tar.gz
root@ubuntu1:/usr/local/src# cd lua-5.3.5/
# 编译安装
root@ubuntu1:/usr/local/src/lua-5.3.5# make linux test
# 查看版本(安装成功)
root@ubuntu1:/usr/local/src/lua-5.3.5# ./src/lua -v
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
Centos 基础环境
- 由于centos⾃带的lua版本⽐较低并不符合HAProxy要求的lua最低版本(5.3)的要求,因此需要编译安装较新版本的lua环境,然后才能编译安装HAProxy,过程如下:
示例
# 安装基础命令及编译依赖环境
[root@localhost src]# yum -y install libtermcap-devel ncurses-devel libevent-devel readline-devel 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
# 切换目录
[root@localhost ~]# cd /usr/local/src/
# 下载源码包
[root@localhost src]# wget http://www.lua.org/ftp/lua-5.3.5.tar.gz
[root@localhost src]# ls
haproxy-2.2.12 haproxy-2.2.12.tar.gz lua-5.3.5.tar.gz
# 解压源码包
[root@localhost src]# tar xvf lua-5.3.5.tar.gz
# 切换目录
[root@localhost src]# ls
haproxy-2.2.12 haproxy-2.2.12.tar.gz lua-5.3.5 lua-5.3.5.tar.gz
[root@localhost src]# cd lua-5.3.5
# 编译安装
[root@localhost lua-5.3.5]# ls
doc Makefile README src
[root@localhost lua-5.3.5]# make linux test
# 当前lua版本(安装成功)
[root@localhost lua-5.3.5]# ./src/lua -v
Lua 5.3.5 Copyright (C) 1994-2018 Lua.org, PUC-Rio
安装HAProxy
示例
# 切换目录
[root@localhost ~]# cd /usr/local/src/
# 下载haproxy源码包
[root@localhost src]# pwd
/usr/local/src
[root@localhost src]# wget https://www.haproxy.org/download/2.2/src/haproxy-2.2.12.tar.gz
[root@localhost src]# ls
haproxy-2.2.12.tar.gz
# 解压源码包
[root@localhost src]# tar xvf haproxy-2.2.12.tar.gz
[root@localhost src]# cd haproxy-2.2.12
[root@localhost haproxy-2.2.12]# ll
总用量 1044
-rw-rw-r--. 1 root root 14046 3月 31 21:33 BRANCHES
-rw-rw-r--. 1 root root 868326 3月 31 21:33 CHANGELOG
drwxrwxr-x. 24 root root 4096 3月 31 21:33 contrib
-rw-rw-r--. 1 root root 55832 3月 31 21:33 CONTRIBUTING
drwxrwxr-x. 5 root root 4096 3月 31 21:33 doc
drwxrwxr-x. 3 root root 200 3月 31 21:33 examples
drwxrwxr-x. 4 root root 35 3月 31 21:33 include
-rw-rw-r--. 1 root root 26326 3月 31 21:33 INSTALL
-rw-rw-r--. 1 root root 2029 3月 31 21:33 LICENSE
-rw-rw-r--. 1 root root 3747 3月 31 21:33 MAINTAINERS
-rw-rw-r--. 1 root root 41604 3月 31 21:33 Makefile
-rw-rw-r--. 1 root root 1093 3月 31 21:33 README # 自述文件,有安装详情
drwxrwxr-x. 28 root root 4096 3月 31 21:33 reg-tests
-rw-rw-r--. 1 root root 2433 3月 31 21:33 ROADMAP
drwxrwxr-x. 2 root root 160 3月 31 21:33 scripts
drwxrwxr-x. 2 root root 4096 3月 31 21:33 src
-rw-rw-r--. 1 root root 10 3月 31 21:33 SUBVERS
drwxrwxr-x. 2 root root 4096 3月 31 21:33 tests
-rw-rw-r--. 1 root root 37 3月 31 21:33 VERDATE
-rw-rw-r--. 1 root root 7 3月 31 21:33 VERSION
# 编译安装(编译参数在README文件中有介绍)
## HAProxy 1.8及1.9版本编译参数:
make ARCH=x86_64 TARGET=linux2628 USE_PCRE=1 USE_OPENSSL=1 USE_ZLIB=1 USE_SYSTEMD=1 USE_CPU_AFFINITY=1 PREFIX=/usr/local/haproxy
## HAProxy 2.0编译参数(linux-glibc是一个通用的内核参数):
[root@localhost haproxy-2.2.12]# make 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=/apps/haproxy
# 安装
[root@localhost haproxy-2.2.12]# make install PREFIX=/apps/haproxy
[root@localhost haproxy-2.2.12]# ls /apps/haproxy/sbin
haproxy
# 将haproxy的可执行程序,妨到/usr/sbin/中,会有环境变量,可以直接调用
[root@localhost haproxy-2.2.12]# cp /apps/haproxy/sbin/haproxy /usr/sbin
# 验证haproxy环境变量,和版本(可以看到版本好就是编译成功了)
[root@localhost haproxy-2.2.12]# haproxy -v
HA-Proxy version 2.2.12-a723e77 2021/03/31 - https://haproxy.org/
Status: long-term supported branch - will stop receiving fixes around Q2 2025.
Known bugs: http://www.haproxy.org/bugs/bugs-2.2.12.html
Running on: Linux 3.10.0-693.el7.x86_64 #1 SMP Tue Aug 22 21:09:27 UTC 2017 x86_64
# 查看配置模板文件(这里面提供的是配置文件的模板)
[root@localhost haproxy-2.2.12]# ls examples/
acl-content-sw.cfg errorfiles option-http_proxy.cfg transparent_proxy.cfg
content-sw-sample.cfg haproxy.init socks4.cfg wurfl-example.cfg
# 创建配置文件(自己创建配置文件)
[root@localhost haproxy-2.2.12]# mkdir -pv /etc/haproxy
mkdir: 已创建目录 "/etc/haproxy"
[root@localhost haproxy-2.2.12]# vi /etc/haproxy/haproxy.cfg
global # 声明全局配置,跟缩进没有要求
maxconn 1000000 # 整个连接的最大值,每个haproxy进程的最大并发连接数,整个值一般可以调的大点,通常是10万,如果是4个进程就是40万了,这个值设置大点没关系,比如100万,不要设置小了万一那天并发量上来haproxy就处理不了,可能要排队
chroot /apps/haproxy # 为了安全考虑,锁定运行工作目录,路径需要提前存在
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin # 指定socket路径,注意:/var/lib/haproxy/ 目录需要首先存在,sock文件服务启动时自动创建,mode 600表示haproxy.sock这个文件的权限是600,level级别是admin也就是管理员级别,他可以通过socket对haproxy进行管理操作,包括加服务器,减服务器
uid 99 # 99是系统nobody用户
gid 99
daemon # 把haproxy进程发到后端,要不然他就在前台执行了,在一些容器运行haproxy的时候可能会用到这个
#nbproc 4 # 指定开启的工作进程数量,进程数量一般等于cpu内核数一样,多进程不能和多线程同时开,否者启动不来,可以看系统日志,默认一个进程一个线程,
#cpu-map 1 0 # cup绑定,1 0前面的1是进程,0是cpu,绑定后工作进程就不会在多个cpu之间抖动了
#cpu-map 2 1
#cpu-map 3 2
#cpu-map 4 3
#nbthread 4 # 开启多线程,性能会有提升但是没有多进程性能好ps -ef | grep haproxy查看,默认是多线程
pidfile /var/lib/haproxy/haproxy.pid # 指定pid文件路径,需要跟systemd定义的路径一致
log 127.0.0.1 local3 info # 记录日志
defaults
option redispatch
option abortonclose
option http-keep-alive
option forwardfor # ip地址透传,在defaults定义,listen中没有定义,会继承
mode http
timeout http-keep-alive 120s
timeout connect 120s
timeout server 600s
timeout client 600s
timeout check 5s
maxconn 100000
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status # haproxy的状态页,指定一个uri
stats auth haadmin:q1w2e3r4ys # 认证的账号和密码
# listen web_port
# bind 192.168.7.101:80 # 绑定的地址,需要改成自己地址否者会启动不起来
# mode http
# log global
# server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5
# frontend helloworld-webserver-80 # 名字要见字达意,frontend这种方式用的不多,大多数用的是listen
# bind 192.168.127.130:80 # 绑定一个监听地址和端口
# mode http # 工作模式
# use_backend helloworld-webserver-80-host # 要使用哪个后端服务器,不然 bind 192.168.127.130:80 这里找不到后端服务器
# backend helloworld-webserver-80-host # 后端服务器
# mode http # 工作模式
# server web1 192.168.127.129:80 check inter 3s fall 3 rise 5 # 声明服务器,后面定义服务器名称,下线服务器的时候就是helloworld-webserver-80-host在这个名称里面找到web1进行下线,haproxy下线服务器不是通过ip地址下线的,check表示对后端>服务器进行状态检测,如果服务器挂了,将不在发送请求到挂了的后端服务器上,intre表示多长时间检测一次,这里定义3秒,fall 3表示连续检测失败3次就踢出去,rise 5连续五次检测成功了,就在加回来
# server web2 192.168.127.131:80 check inter 3s fall 3 rise 5 # 定义两个默认会轮询访问
listen webserver-80
bind 192.168.127.130:80
mode http
# redirect prefix https://www.cnblogs.com/hao-ran/ # 单独打开,他的作用的就是nginx的转发功能,这是一个302临时重定向,不记录dns缓存
server web1 192.168.127.129:80 check weight 1 maxconn 500 addr 192.168.127.129 port 8080 inter 3s fall 3 rise 5 # 如果这个地址是后端httpd的代理服务器地址,代理至后端的tomcat服务器上,addr如果我们有多个网卡的话,就写另外一个地址,用另外的网卡专门用来做这种服务检测,port检测后端服务器的哪个端口,比如8080,比如3306,只要这些端口存在我就认为他们是可用的,如果不存在我就认为他们是不可用的,可用状态页的服务器是绿的,健康检测,如果有两个端口,就会检测两个端口,如果都是好的服务都在,状态页中才会显示绿色,weight 1表示权重,如果服务器硬件性能不一样可以单独设置以下,maxconn 500表示这台服务器500并发量
server web2 192.168.127.131:80 check inter 3s fall 3 rise 5
HAProxy启动脚本
示例
# 这里是模板,也可以在在别的服务器中复制过来改以下,或者yum安装的haproxy启动脚本改以下 (注意,复制的时候删除掉注释,否者启动不了服务)
[root@localhost haproxy-2.2.12]# vi /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 # /usr/sbin/haproxy可执行文件,如果没有复制到/usr/sbin/下那么就用,我们编译目录中的/apps/haproxy/sbin/haproxy这个可执行文件,必须指定。 -f表示指定可执行文件的配置文件
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid # 这里也要指定可执行文件。 -Ws表示master-worker工作模式,使用systemd启动 -p表示指定pid文件
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target
# 创建路径,放haproxy.pid文件和haproxy.sock文件
[root@localhost haproxy-2.2.12]# mkdir -pv /var/lib/haproxy/
mkdir: 已创建目录 "/var/lib/haproxy/"
# 给目录权限
## (99是nobody用户,nobody是一个普通用户,没有特权,他存在的目的是为了让任何人都能登录系统,通俗来说: 一个系统,任何人都能登录,那么当我们登录后,我们的身份是什么,我们是nobody,可以看做一个特殊的名分,很多系统都会按照惯例创建一个nobody,并且将其权限降到最低,例如服务器对外公布,会让客户以nobody身份登录,由于权限很低,这样能降低风险,这也是其存在的意义。)
## (nobody在linux中是一个不能登陆的帐号,一些服务进程如apache,aquid等都采用一些特殊的帐号来运行,比如nobody,news,games等等,这是就可以防止程序本身有安全问题的时候,不会被黑客获得root权限)
[root@localhost haproxy-2.2.12]# chown 99.99 /var/lib/haproxy/ -R
### 或者 (使用id查看nobody用户,他的组是什么和他的id是什么)
root@ha1:/usr/local/src/haproxy-2.2.12# id nobody
uid=65534(nobody) gid=65534(nogroup) groups=65534(nogroup)
root@ha2:/usr/local/src/haproxy-2.2.12# chown nobody:nogroup /var/lib/haproxy/ -R
# 关闭防火墙 (ubuntu默认没有开启防火墙)
[root@localhost haproxy-2.2.12]# systemctl stop firewalld
[root@localhost haproxy-2.2.12]# setenforce 0
# 启动haproxy(9999端口和192.168.127.130:80已监听,这个9999状态页是可以直接访问的)
[root@localhost haproxy-2.2.12]# systemctl restart haproxy
[root@localhost haproxy-2.2.12]# systemctl enable haproxy
[root@localhost haproxy-2.2.12]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:9999 *:*
LISTEN 0 128 192.168.127.130:80 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
# 查看进程(haproxy默认是单主进程,主进程id是75604,单子进程,子进程id是75608)
[root@localhost haproxy-2.2.12]# ps -ef | grep haproxy
root 5466 2076 0 11:39 pts/0 00:00:00 grep --color=auto haproxy
root 75604 1 0 11:12 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid
nobody 75608 75604 0 11:12 ? 00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid
# 访问测试(访问hapeoxy返回503表示,后端的服务器都挂了)
http://192.168.127.130/
503 Service Unavailable
# 设置httpd日志,测试ip透传(%{X-Forwarded-For}i已添加的情况下)
[root@localhost ~]# vi /etc/httpd/conf/httpd.conf
LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
# 查看httpd日志(192.168.127.1可以看到客户端ip,透传成功)
[root@localhost ~]# tail /etc/httpd/logs/access_log
192.168.127.1 192.168.127.130 - - [01/Apr/2021:14:13:20 +0800] "GET / HTTP/1.1" 200 6 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
# 访问测试状态页面
http://192.168.127.130:9999/haproxy-status
验证haproxy状态
- haproxy.cfg⽂件中定义了chroot、pidfile、user、group等参数,如果系统没有相应的资源会导致haproxy⽆法启动,具体参考⽇志⽂件/var/log/messages
示例
[root@localhost haproxy-2.2.12]# systemctl status haproxy
● haproxy.service - HAProxy Load Balancer
Loaded: loaded (/usr/lib/systemd/system/haproxy.service; enabled; vendor preset: disabled)
Active: active (running) since 四 2021-04-01 11:12:51 CST; 4min 20s ago
Main PID: 75604 (haproxy)
CGroup: /system.slice/haproxy.service
├─75604 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid
└─75608 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid
4月 01 11:12:51 localhost.localdomain systemd[1]: Starting HAProxy Load Balancer...
4月 01 11:12:51 localhost.localdomain systemd[1]: Started HAProxy Load Balancer.
4月 01 11:12:51 localhost.localdomain haproxy[75604]: [NOTICE] 090/111251 (75604) : New worker #1 (75608) forked
4月 01 11:12:51 localhost.localdomain haproxy[75604]: [WARNING] 090/111251 (75608) : Server web_port/web1 is DOWN, r...eue.
4月 01 11:12:51 localhost.localdomain haproxy[75604]: [NOTICE] 090/111251 (75608) : haproxy version is 2.2.12-a723e77
4月 01 11:12:51 localhost.localdomain haproxy[75604]: [NOTICE] 090/111251 (75608) : path to executable is /usr/sbin/haproxy
4月 01 11:12:51 localhost.localdomain haproxy[75604]: [ALERT] 090/111251 (75608) : proxy 'web_port' has no server av...ble!
Hint: Some lines were ellipsized, use -l to show in full.
基础配置详解
-
官方配置文档:http://cbonte.github.io/haproxy-dconv/2.5/configuration.html
-
HAPrpxy的配置⽂件haproxy.cfg由两⼤部分组成,分别是global和proxies部分。
-
global:全局配置段 (类似于nginx的http以外的配置,是整个进程生效的)
- 进程及安全配置相关的参数
- 性能调整相关参数
- Debug参数
-
proxies:代理配置段
- defaults:为frontend, backend, listen提供默认配置
- frontend:前端,相当于nginx中的server {}
- backend:后端,相当于nginx中的upstream {}
- listen:同时拥有前端和后端配置
-
global配置参数
示例
# 锁定运⾏⽬录
chroot
# 以守护进程运⾏
deamon
-----------------------------
# socket⽂件,并赋予admin权限
# stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
## 需要注意的是,restart会直接关掉旧进程并建立新进程,所以会丢弃大量已建立的连接,而reload会启动新进程,但旧进程会先处理完当前已建立连接然后再关闭。但是,reload仍然会丢弃极少量的连接,虽然大多数情况下这足够完美了,但是在极度严格的环境下,这是不允许的。在haproxy 1.8中,提供了完全不丢弃连接的无损重启,要求haproxy启动命令中加入-x选项,同时要求haproxy配置文件的"stats socket"配置中加入expose-fd listeners
## 使用-x选项以及expose-fd listeners之后,reload haproxy的时候,会将已建立TCP连接(TCP套接字)转移到Unix Domain状态套接字中进行处理。
## stats socket /run/haproxy/admin.sock mode 660 level admin expose-fd listeners
-----------------------------
# 运⾏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服务器;最多可以定义两个
log 127.0.0.1 local3 info
Proxies配置(此选项严格区分大小写)
https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4
示例
defaults [<name>] #默认配置项,针对以下的frontend、backend和
lsiten⽣效,可以多个name也可以没有name (defaults优先级没有listen高,通常配置一些全局的选项)
frontend <name> #前端servername,类似于Nginx的⼀个虚拟主机
server。
backend <name> #后端服务器组,等于nginx的upstream
listen <name> #将frontend和backend合并在⼀起配置 (这种listen是主要使用的,listen定义的名称比较有用,不同listen之间名称不能冲突,listen的优先级比defaults高)
•注:name字段只能使⽤”-”、”_”、”.”、和”:”,并且严格区分⼤⼩写,例如:Web和web是完全不同的两组服务器。
Proxies配置-defaults
-
defaults 配置参数:
-
option redispatch #当server Id对应的服务器挂掉后,强制定向到其他健康的服务器,重新派发(要加上比较重要)
-
option abortonclose #当服务器负载很⾼的时候,⾃动结束掉当前队列处理⽐较久的链接,关闭(这个值一般不加)
-
option http-keep-alive #开启与客⼾端的会话保持(一般会加,当会话结束后,仍然保持连接)
-
option forwardfor #透传客⼾端真实IP⾄后端web服务器(ningx里也有)
-
mode http #设置默认⼯作类型 (如果后面的listen没有定义工作类型,他会继承defaults的工作模式,如果listen定义了,先用listen定义的,listen定义的优先级高)
-
timeout http-keep-alive 120s #session 会话保持超时时间,范围内会转发到相同的后端服务器(option http-keep-alive开启会话保持后,多久断开)
-
timeout connect 120s #客⼾端请求从haproxy到后端server的最⻓连接等待时间(TCP之前)(haproxy和后端服务器多久没有通过tcp建立连接,超时断开,这个时间越小越好)
-
timeout server 600s #客⼾端请求从haproxy到后端服务端的请求处理超时时⻓(TCP之后)(后端服务器向haproxy发送数据,定义多长时间内传完,这个值需要长点,后端服务器比如mysql可能处理比较慢)
-
timeout client 600s #设置haproxy与客⼾端的最⻓⾮活动时间
-
timeout check 5s #对后端服务器的默认检测超时时间(检测后端服务器的时候,服务器多久没有返回,就认为服务器超时了)
-
-
frontend配置参数:
示例
bind:指定HAProxy的监听地址,可以是IPV4或IPV6,可以同时监听多个IP或端⼝,可同时⽤于listen字段中
bind [<address>]:<port_range> [, ...] [param*]
listen http_proxy #监听http的多个IP的多个端⼝和sock⽂件
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
listen http_https_proxy #https监听
bind :80
bind :443 ssl crt /etc/haproxy/site.pem
listen http_https_proxy_explicit #监听ipv6、ipv4和unix sock⽂件
bind ipv6@:80
bind ipv4@public_ssl:443 ssl crt /etc/haproxy/site.pem
bind unix@ssl-frontend.sock user root mode 600 acceptproxy
listen external_bind_app1 #监听file descriptor
bind "fd@${FD_APP1}"
⽣产⽰例:
frontend WEB_PORT
bind :80,:8080
bind 192.168.7.102:10080,:8801-8810,192.168.7.101:9001-9010
mode http/tcp #指定负载协议类型
use_backend backend_name #调⽤的后端服务器组名称
Proxies配置-backend
- 定义⼀组后端服务器,backend服务器将被frontend进⾏调⽤。
-
mode http/tcp #指定负载协议类型
-
option #配置选项
-
server #定义后端real server
- 注意:option后⾯加httpchk,smtpchk,mysql-check,pgsql-check,sslhello-chk⽅法,可⽤于实现更多应⽤层检测功能。
-
check #对指定real进⾏健康状态检查,默认不开启
- addr IP #可指定的健康状态监测IP
- port num #指定的健康状态监测端⼝
- inter num #健康状态检查间隔时间,默认2000 ms
- fall num #后端服务器失效检查次数,默认为3
- rise num #后端服务器从下线恢复检查次数,默认为2
-
weight #默认为1,最⼤值为256,0表⽰不参与负载均衡 (表示权重)
-
backup #将后端服务器标记为备份状态(所有的服务器都关了,才会转给backup备份服务器)
-
disabled #将后端服务器标记为不可⽤状态
-
redirect prefix http://www.magedu.net/ #将请求临时重定向⾄其它URL,只适⽤于http模式
-
maxconn
:当前后端server的最⼤并发连接数(很少去设置 ) -
backlog
:当server的连接数达到上限后的后援队列⻓度,如果设置了maxconn最⼤并发连接数,如果满了,就排队
-
frontend+backend配置实例
#官⽹业务访问⼊⼝======================================
frontend WEB_PORT_80 # 访问WEB_PORT_80他,去找web_prot_http_nodes他下面配置的主机
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
Proxies配置-listen替代frontend+backend
使⽤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
HAProxy调度算法
-
HAProxy通过固定参数balance指明对后端服务器的调度算法,该参数可以配置在listen或backend选项中。
-
HAProxy的调度算法分为静态和动态调度算法,但是有些算法可以根据参数在静态和动态算法中相互转换。
-
https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4 #官⽅⽂档
静态算法
-
静态算法:按照事先定义好的规则轮询公平调度,不关⼼后端服务器的当前负载、链接数和响应速度等,且⽆法实时修改权重,只能靠修改配置文件重启HAProxy⽣效。
-
服务器动态权重调整:
示例
#Socat 是 Linux 下的⼀个多功能的⽹络⼯具,名字来由是Socket CAT,Socat 的主要特点就是在两个数据流之间建⽴通道,且⽀持众多协议和链接⽅式。如 IP、TCP、 UDP、IPv6、Socket⽂件等。(静态算法需要事先安装此程序,通过这个工具我们往haproxy.sock中输入指令)
[root@localhost haproxy-2.2.12]# yum -y install socat
# echo出一个字符,用socat命令,通过stdio标准输入,传递给haproxy.sock这个sock文件
## 通过htlp打印出帮助信息
[root@localhost haproxy-2.2.12]# echo "help" | socat stdio /var/lib/haproxy/haproxy.sock
## 查看haproxy的运行状态(如果有空格需要使用双引号引用起来)
[root@localhost haproxy-2.2.12]# echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
# 通过sock的文件实时调整后端服务器的权重
## 通过get查看后端服务器权重
### 配置文件设置权重:
[root@localhost haproxy-2.2.12]# vi /etc/haproxy/haproxy.cfg
...
listen webserver-80
bind 192.168.127.130:80
mode http
# redirect prefix https://www.cnblogs.com/hao-ran/ # 单独打开,他的作用的就是nginx的转发功能,这是一个302临时重定向,不记录dns缓存
server web1 192.168.127.129:80 check weight 1 maxconn 500 addr 192.168.127.129 port 8080 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 check weight 1 inter 3s fall 3 rise 5
### 查看权重(weight 后面是名称,比如listen的名称,或者backend的名称)
[root@localhost haproxy-2.2.12]# echo "get weight webserver-80/web2" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 1)
## 通过set设置权重
### set设置权重(如果执行结果没有任何返回那就是成功了,如果是多进程,可能需要设置多个,他每次会设置一个进程的web权重)
[root@localhost haproxy-2.2.12]# echo "set weight webserver-80/web2 2" | socat stdio /var/lib/haproxy/haproxy.sock
### 查看权重
[root@localhost haproxy-2.2.12]# echo "get weight webserver-80/web2" | socat stdio /var/lib/haproxy/haproxy.sock
2 (initial 1)
## 关闭指定的后端服务器(disable server会把服务器强制摘掉,可以看状态页服务器状态会提示MAINT维护,手动下线的)
[root@localhost haproxy-2.2.12]# echo "disable server webserver-80/web2" | socat stdio /var/lib/haproxy/haproxy.sock
## 开启指定的后端服务器(使用enable server)
[root@localhost haproxy-2.2.12]# echo "enable server webserver-80/web2" | socat stdio /var/lib/haproxy/haproxy.sock
static-rr
- static-rr:基于权重的轮询调度,不⽀持权重的运⾏时set调整(可以使用配置文件调整权重)及后端服务器慢启动(慢启动就是,新上线的服务器,不会直接就顶上,而是会慢慢的一点一带你的给他加负载),但是可以上线,和下线服务器,其后端主机数量没有限制
示例
listen web_host
bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
mode http
log global
balance static-rr # 添加这一条,就把默认轮询换成了静态轮询,不支持set调整权重
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
测试访问效果
first
- first:根据服务器在列表中的位置,⾃上⽽下进⾏调度,但是其只会当第⼀台服务器的连接数达到上限,新请求才会分配给下⼀台服务,因此会忽略服务器的权重设置。(只有第一个web1服务器请求满了以后,他才会往下一个web2服务器中转请求,以此向后,这个算法几乎不会用)
示例
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
# 测试访问效果(使用命令行测试)
# while true;do curl http://192.168.7.101/app/index.html; sleep 0.1;done
动态算法
- 动态算法:基于后端服务器 状态进⾏调度适当调整,⽐如优先调度⾄当前负载较低的服务器,且权重可以在haproxy运⾏时动态调整⽆需重启。
roundrobin
- roundrobin(默认):基于权重的轮询动态调度算法,⽀持权重的运⾏时调整,不完全等于lvs中的rr轮训模式,HAProxy中的roundrobin⽀持慢启动(新加的服务器会逐渐增加转发数),其每个后端backend中最多⽀持4095个realserver,roundrobin为默认调度算法,且⽀持对real server权重动态调整。
示例
# 调整权重
[root@localhost haproxy-2.2.12]# vi /etc/haproxy/haproxy.cfg
listen webserver-80
bind 192.168.127.130:80
mode http
# redirect prefix https://www.cnblogs.com/hao-ran/ # 单独打开,他的作用的就是nginx的转发功能,这是一个302临时重定向,不记录dns缓存
server web1 192.168.127.129:80 check weight 1 maxconn 500 addr 192.168.127.129 port 3306 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 check weight 1 inter 3s fall 3 rise 5
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
# 测试访问效果(使用命令行测试,roundrobin算法是可以根据服务器负载来自动调整轮询权重,我们服务器没有负载,看不出来)
[root@localhost ~]# while true;do curl 192.168.127.130; sleep 0.5;done
## roundrobin算法动态调整权限(调整后立即生效,可以看到访问两次webB,一次webA)
[root@localhost haproxy-2.2.12]# echo "get weight webserver-80/web2" | socat stdio /var/lib/haproxy/haproxy.sock
1 (initial 1)
[root@localhost haproxy-2.2.12]# echo "set weight webserver-80/web2 2" | socat stdio /var/lib/haproxy/haproxy.sock
[root@localhost haproxy-2.2.12]# echo "get weight webserver-80/web2" | socat stdio /var/lib/haproxy/haproxy.sock
2 (initial 1)
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
其他算法
- 其他部分算法即可作为静态算法,⼜可以通过选项成为动态算法
source
-
源地址hash,基于⽤⼾源地址hash并将请求转发到后端服务器,默认为静态即取模⽅式,但是可以通过hash-type⽀持的选项更改,后续同⼀个源地址请求将被转发⾄同⼀个后端web服务器,⽐较适⽤于session保持/缓存业务等场景。(只要是同一个地址发过来的请求,他就转发给第一次接收这个地址的请求的服务器,这是静态算法,不能用set更改权重,缺点是一个公司什么的基本上都是使用一个公网ip,相当于可能有几百号人,只请求一台服务器,压力很重)
- 源地址有两种转发客⼾端请求到后端服务器的服务器选取计算⽅式,分别是取模法和⼀致性hash
map-base取模法
-
map-based:取模法,基于服务器总权重(全部服务器weight设置的权重相加,就是总权重,然后取模,取模就是除法,源地址哈希对总权重取模,除尽是0,除不尽就余1,然后就是转发给0或者1的服务器处理请求)的hash数组取模,该hash是静态的即不⽀持在线调整权重,不⽀持慢启动,其对后端服务器调度均衡,缺点是当服务器的总权重发⽣变化时,即有服务器上线或下线,都会因权重发⽣变化⽽导致调度结果整体改变。
-
所谓取模运算,就是计算两个数相除之后的余数,10%7=3, 7%4=3,基于权重取模:(2^32-1)%(1+1+2),公式为,hash(o)mod n,即a mod b=c,表明a除以b余数为c。
取模法配置⽰例
示例
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 3000fall 2 rise 5
server web2 192.168.7.104:80 weight 1 check inter 3000fall 2 rise 5
⼀致性hash
- ⼀致性哈希,该hash是动态的,⽀持在线调整权重,⽀持慢启动,优点在于当服务器的总权重发⽣变化时,对调度结果影响是局部的,不会引起⼤的变动。
⼀致性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 # 加上这个host-type 我们在echo"set weighi"权重就不会报错了
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
# 修改了配置文件重启haproxy生效
[root@localhost ~]# systemctl restart haproxy
uri
- 基于对⽤⼾请求的uri做hash并将请求转发到后端指定服务器,也可以通过map-based和consistent定义使⽤取模法还是⼀致性hash。
- http://example.org/absolute/URI/with/absolute/path/to/resource.txt #URI/URL
- ftp://example.org/resource.txt #URI/URL
- /relative/URI/with/absolute/path/to/resource.txt #URI
uri 取模法配置⽰例
示例
listen web_host
bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
mode http
log global
balance uri # 加上这个,对请求的url做哈希,测试结果不同主机请求的同一个uri转发给同一个uri,基于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
访问测试
- 访问不同的uri,确认可以将⽤⼾同样的请求转发⾄相同的服务器
url_param
-
url_param对⽤⼾请求的url中的 params 部分(params也就是参数,也就是对参数部分name部分做哈希计算,其实跟一致性哈希或者uri哈希一样,只不过这个参数变成了参数名,这种用的不多,除非向京东的电商,他做搜索的,他的服务器可能已经缓存好搜索结果了,那么这个就是同一个产品的搜索结果,找到同一个后端服务器去请求数据,那么他的服务器就不用来来回回去做商品的搜索了)中的参数name作hash计算,并由服务器总权重相除以后派发⾄某挑出的服务器;通常⽤于追踪⽤⼾,以确保来⾃同⼀个⽤⼾的请求始终发往同⼀个real server
- 假设url = http://www.magedu.com/foo/bar/index.php?k1=v1&k2=v2(测试就加上k1=v1&k2=v2参数,键加值,类似于同一个产品搜索,就转发给后端同一个服务器,在京东上搜索手机,比如搜华为,https://search.jd.com/Search keyword=%E5%8D%8E%E4%B8%BA&enc=utf8&wq=hua%27wei&pvid=a1451fc38b5d4df49f5a278d8b474ce0 这就是他的url,其中可以对keyword做哈希)
- 则:
- 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,(balance url_param这两个是参数, name,age这两个是需要做哈希的参数名,对这两个参数做哈希,以逗号做分割, 这个时候如果访问的时候,传过来的那么的值不一样,那么后端处理的服务器也可能不一样)
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 # ⽀持对单个及多个url_param 值hash
hash-type consistent # 此参数需要加上(可以理解为这个是可以对uri做哈希的参数,而balance url_param这个是他的可选择参数,单独一个balance url_param测试不成功)
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
测试访问
# curl http://192.168.7.101/app/index.html?name=NAME #单个参数访问(?name=NAME表示参数,会对这参数的name做哈希,请求的不同参数name可能访问的服务器也不一样)
# curl http://192.168.7.101/app/index.html?age=AGE
# curl http://192.168.7.101/app/index.html?age=AGE&&name=NAME #多个参数访问
示例
[root@localhost ~]# while true; do curl http://192.168.127.130/index.html?name=jerry;sleep 0.2;done
web B
web B
web B
web B
web B
web B
web B
web B
^C
[root@localhost ~]# while true; do curl http://192.168.127.130/index.html?name=tom;sleep 0.2;done
web A
web A
web A
web A
web A
web A
web A
web A
web A
web A
web A
web A
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) # 我们使用hdr去取用户头部的那些字段(User-Agent),这里取的是User-Agent如果是请求使用的不同的浏览器那么可能会被转发给不同的后端服务器,因为你的浏览器类型不一样,我们是用包头部的User-Agent做的哈希,这里记录的是浏览器类型(具体的是哪个可能去浏览器里面f12调试模式在Request Headers请求头部去找,那里面的参数都是可以取的,host和uri还有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
测试访问(测试成功)
示例
# curl测试请求的是web A
[root@localhost ~]# while true; do curl http://192.168.127.130 ;sleep 0.2;done
web B
web B
web B
web B
# 谷歌浏览器请求的后端服务器是web A
http://192.168.127.130/
web A
# 火狐浏览器请求的后端服务器是web B
http://192.168.127.130/
web B
rdp-cookie(用的场景非常少,只适用于windwos server场合)
-
rdp-cookie可以实现对windows远程桌⾯的负载(可以以为专门为windws server做的),如果有多个后端windows Server服务器,rdp-cookie可以实现同⼀个window server的请求始终被转发给同⼀个后端服务器,如果之前从未访问过,那么第⼀次使⽤连接roundrobin算法计算出⼀个后端服务器并进⾏转发。
-
http://cbonte.github.io/haproxy-dconv/2.2/configuration.html#persist rdp-cookie
-
https://www.loadbalancer.org/blog/load-balancing-windows-terminalserver-haproxy-and-rdp-cookies/
rdp-cookie取模法配置⽰例
示例
listen RDP
bind 192.168.7.101:3389
balance rdp-cookie # 简单点写法就是balance指定rdp-cookie
mode tcp # 这个mode指定协议写tcp
server rdp0 172.18.132.20:3389 check fall 3 rise 5 inter 2000 weight 1
rdp-cookie⼀致性hash配置⽰例
示例
listen RDP
bind 172.31.7.201:3389
mode tcp
balance rdp-cookie # 复杂一点的rdp-cookie写法
persist rdp-cookie # 启⽤基于RDP cookie的持久连接,如果是同⼀个cookie就转发给对应的同一个服务器。(就是基于库cookie的会话保持)
tcp-request inspect-delay 5s # 设置内容检查期间等待数据的最⼤允许时间 (等待5秒钟,检查请求头部报文钟是否有rdp-cookie)(如果超时就会基于默认算法,转发给默认服务器了)
tcp-request content accept if RDP_COOKIE # 匹配RDP_COOKIE存在就接受请求(就是判断你的请求头部中是否有cookie的)(RDP_COOKIE其实是内部变量)
#hash-type consistent
server win-server1 172.31.4.0:3389 check fall 3 rise 5 inter 2000 weight 1
测试访问
- 可以测试远程连接haproxy转发到windows,实现远程windows桌面
基于iptables实现(也是实现地址转发)
示例
# 查看net.ipv4.ip_forwar是否打开
[root@localhost ~]# sysctl -a | grep forward
net.ipv4.ip_forward = 0
# 打开net.ipv4.ip_forward地址转换功能
[root@localhost ~]# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
sysctl: reading key "net.ipv6.conf.lo.stable_secret"
net.ipv4.ip_forward = 1
[root@localhost ~]# sysctl -p
net.ipv4.ip_forward = 1
# net.ipv4.ip_forward = 1 #必须开启ip转发功能
# iptables -t nat -A PREROUTING -d 172.31.7.201 -p tcp --dport 3389 -j DNAT --to-destination 172.31.4.0:3389
## PREROUTING 表示路由之前的,-d 172.31.7.201把访问这个地址的,-p tcp这个协议的,--dport 3389这个端口,-j DNAT做一个目的地址转换, --to-destination 172.31.4.0:3389转换到这个地址的,这个端口(这条规则会转发请求,但是不会转发响应,数据回不去)
# iptables -t nat -A POSTROUTING -s 172.31.0.0/21 -j SNAT --to-source 172.31.7.201
## 对于172.31.0.0/21这个地址请求(可以是地址,可以是网段,这里写网段), -j SNAT 做一个地址转换,--to-source 172.31.7.201转换到这个地址(这条规则相当于,补充了上一条规则请求进来了,响应回去的规则)
# 查看iptables规则
[root@localhost ~]# iptables -t net -vnL
random
- 在1.9版本开始增加⼀个叫做random的负载平衡算法,其基于⼀个随机数作为⼀致性hash的key,随机负载平衡对于⼤型服务器场或经常添加或删除服务器⾮常有⽤。(他也不是依据权重,也不是依据ip地址,他自己内部做的一些标记然后哈希,实验结果类似于轮询,你可以把他当做轮询使用)
random配置实例
示例
listen web_host
bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
mode http
log global
balance random # 加上这条
# hash-type consistent # 这里加hash-type加不加效果一样
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
访问测试
示例
# 不咋规则的轮询访问后端服务器,不依据ip,浏览器类型,uri(乱七八糟)
[root@localhost ~]# while true; do curl http://192.168.127.130 ;sleep 0.2;done
web A
web A
web A
web A
web B
web B
web B
web A
web A
web B
web A
web B
web B
web A
web B
算法总结
示例
static-rr--------->tcp/http 静态 (适用协议tcp/http)(无论怎么改,他都是静态的)
first------------->tcp/http 静态 (适用协议tcp/http)(无论怎么改,他都是静态的)
roundrobin-------->tcp/http 动态 (适用协议tcp/http)(纯动态)
leastconn--------->tcp/http 动态 (适用协议tcp/http)(纯动态)
random------------>tcp/http 动态 (适用协议tcp/http)(纯动态)(这个可以修改权重,所以他也是动态的)
source------------>tcp/http (默认静态) (适用协议tcp/http) (加上hash-type等于consistent他就是动态的)
Uri--------------->http (默认静态) (适用协议http) (加上hash-type等于consistent他就是动态的)
url_param--------->http (默认静态) (适用协议http,他基于uri的哈希调度算法,如果适用tcp模式,他是不生效的) (加上hash-type等于consistent他就是动态的) 取决于hash_type是否consistent
hdr--------------->http (默认静态) (适用协议http) (加上hash-type等于consistent他就是动态的)
rdp-cookie-------->tcp (默认静态) (适用协议tcp) (加上hash-type等于consistent他就是动态的)
各算法使⽤场景
示例
first # 使⽤较少
static-rr # 做了session共享的web集群(轮询,静态)(适用于,做了session共享的web集群)
roundrobin #(轮询,可以加权重)(适用于,做了session共享的web集群)
random #(轮询)(适用于,做了session共享的web集群)
leastconn # 适用于数据库
source # 基于客⼾端公⽹IP的会话保持(少用)
Uri--------------->http #缓存服务器,CDN服务商,蓝汛、百度、阿⾥云、腾讯 (可以适用于缓存,基于请求的uri资源路径做转发)
url_param--------->http # 京东和天猫可能用的多,因为他可以基于用户的搜索结果做缓存
hdr() #基于客⼾端请求报⽂头部做下⼀步处理
rdp-cookie # 毕竟做windws使用的,很少使⽤
layer 4与layer 7
- (四成和七成的区别)
-
四层:IP+PORT转发(基于ip和端口转发的,在负载均衡器上只会修改报文的目的地址加上目的端口,和源地址,把源地址改成自己的,这个根据请求,不会是所有的都改)
-
七层:协议+内容交换(在七层下,我们的负载均衡器可以做的修改比较多,可以添加一些头部字段等,这些都是4层所不具备的,在七层下,后端服务器看到请求者就是负载均衡器,负载均衡器拿到用户的请求报文,替用户向后端服务器发起了请求,然后后端服务器根据负载均衡器的请求回应,然后负载均衡器,在构建报文,(回应)返回给给客户端)
- (需要客户端和负载均衡器建立tcp连接,而负载均衡器需要和后端服务器建立起tcp连接)
-
四层负载
- 在四层负载设备中,把client发送的报⽂⽬标地址(原来是负载均衡设备的IP地址),根据均衡设备设置的选择web服务器的规则选择对应的web服务器IP地址,这样client就可以直接跟此服务器建⽴TCP连接并发送数据
七层代理
- 七层负载均衡服务器起了⼀个反向代理服务器的作⽤,服务器建⽴⼀次TCP连接要三次握⼿,⽽client要访问webserver要先与七层负载设备进⾏三次握⼿后建⽴TCP连接,把要访问的报⽂信息发送给七层负载均衡;然后七层负载均衡再根据设置的均衡规则选择特定的webserver,然后通过三次握⼿与此台webserver建⽴TCP连接,然后webserver把需要的数据发送给七层负载均衡设备,负载均衡设备再把数据发送给client;所以,七层负载均衡设备起到了代理服务器的作⽤。
示例
# 测试,查看三次握手
# tcpdump tcp -i eth0 -nn port ! 22 -w dump-tcp.pcap -v
Proto Recv-Q Send-Q Local Address Foreign Address
State PID/Program name
#客⼾端请求HAProxy
tcp 0 0 47.90.22.132:80 111.199.184.27:3125
ESTABLISHED 27313/haproxy
#HAProxy与Nginx的连接
tcp 0 0 10.25.144.141:41658 10.25.144.141:81
ESTABLISHED 27313/haprox
IP透传
- web服务器中需要记录客⼾端的真实IP地址,⽤于做访问统计、安全防护、⾏为分析、区域排⾏等场景。
四层IP透传
示例
haproxy 配置send-proxy(就是代理模式,可以在用户的请求报文当中加个字段,然后转发给后端服务器,这样后端服务器就能拿到客户端的源地址了):
listen web_prot_http_nodes
bind 192.168.7.101:80
mode tcp # 注意修改mode为tcp
balance roundrobin
server web1 blogs.studylinux.net:80 send-proxy check inter 3000 fall 3 rise 5 (在server上添加send-prox,把他设置为代理模式,然后重启,重启之后,我们的后端是nginx,那么就改nginx的配置文件)
# 自定以日志格式,也是通过$proxy_protocol_addr
此变量来获取客户端ip
## 示例,在nginx主配置文件中添加自定义日志,添加一条比如键起个名字tcp_xff,变量名为$proxy_protocol_addr,这样客户端请求负载均衡服务器haproxy代理至nginx,在nginx日志中就可以看到,比如tcp_xff:192.168.127.128这样的客户端地址
log_format access_json '{"@timestamp":"$time_iso8601",'
...
'"tcp_xff":"$proxy_protocol_addr",'
...
'"status":"$status"}';
# nginx配置(添加特殊的日志格式配置,记得调用主配置文件中配置的日志):
server {
access_log /apps/nginx/logs/access_json.log access_json; # 调用主配置文件中定于的日志
listen 80 proxy_protocol; # listen监听配置中加一个参数proxy_protocol表示代理模式
#listen 80;
server_name blogs.studylinux.net;
......
# 重启nginx,客户端访问测试
七层IP透传(编译安装HAProxy 中做过)
- 当haproxy⼯作在七层的时候,如何透传客⼾端真实IP⾄后端服务器
HAProxy配置
示例
haproxy 配置:
defaults
option forwardfor
或者:
option forwardfor header X-Forwarded-xxx # ⾃定义传递IP参数,后端web服务器写X-Forwarded-xxx,如果写option forwardfor则后端服务器web格式为X-Forwarded-For(X-Forwarded-xxx中的xxx表示可以自定义名字)
listen配置:
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
⾼级功能及配置
- 介绍HAProxy⾼级配置及实⽤案例
基于cookie的会话保持
- cookie value:为当前server指定cookie值,实现基于cookie的会话黏性
- (如果做了基于session共享,那么这个基于cookie的value就用不上了, 当用户第一次访问我们的haproxy的时候,他可能没有cookie,那么haproxy会给他加一个,然后会使用轮询算法,给他转发到某一个后端服务器,然后客户端下一次请求他就有cookie了,那么他下回请求回携带有haproxy给他发的cookie,那么haproxy会获取到cookie值,在给他转到相对应的服务器,这个时候这个cookie就取道了会话保持的作用,但是一般我们都倾向于做session共享)
配置选项
示例
cookie name [ rewrite | insert | prefix ][ indirect ] [nocache ][ postonly ] [ preserve ][ httponly ] [ secure ][domain ]* [ maxidle <idle> ][ maxlife ]
name:cookie 的key名称,⽤于实现持久连接
insert: # 如果客⼾端请求报⽂没有cookie就插⼊新的cookie到响应报⽂,如第⼀次访问HAProxy
indirect: # 不会向客⼾端发送服务器已经处理过请求的cookie信息,⽐如后端服务器宕机后HAProxy将客⼾端请求强制转发⾄real server则会涉及修改cookie,不建议配置(也就是服务器宕了,本来是转发给server1的现在转发给server2了,但是HAProxy不会向客户端发送已经修改过的cookie,这样客户端下一会请求任然会发送给之前的cookie地址,所以不建议)
nocache: # 当client和hapoxy之间有缓存时,haproxy不缓存客⼾端cookie,因为客⼾端浏览器会缓存cookie并携带cookie访问haproxy(所以说客户端的每次访问都会携带cookie,那么haproxy就不用缓存了,haproxy判断客户端的请求报文中有没有cookie,如果有的话就转到对应的服务器,如果没有就给你插入)
配置⽰例
- 一台服务器是测试不出效果的,至少两个
示例
listen web_host
bind 192.168.7.101:80
mode http
log global
balance roundrobin
cookie SERVER-COOKIE insert indirect nocache # 这条参数就是加cookie,取一个名字叫SERVER-COOKIE
server web1 192.168.7.103:80 cookie web1 check inter 3000 fall 3 rise 5 # 每一个服务器给他指定不同的cookie,比如cookie web1,这样一旦访问这台服务器,haproxy就会给他插入kookie了,你访问哪台服务器那么头部报文当中就插入cookie,并且发给客户端
server web2 192.168.7.104:80 cookie web2 check inter 3000 fall 3 rise 5
#重启haproxy,客户端在访问就有cookie了
[root@localhost ~]# systemctl restart haproxy
验证cookie信息
-
浏览器验证(拿到cookie后,携带cookie在访问haproxy的时候,就会转跳道指定的后端服务器):
- http://192.168.127.130/
- Cookie: SERVER-COOKIE=web1
-
通过命令⾏验证:
示例
[root@localhost ~]# curl --cookie "SERVER-COOKIE=web1" http://192.168.127.130
web A
[root@localhost ~]# curl --cookie "SERVER-COOKIE=web2" http://192.168.127.130
web B
HAProxy状态⻚
- 通过web界⾯,显⽰当前HAProxy的运⾏状态。
- https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4-stats uri
状态⻚配置项
示例
stats enable #基于默认的参数启⽤stats page
stats hide-version # 隐藏版本(不显示haproxy版本)
stats refresh <delay> # 设定⾃动刷新时间间隔(如果不设置每次访问都要刷新一次)
stats uri <prefix> # ⾃定义stats page uri,默认值:/haproxy?stats
stats realm <realm> # 账⼾认证时的提⽰信息,⽰例:stats realm :HAProxy\ Statistics
stats auth <user>:<passwd> #认证时的账号和密码,可使⽤多次,默认:no authentication
stats admin { if | unless } <cond> #启⽤stats page中的管理功能(在状态页界面,对服务器进行管理,不要打开,如果别人能打开状态页,很危险,别人会把你的服务器踢出去)
启⽤状态⻚
- (注意必须配置了defaults,状态页才能生效)
示例
listen stats # 首先配置一个listen为stats
bind :9009 # 然后绑定ip和端口,这个端口和地址可以自己改,不写表示所有地址都可以访问
mode http # 非常重要,否者状态页显示不了,可以定义在defaults中,或者状态页的listen中
stats enable # 状态,enable表示开启
#stats hide-version # 隐藏版本(不显示haproxy版本),但是也没啥用,人家都访问你的状态页了,你说你隐藏版本信息有啥用
log global # 给他记录在global日志
stats refresh 3s # 自动刷新状态页,3秒刷新一次
stats uri /haproxy-status # 表示访问哪个uri的时候显示状态页
stats realm HAPorxy\ Stats\ Page
stats auth haadmin:123456 # 表示认证的时候使用的 用户名和密码
stats auth admin:123456 # 账号可以设置好几个,但是没有权限划分,每个用户都是超级管理员
#stats refresh 30s
#stats admin if TRUE
登录状态⻚
示例
# 访问测试状态页
http://192.168.127.130:9999/haproxy-status
pid = 3698 (process #2, nbproc = 2, nbthread = 1) # pid为当前pid号,process为当前进程号,nbproc和nbthread为⼀共多少进程和每个进程多少个线程(pid当前访问haproxy的时候,有哪个进程,去处理你的请求)
uptime = 0d 0h00m08s #启动了多⻓时间(或者叫运行时间,老师重启,这个时间短)
system limits: memmax = unlimited; ulimit-n = 131124 # 系统资源限制:内存/最⼤打开⽂件数/
maxsock = 131124; maxconn = 65536; maxpipes = 0 # 最⼤socket连接数/单进程最⼤连接数/最⼤管道数maxpipes
current conns = 1; current pipes = 0/0; conn rate = 1/sec # 当前连接数/当前管道数/当前连接速率 (主要看这个)
Running tasks: 1/9; idle = 100 % # 运⾏的任务/当前空闲率(通常比较低,如果很高,表示你的haproxy负载已经很高了)
active UP: # 在线服务器(可以接收用户请求)
backup UP: # 标记为backup的服务器(直接标记为了备份服务器)
active UP, going down: # 监测未通过正在进⼊down过程(检测中)
backup UP, going down: # 备份服务器正在进⼊down过程(检查中)
active DOWN, going up: # down的服务器正在进⼊up过程 (之前down了,现在你给他修好了,他需要连续几次检测,通过之后,他会给他加到活动服务器列表中,比如检测5次,每次3秒,这就是15秒,通过后就标记为在线服务器)
backup DOWN, going up: # 备份服务器正在进⼊up过程
active or backup DOWN: # 在线的服务器或者是backup的服务器已经转换成了down状态
not checked: # 标记为不监测的服务器
active or backup DOWN for maintenance (MAINT) # active或者backup服务器⼈为下线的(手动下线的)
active or backup SOFT STOPPED for maintenance # active或者backup被⼈为软下线(⼈为set将weight改成0)
backend server信息
| session rate\每秒的连接会话信息) | Errors(错误统计信息) |
|---|---|
| cur:每秒的当前会话数量 | Req:错误请求量 |
| max:每秒新的最⼤会话数量 | conn:错误链接量 |
| limit:每秒新的会话限制量 | Resp:错误响应量 |
| sessions(会话信息) | Warnings(警告统计信息) |
| cur:当前会话量 | Retr:重新尝试次数 |
| max:最⼤会话量 | Redis:再次发送次数 |
| limit: 限制会话量 | |
| Total:总共会话量 | Server(real server信息) |
| LBTot:选中⼀台服务器所⽤的总时间 | Status:后端机的状态,包括UP和DOWN |
| Last:和服务器的持续连接时间 | LastChk:持续检查后端服务器的时间 |
| Wght:权重 | |
| Bytes(流量统计) | Act:活动链接数量 |
| In:⽹络的字节输⼊总量 | Bck:备份的服务器数量 |
| Out:⽹络的字节输出总量 | Chk:⼼跳检测时间 |
| Dwn:后端服务器连接后都是DOWN的数量 | |
| Denied(拒绝统计信息) | Dwntme:总的downtime时间 |
| Req:拒绝请求量 | Thrtle:server 状态 |
| Resp:拒绝回复量 |
报⽂修改
- 在http模式下,基于实际需求修改客⼾端的请求报⽂与响应报⽂,通过http-reqadd(添加,添加某些报文信息)和http-reqdel(删除,删除某些报文信息,一般不删除)在请求报⽂添加删除字段,通过rspadd与rspidel在响应报⽂中添加与删除字段。 (客户端看到的后端服务器是haproxy,后端看到的客户端是haproxy,haproxy可以客户端请求的和后端服务器响应的报文进行修改有在进行转发,比如客户端的ip透传,后端服务器的版本信息隐藏)
示例
# 在请求报⽂尾部添加指定⾸部
http-response add-header
# 从请求报⽂中删除指定的key首部(#从响应报⽂删除server信息,键值大小写应该于浏览器显示的大小写相同)
http-response del-header server
# 老版本(2.0之前版本)使用方式(删除key可以使用正则表达式比如reqdel server.*)
## 添加
reqadd
## 删除
reqdel
# 示例:
## 查看报文
[root@localhost ~]# curl -I http://192.168.127.130
HTTP/1.1 200 OK
date: Sun, 04 Apr 2021 11:21:06 GMT
server: Apache/2.4.6 (CentOS)
last-modified: Mon, 29 Mar 2021 02:33:02 GMT
etag: "6-5bea3b3674691"
accept-ranges: bytes
content-length: 6
content-type: text/html; charset=UTF-8
set-cookie: SERVER-COOKIE=web1; path=/
cache-control: private
## 编辑haproxy配置文件,删除掉头部报文中的server
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
listen webserver-80
...
http-response del-header server
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 addr 192.168.127.129 port 3306 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl reload haproxy
# 访问测试,查看头部信息,server显示了
[root@localhost ~]# curl -I http://192.168.127.130
HTTP/1.1 200 OK
date: Sun, 04 Apr 2021 11:24:44 GMT
last-modified: Mon, 29 Mar 2021 02:33:02 GMT
etag: "6-5bea3b3674691"
accept-ranges: bytes
content-length: 6
content-type: text/html; charset=UTF-8
set-cookie: SERVER-COOKIE=web1; path=/
cache-control: private
HAProxy⽇志配置
-
配置HAProxy记录⽇志到指定⽇志⽂件中
- (我们有些时候可能会在haproxy记日志,但是百分之90的场合下都不记,日志我们会让后端的web服务器去记,通常都是nginx去记,为了优化我们的服务器IO,用nginx去记日志,nginx记日志,处理用户请求的性能相对较高,haproxy记录日志的性能不是很高,所以我们为了降低haproxy的IO所以不在haproxy上记日志,而是将日志直接关掉,关了以后交给nginx去记,tomcat有时候也不记日志,因为tomcat记录日志的性能也不是很强,tomcat本来处理用户的请求就比较吃力,你又给tomcat开日志,会消耗性能,他需要先写日志,在给用户返回数据,这时候这个请求才算是处理完成了,所以说记录日志也会降低服务的并发能力 但是如果非要在haproxy记录日志他也可以,下面是配置)
HAProxy配置
示例
# 在global配置项定义:
log 127.0.0.1 local{1-7} info #基于syslog记录⽇志到指定设备,级别有(err、warning、info、debug)
listen web_port
bind 127.0.0.1:80
mode http
# option httplog # 表示http日志格式
# option tcplog # 表示tcp日志格式
log global # listen中需要添加,单独使用是默认日志格式
server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5
# systemctl restart haproxy
Rsyslog配置
示例
# 编辑系统日志服务配置文件
vim /etc/rsyslog.conf
... (在文件最后添加)
# Provides UDP syslog reception (提供 UDP 系统日志接收)
$ModLoad imudp
$UDPServerRun 514
# Provides TCP syslog reception (提供 TCP 系统日志接收)
$ModLoad imtcp
$InputTCPServerRun 514
local3.* /var/log/haproxy.log
# 重启系统日志服务
systemctl restart rsyslog
验证HAProxy⽇志
重启syslog服务并访问app⻚⾯,然后验证是否⽣成⽇志
示例
# tail -f /var/log/haproxy.log
Aug 14 20:21:06 localhost haproxy[18253]: Connect from
192.168.0.1:3050 to 192.168.7.101:80 (web_host/HTTP)
Aug 14 20:21:06 localhost haproxy[18253]: Connect from
192.168.0.1:3051 to 192.168.7.101:80 (web_host/HTTP)
Aug 14 20:21:06 localhost haproxy[18253]: Connect from
192.168.0.1:3050 to 192.168.7.101:80 (web_host/HTTP)
⾃定义⽇志格式
- 将特定信息记录在⽇志中
配置选项
示例
capture cookie <name> len <length> #捕获请求和响应报⽂中的cookie并记录⽇志,length表示还需要指定长度。
capture request header <name> len <length> #捕获请求报⽂中指定的⾸部内容和⻓度并记录⽇志
capture response header <name> len <length> #捕获响应报⽂中指定的内容和⻓度⾸部并记录⽇志
⽰例:
capture request header Host len 256
capture request header User-Agent len 512
capture request header Referer len 15
配置⽰例
示例
listen web_host
bind 192.168.7.101:80
mode http
balance roundrobin
log global
option httplog #⽇志格式选项
capture request header X-Forwarded-For len 15
capture request header User-Agent len 512
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
示例
示例
示例
# 查看配置文件中的日志记录级别,并在listen中引用
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
...
log 127.0.0.1 local3 info # 日志发给 127.0.0.1这个地址的local3,这个日志级别是info,(info记录级别可以调) (local3级别最大到7)
...
listen webserver-80
log global # 在webserver-80引用日志,访问webserver-80的时候会记录日志
option httplog # 添加日志格式选项(以httplog格式去记录日志)
capture request header User-Agent len 8 # 捕获访问报文头部(可以写多个),比如User-Agent,指定捕获长度len 8表示长度前8位(长度不写不行,重启会报错,如果向记录全部类型len 512记录512位)
# capture request header Cookie len 8
...
# 然后在修改配置文件(在文件最低加一条)
[root@localhost ~]# vi /etc/rsyslog.conf
# Provides UDP syslog reception(提供UDP Syslog接收) (这个端口是udp的所以需要打开)
$ModLoad imudp # 打开
$UDPServerRun 514 # 打开端口,他会去找127.0.0.1:514,不打开是访问不了的,这个端口是udp的
local3.* /var/log/haproxy.log # 凡是local3级别的.*所有日志记录在/var/log/haproxy.log
# 重启rsyslog和haproxy
[root@localhost ~]# systemctl restart rsyslog
[root@localhost ~]# systemctl restart haproxy
# 查看是否监听514端口
[root@localhost ~]# ss -tunl
udp UNCONN 0 0 :::514 :::*
# 客户端访问测试
[root@localhost ~]# curl http://192.168.127.130
web B
[root@localhost ~]# curl http://192.168.127.130
web A
## 查看日志是否记录(可以看到日志已经记录)(这个日志比较简单)
[root@localhost ~]# ll /var/log/haproxy.log
-rw-------. 1 root root 9646 4月 4 19:59 /var/log/haproxy.log
Apr 4 20:14:40 localhost haproxy[44512]: 192.168.127.1:57747 [04/Apr/2021:20:14:40.348] webserver-80 webserver-80/web1 0/0/1/1/2 304 130 - - ---- 4/2/0/0/0 0/0 {Mozilla/} "GET / HTTP/1.1"
Apr 4 20:14:40 localhost haproxy[44512]: 192.168.127.1:57747 [04/Apr/2021:20:14:40.887] webserver-80 webserver-80/web2 0/0/0/2/2 200 237 - - ---- 4/2/0/0/0 0/0 {Mozilla/} "GET / HTTP/1.1"
Apr 4 20:14:41 localhost haproxy[44512]: Connect from 192.168.127.1:57721 to 192.168.127.130:9999 (stats/HTTP)
Apr 4 20:14:41 localhost haproxy[44512]: Connect from 192.168.127.1:57721 to 192.168.127.130:9999 (stats/HTTP)
Apr 4 20:14:44 localhost haproxy[44512]: Connect from 192.168.127.1:57721 to 192.168.127.130:9999 (stats/HTTP)
Apr 4 20:14:44 localhost haproxy[44512]: Connect from 192.168.127.1:57721 to 192.168.127.130:9999 (stats/HTTP)
Apr 4 20:14:47 localhost haproxy[44512]: Connect from 192.168.127.1:57721 to 192.168.127.130:9999 (stats/HTTP)
Apr 4 20:14:47 localhost haproxy[44512]: Connect from 192.168.127.1:57721 to 192.168.127.130:9999 (stats/HTTP)
压缩功能
- 对响应给客⼾端的报⽂进⾏压缩,以节省出口⽹络带宽,但是会占⽤部分CPU性能。
- (浏览器的请求报文中会提示,浏览器支持的压缩格式,比如google的Accept-Encoding: gzip, deflate)
配置选项
示例
compression algo #启⽤http协议中的压缩机制,常⽤算法有gzip deflate
identity #调试使⽤的压缩⽅式(调试用的,生产中不用)
gzip #常⽤的压缩⽅式,与各浏览器兼容较好(使用较多)
deflate #有些浏览器不⽀持
raw-deflate #新出的压缩⽅式
compression type #要压缩的⽂件类型
配置⽰例
示例
listen web_host
bind 192.168.7.101:80
mode http
balance roundrobin
log global
option httplog
#capture request header X-Forwarded-For len 15
#capture request header User-Agent len 512
compression algo gzip deflate # 开启压缩,写两个压缩格式,他会和浏览器协商使用一个
compression type text/plain text/html text/css text/xml text/javascript application/javascript # 压缩类型,对那些类型的文件进行压缩
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
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
验证压缩功能
示例
# web A 准备一个文件,最好大点,比较好显示压缩后的区别
[root@localhost ~]# ll /var/www/html/
总用量 2268
-rw-r--r--. 1 root root 6 3月 29 10:33 index.html
-rw-r--r--. 1 root root 2314700 3月 29 22:05 test.txt
[root@localhost ~]# ll -h /var/www/html/
总用量 2.3M
-rw-r--r--. 1 root root 6 3月 29 10:33 index.html
-rw-r--r--. 1 root root 2.3M 3月 29 22:05 test.txt # 压缩传输前文件是2.3M
# 浏览器访问测试(可以看到压缩传输后的文件大小是787KB)(查看响应报文content-encoding: gzip,可以看到服务器和浏览器协商使用的压缩算法是gzip)
http://192.168.127.130/test.txt
web服务器状态监测
- 基于不同的监测⽅式,对后端real server进⾏状态监测
示例
# 基于什么来对后端服务器做检测
option httpchk
option httpchk <uri>
option httpchk <method> <uri>
option httpchk <method> <uri> <version>
三种状态监测⽅式
基于四层的传输端⼝做状态监测
基于指定URI 做状态监测
基于指定URI的request请求头部内容做状态监测
配置⽰例
示例
listen web_host
bind 192.168.7.101:80
mode http
balance roundrobin
log global
option httplog
#option httpchk GET /app/monitor/check.html HTTP/1.0 # 请求方法使用GET,对/app/monitor/check.html这个uri做检测(这个页面文件需要存在,并且可以访问,才可以),使用 HTTP/1.0协议(他会检测server web1定义的192.168.7.103:80 这个地址下的/app/monitor/check.html这个uri文件,这个文件需要小点,比如几个直字节,因为他检测就是访问以下这个页面)(他对这个listen下的所有后端服务器生效,所有后端服务器都需要有这个目录,否者haproxy就认为你这个服务挂了)
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130 # 上面的方式会请求完成页面,浪费时间和带宽,我们一般看到返回的状态码是200就可以了,所有我们使用HEAD方法,\r\n表示空格后面的host表示告诉后端服务器检测的时候,他往哪个源地址检测,这个host可以不加,这里加上haproxy的地址,因为是haproxy访问的
cookie SERVER-COOKIE insert indirect nocache
server web1 192.168.7.103:80 cookie web1 check inter 3000 fall 3 rise 5 (不可以添加多地址和端口,否者状基于uri的状态检测会报错)
server web2 192.168.7.104:80 cookie web2 check inter 3000 fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
验证http监测
示例
# web A创建检测,测试页面
[root@localhost ~]# cd /var/www/html/
[root@localhost html]# mkdir -pv ./app/monitor/
mkdir: 已创建目录 "./app"
mkdir: 已创建目录 "./app/monitor/"
[root@localhost html]# echo app/monitor/check.html > /var/www/html/app/monitor/check.html
[root@localhost html]# cat /var/www/html/app/monitor/check.html
app/monitor/check.html
# 查看状态页(测试成功,删除检测文件,服务down)
http://192.168.127.130:9999/haproxy-status#webserver-80/Backend
# 删除检测文件,服务down
[root@localhost html]# rm -rf /var/www/html/app/monitor/check.html
# 创建后服务器up
[root@localhost html]# echo app/monitor/check.html > /var/www/html/app/monitor/check.html
ACL
-
访问控制列表(ACL,Access Control Lists)是⼀种基于包过滤的访问控制技术,它可以根据设定的条件对经过服务器传输的数据包进⾏过滤(条件匹配),即对接收到的报⽂进⾏匹配和过滤,基于请求报⽂头部中的源地址、源端⼝、⽬标地址、⽬标端⼝、请求⽅法、URL、⽂件后缀等信息内容进⾏匹配并执⾏进⼀步操作,⽐如允许其通过或丢弃。
- (也是用于7层模型,用在4层是不生效的)
-
http://cbonte.github.io/haproxydconv/2.0/configuration.html#7
ACL配置选项
示例
acl <aclname> <criterion> [flags] [operator] [<value>]
acl 名称 匹配规范 匹配模式 具体操作符 操作对象类型
ACL-Name
示例
acl image_service hdr_dom(host) -i img.magedu.com
ACL名称,可以使⽤⼤字⺟A-Z、⼩写字⺟a-z、数字0-9、冒号:、点.、中横线和下划线,并且严格区分⼤⼩写,⽐如Image_site和image_site就是两个完全不同的acl。
ACL-criterion
- 定义ACL匹配规范
示例
hdr([<name> [,<occ>]]): 完全匹配字符串,header的指定信息
hdr_beg([<name> [,<occ>]]): 前缀匹配,header中指定匹配内容的begin
hdr_end([<name> [,<occ>]]): 后缀匹配,header中指定匹配内容end
hdr_dom([<name> [,<occ>]]): 域匹配,header中的domain name
hdr_dir([<name> [,<occ>]]): 路径匹配,header的uri路径
hdr_len([<name> [,<occ>]]): ⻓度匹配,header的⻓度匹配
hdr_reg([<name> [,<occ>]]): 正则表达式匹配,⾃定义表达式(regex)模糊匹配
hdr_sub([<name> [,<occ>]]): ⼦串匹配,header中的uri模糊匹配
dst ⽬标IP
dst_port ⽬标PORT
src 源IP
src_port 源PORT
⽰例:
hdr(<string>) ⽤于测试请求头部⾸部指定内容
hdr_dom(host) 请求的host名称,如 www.helloworid.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.
ACL-flags
示例
# ACL匹配模式
# -i 不区分⼤⼩写
# -m 使⽤指定的pattern匹配⽅法
# -n 不做DNS解析
# -u 禁⽌acl重名,否则多个同名ACL匹配或关系
ACL-operator
- ACL 操作符
示例
整数⽐较: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进⾏匹配
ACL-value
- value的类型
示例
The ACL engine can match these types against patterns of
the following types :
- Boolean #布尔值
- integer or integer range #整数或整数范围,⽐如⽤于匹配端⼝范围
- IP address / network #IP地址或IP范围, 192.168.0.1
,192.168.0.1/24
- string--> www.helloworld.com
exact –精确⽐较
substring—⼦串
suffix-后缀⽐较
prefix-前缀⽐较
subdir-路径, /wp-includes/js/jquery/jquery.js
domain-域名,www.helloworld.com
- regular expression #正则表达式
- hex block #16进制
ACL调⽤⽅式
- ACL调⽤⽅式
示例
- 与:隐式(默认)使⽤
- 或:使⽤“or” 或 “||”表⽰
- 否定:使⽤“!“ 表⽰
-
⽰例:
if valid_src valid_port #与关系,A和B都要满⾜为true
if invalid_src || invalid_port #或,A或者B满⾜⼀个为true
if ! invalid_src #⾮,取反,A和B哪个也不满⾜为true
ACL⽰例-域名匹配
示例
# 备份配置文件
[root@localhost ~]# cp /etc/haproxy/haproxy.cfg /opt
# 编辑配置文件(使用frontend定义下面使用backend调用)
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
log global
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
acl web_host hdr_dom(host) www.helloworld.net
#################################host################################################
use_backend helloworld_host if web_host
#################################default server######################################
default_backend default_web
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3 rise 5
## acl匹配www.helloworld.net访问域名是否通过。
## if web_host判断是否为true,如果为true判断是否允许访问, use_backend helloworld_host表示,如果允许访问调用 helloworld_host这个服务器组
## default_backend default_web表示如果acl匹配不通过,使用备份服务器组
# 安装备份服务器
[root@backup ~]# yum -y install httpd
[root@backup ~]# cat /var/www/html/index.html
web C
# 关闭防火墙
[root@backup ~]# systemctl stop firewalld
[root@backup ~]# setenforce 0
# 启动服务
[root@localhost ~]# systemctl start httpd
[root@localhost ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::80 :::*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
# 客户端访问测试(测试成功)
[root@localhost ~]# cat /etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
192.168.127.130 www.helloworld.net
192.168.127.130 www.helloworld.local
[root@localhost ~]# while true; do curl www.helloworld.net ;sleep 0.2;done
web A
web B
web A
web B
web A
web B
web A
web B
web A
web B
# 测试备份服务器(匹配不上域名的情况下,使用备份服务器组)
[root@localhost ~]# while true; do curl www.helloworld.local ;sleep 0.2;done
web B
web B
web B
web B
web B
ACL⽰例-基于源IP或⼦⽹调度访问
- 将指定的源地址调度⾄指定的web服务器组
示例
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
acl web_host hdr_dom(host) www.helloworld.net
acl ip_range_test src 192.168.127.128 192.168.0.0/24 10.10.10.0/24
#################################host################################################
use_backend helloworld_host if web_host
use_backend ip_range_test_host if ip_range_test
#################################default server######################################
default_backend default_web
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend ip_range_test_host
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3 rise 5
## src 192.168.127.128 192.168.0.0/24 10.10.10.0/24 匹配客户端的ip地址
## if ip_range_test判断是否为true,如果为true判断是否允许访问,如果允许访问use_backend ip_range_test_host使用ip_range_test_host这个服务器组(这个服务器组需要创建好)
# 访问测试(客户端ip192.168.127.128,匹配成功测试访问成功)
[root@localhost ~]# while true; do curl 192.168.127.130 ;sleep 0.2;done
web B
web B
web B
web B
ACL⽰例-基于源地址的访问控制
- 拒绝指定IP或者IP范围访问(这个不合适,都已经访问到haproxy了在拒绝,已经晚了,相等于已经过了防火墙了)
示例
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
acl web_host hdr_dom(host) www.helloworld.net
acl ip_range_test src 192.168.127.128 192.168.0.0/24 10.10.10.0/24
#################################host################################################
use_backend helloworld_host if web_host
# use_backend ip_range_test_host if ip_range_test
# block if ip_range_test_host # block指令不支持了,使用http-request deny
http-request deny if ip_range_test
#################################default server######################################
default_backend default_web
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend ip_range_test_host
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
## src 192.168.127.128 192.168.0.0/24 10.10.10.0/24匹配客户端的ip地址
## if ip_range_test判断是否为true,如果为true,不允许访问http-request deny
# 访问测试(测试成功,会报403错误)
[root@localhost ~]# while true; do curl 192.168.127.130 ;sleep 0.2;done
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
</body></html>
ACL⽰例-匹配浏览器类型
- 匹配客⼾端浏览器,将不同类型的浏览器调动⾄不同的服务器组
示例
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
# acl web_host hdr_dom(host) www.helloworld.net
# acl ip_range_test src 192.168.127.128 192.168.0.0/24 10.10.10.0/24
acl redirect_test hdr_dom(User-Agent) -m sub -i "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36" # 匹配浏览器类型hdr(User-Agent)不成功使用匹配域名,可能是版本的问题,使用hdr_dom(User-Agent)匹配google浏览器类型匹配成功
# acl redirect_test hdr_dom(host) "www.helloworld.net" # 通过域名匹配,测试成功可以跳转
redirect prefix https://www.cnblogs.com/hao-ran/ if redirect_test # 如果匹配成功 redirect prefix做重定向,转跳到https://www.cnblogs.com/hao-ran/
#################################host################################################
use_backend helloworld_host if web_host
# use_backend ip_range_test_host if ip_range_test
# block if ip_range_test_host # block指令不支持了,使用http-request deny
http-request deny if ip_range_test
#################################default server######################################
default_backend default_web
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend ip_range_test_host
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3 rise 5
# -m 使⽤指定的pattern匹配⽅法
# (-m sub) :在提取的字符串中查找模式,如果其中任何⼀个被发现,ACL将匹配
# -i 不区分⼤⼩写
# hdr(<string>) ⽤于测试请求头部⾸部指定内容
# User-Agent 浏览器类型
ACL⽰例-基于⽂件后缀名实现动静分离
- 这个功能不是在haproxy这里配的,我们只是说haproxy有这个功能,因为haproxy能拿到客户访问的uri然后以下文件名的后缀是不是php,或者jpg图片就行
示例
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
acl php_server path_end -i .php
use_backend php_server_host if php_server
acl image_server path_end -i .jpg .png .jpeg .gif
use_backend image_server_host if image_server
#################################host################################################
# use_backend helloworld_host if web_host
# use_backend ip_range_test_host if ip_range_test
# block if ip_range_test_host # block指令不支持了,使用http-request deny
# http-request deny if ip_range_test
#################################default server######################################
default_backend default_web
backend php_server_host # 添加一个php_server_host服务器组
mode http
server web1 192.168.127.129:80 cookie php.web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
backend image_server_host # 添加一个php_server_host静态图片资源服务器组
mode http
server web2 192.168.127.131:80 cookie images.web2 check weight 1 inter 3s fall 3 rise 5
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend ip_range_test_host
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# web A 创建php测试文件(没有文件会访问报错)
[root@localhost ~]# echo "php.web A" > /var/www/html/index.php
[root@localhost ~]# cat /var/www/html/index.php
php.web A
# web B 创建静态图片资源测试文件
[root@localhost ~]# wget -P /var/www/html/ https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png
[root@localhost ~]# mv /var/www/html/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png /var/www/html/image.png
# 访问测试php(测试成功)
[root@localhost ~]# curl http://www.helloworld.net/index.php
php.web A
# 访问测试图片(浏览器测试访问成功)
http://www.helloworld.net/image.png
ACL-匹配访问路径实现动静分离
示例
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
acl static_path path_beg -i /static /images /javascript # 跟匹配文件后缀的做分离的方式一样,这里是匹配路径,访问这些路径的请求(路径可以有多个,匹配其中一个),分配到static_path_host这个服务器组
use_backend static_path_host if static_path
#################################host################################################
use_backend helloworld_host if web_host
# use_backend ip_range_test_host if ip_range_test
# block if ip_range_test_host # block指令不支持了,使用http-request deny
http-request deny if ip_range_test
#################################default server######################################
default_backend default_web
backend static_path_host # 创建static_path_host服务器组
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend ip_range_test_host
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# web B创建目录,没有目录访问会报错
[root@localhost ~]# mkdir -pv /var/www/html/images
mkdir: 已创建目录 "/var/www/html/images"
[root@localhost ~]# mv /var/www/html/image.png /var/www/html/images/image.png
[root@localhost ~]# ls /var/www/html/images/image.png
/var/www/html/images/image.png
# 访问测试(访问成功)
http://www.helloworld.net/images/image.png
ACL⽰例-基于ACL的HTTP访问控制
示例
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
acl badguy_deny src 192.168.127.128 # 匹配用户ip地址
http-request deny if badguy_deny # 判断是否匹配到,如果匹配到为true,然后看是否允许访问,http-request deny表示不允许访问。
#################################host################################################
use_backend helloworld_host if web_host
# use_backend ip_range_test_host if ip_range_test
# block if ip_range_test_host # block指令不支持了,使用http-request deny
http-request deny if ip_range_test
#################################default server######################################
default_backend default_web
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend ip_range_test_host
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3
# 测试(测试成功,状态码403拒绝访问):
[root@localhost ~]# while true; do curl www.helloworld.net ;sleep 0.2;done
<html><body><h1>403 Forbidden</h1>
Request forbidden by administrative rules.
ACL⽰例-预定义ACL使⽤
预定义ACL
| ACL name | Equivalent to | Usage |
|---|---|---|
| FALSE | always_false | never match |
| HTTP | req_proto_http | match if protocol is valid HTTP |
| HTTP_1.0 | req_ver 1.0 | match HTTP version 1.0 |
| HTTP_1.1 | req_ver 1.1 | match HTTP version 1.1 |
| HTTP_CONTENT | hdr_val(contentlength) gt 0 | match an existing content-lengt |
| HTTP_URL_ABS | url_reg [/:]*😕/ | match absolute URL with scheme |
| HTTP_URL_SLASH | url_beg / | match URL beginning with "/" |
| HTTP_URL_STAR | url * | match URL equal to "*" |
| LOCALHOST | src 127.0.0.1/8 | match connection from local host |
| METH_CONNECT | method CONNECT | match HTTP CONNECT method |
| METH_DELETE | method DELETE | match HTTP DELETE method |
| METH_GET | method GET HEAD | match HTTP GET or HEAD method |
| METH_HEAD | method HEA | match HTTP HEAD method |
| METH_OPTIONS | method OPTIONS | match HTTP OPTIONS method |
| METH_POST | method POST | match HTTP POST method |
| METH_PUT | method PUT | match HTTP PUT method |
| METH_TRACE | method TRACE | match HTTP TRACE method |
| RDP_COOKIE | req_rdp_cookie_cntgt 0 | match presence of an RDP cookie |
| REQ_CONTENT | req_len gt 0 | match data in the request buffer |
| TRUE | always_true | always match |
| WAIT_END | wait_end | wait for end of content analysis |
预定义ACL使⽤
示例
frontend webserver-80
bind 192.168.127.130:80
mode http
balance roundrobin
option httplog
option httpchk HEAD /app/monitor/check.html HTTP/1.0\r\nHost:\ 192.168.127.130
#################################ACL settings#######################################
acl image_server path_end -i .jpg .png .jpeg .gif
use_backend image_server_host if image_server HTTP_1.1 # if判断image_server这个acl是否为true并且必选使用HTTP1.1协议的访问,如果不是不是HTTP1.1进行访问的,拒绝访问。如果有默认服务器,有默认服务器(备份服务器)进行返回,但是默认服务器上必须有默认相应的路径文件。
# use_backend image_server_host if image_server || HTTP_1.1 # 两者满足一种就可以了,转跳到image_server_host服务器组,进行请求响应
# use_backend image_server_host if image_server HTTP_1.1 METH_GET # 指定请求方法,满足前面的条件,并且必须是get方法请求的页面
#################################host################################################
use_backend helloworld_host if web_host
# use_backend ip_range_test_host if ip_range_test
# block if ip_range_test_host # block指令不支持了,使用http-request deny
http-request deny if ip_range_test
#################################default server######################################
default_backend default_web
backend image_server_host
mode http
server web2 192.168.127.131:80 cookie images.web2 check weight 1 inter 3s fall 3 rise 5
backend helloworld_host
mode http
server web1 192.168.127.129:80 cookie web1 check weight 1 maxconn 500 inter 3s fall 3 rise 5
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend ip_range_test_host
mode http
server web2 192.168.127.131:80 cookie web2 check weight 1 inter 3s fall 3 rise 5
backend default_web
mode http
server web3 192.168.127.132:80 check weight 1 inter 3s fall 3
# 默认服务器(备份服务器)创建测试文件
[root@backup ~]# wget -P /var/www/html/ https://ss1.baidu.com/-4o3dSag_xI4khGko9WTAnF6hhy/exp/w=500/sign=351c5f848a025aafd3327ecbcbedab8d/86d6277f9e2f0708cc373344e124b899a901f240.jpg
[root@backup ~]# cd /var/www/html/
[root@backup images]# mv 86d6277f9e2f0708cc373344e124b899a901f240.jpg image.png
⾃定义HAProxy错误界⾯
- 对指定的报错进⾏重定向,进⾏优雅的显⽰错误⻚⾯
基于错误⻚⾯⽂件
示例
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
defaults # 注意在defaults中添加
#option forwardfor
#no option http-use-htx
#...... #以下三⾏
# errorfile 500 /usr/local/haproxy/html/500.html # errorfile根据我们的状态码(注意这个状态码,一定是haproxy本身产生的状态码,因为haproxy不处理用户请求,所以没有404,他是转发给后端服务器处理的),和路径,这个路径是我们haproxy的本地路径,一个haproxy上的一个html文件,此文件需要事先存在
# errorfile 502 /usr/local/haproxy/html/502.html # 此文件需要事先存在
errorfile 503 /usr/local/haproxy/html/503.html # 此文件需要事先存在
# 参考haproxy本身的错误html文件示例
[root@localhost ~]# find /usr/local/src/haproxy-2.2.12/ -name *.http
/usr/local/src/haproxy-2.2.12/examples/errorfiles/400.http
/usr/local/src/haproxy-2.2.12/examples/errorfiles/403.http
/usr/local/src/haproxy-2.2.12/examples/errorfiles/408.http
/usr/local/src/haproxy-2.2.12/examples/errorfiles/500.http
/usr/local/src/haproxy-2.2.12/examples/errorfiles/502.http
/usr/local/src/haproxy-2.2.12/examples/errorfiles/503.http
/usr/local/src/haproxy-2.2.12/examples/errorfiles/504.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/400-1.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/400-2.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/400-3.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/400.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/403-1.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/403-2.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/403.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/404-1.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/404-2.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/404-3.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/404.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/500-1.http
/usr/local/src/haproxy-2.2.12/reg-tests/http-errorfiles/errors/500.http
# 创建错误文件html文件(现在有特定的格式,必须使用html)
[root@localhost ~]# mkdir -pv /usr/local/haproxy/html/
mkdir: 已创建目录 "/usr/local/haproxy"
mkdir: 已创建目录 "/usr/local/haproxy/html
[root@localhost ~]# cat /usr/local/src/haproxy-2.2.12/examples/errorfiles/503.http > /usr/local/haproxy/html/503.html
[root@localhost ~]# cat /usr/local/haproxy/html/503.html
HTTP/1.0 503 Service Unavailable
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<html><body><h1>503 Service Unavailable</h1>
No server is available to handle this request.
</body></html>
# 编辑错误页面(改改文字就行了,格式不能改,改了就启动不起来)
[root@localhost ~]# vi /usr/local/haproxy/html/503.html
HTTP/1.0 503 12333333333^M
Cache-Control: no-cache^M
Connection: close^M
Content-Type: text/html^M
^M
<html><body><h1>503 tel: 12333333333</h1>
No server is available to handle this request.
</body></html>
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# 关掉web A,wab B,web C的服务器,测试错误页面
[root@localhost ~]# systemctl restart haproxy
# 访问测试(测试成功)
[root@localhost ~]# curl http://www.helloworld.net/
<html><body><h1>503 tel: 12333333333</h1>
No server is available to handle this request.
</body></html>
基于http重定向
- (公司中可能报错不在本地,而是有专门的报错服务器)
示例
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
defaults # 注意在defaults中添加
#option http-keep-alive
#option forwardfor
#no option http-use-htx
#...... 以下⼀⾏
errorloc 503 http://192.168.127.132/error_page/503.html # 使用errorloc当状态码为503的时候,转到远程的服务器上进行报错显示
# 重载naproxy
[root@localhost ~]# systemctl restart haproxy
# 创建错误页面服务器
[root@backup html]# yum -y install httpd
# 创建错误测试页面
[root@backup html]# mkdir -pv /var/www/html/error_page
mkdir: 已创建目录 "/var/www/html/error_page"
[root@backup html]# vi /var/www/html/error_page/503.html
error_page
# 启动httpd,并关闭防火墙
[root@backup html]# systemctl start httpd
[root@backup html]# systemctl stop firewalld
[root@backup html]# setenforce 0
# 访问测试(浏览器访问测试成功)
http://192.168.127.132/error_page/503.html
error_page 192.168.127.132
HAProxy四层负载
- 针对有特殊访问写完的应⽤场景
- Memcache
- Redis
- MySQL
- RabbitMQ
四层负载⽰例
- (跟nginx的差不多)
示例
# 编辑配置文件(添加一个listen,这listen要自己写监听地址)
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
listen redis_port
bind 192.168.127.130:6379
mode tcp
balance static-rr
server redis192.168.127.129 192.168.127.129:6379 check inter 3s fall 3 rise 5
server redis192.168.127.131 192.168.127.131:6379 check inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# 安装epel源并安装redis
[root@localhost ~]# yum -y install epel-release
[root@localhost ~]# yum -y install redis
# 启动前修改配置文件(改掉监听地址)
[root@localhost ~]# vi /etc/redis.conf
bind 0.0.0.0
# 启动redis(启动redis需要指定配置文件。启动后会监听在6379端口)
[root@localhost ~]# redis-server /etc/redis.conf
[root@localhost ~]# ss -tnl
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 *:6379 *:*
LISTEN 0 128 *:22 *:*
LISTEN 0 100 127.0.0.1:25 *:*
LISTEN 0 128 :::22 :::*
LISTEN 0 100 ::1:25 :::*
# 客户端访问测试(输入info测试成功,退出redis使用ctrl+],然后在quit)
[root@localhost ~]# telnet 192.168.127.130 6379
Trying 192.168.127.130...
Connected to 192.168.127.130.
Escape character is '^]'.
info
ACL⽰例-四层访问控制
示例
listen redis_port
bind 192.168.127.130:6379
mode tcp
acl invalid_src src 192.168.1.0/24 192.168.7.102 192.168.127.128 # 添加acl匹配ip地址
tcp-request connection reject if invalid_src balance static-rr # if判断是否匹配到,是否为true,如果可以匹配成功,tcp-request connection reject直接拒绝
server redis192.168.127.129 192.168.127.129:6379 check inter 3s fall 3 rise 5
server redis192.168.127.131 192.168.127.131:6379 check inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# 客户端在访问(客户端地址192.168.127.128,拒绝访问测试成功)
[root@localhost ~]# telnet 192.168.127.130 6379
Trying 192.168.127.130...
Connected to 192.168.127.130.
Escape character is '^]'.
Connection closed by foreign host.
HAProxy https实现
- (证书都是配置在nginx中的,很少配置在haproxy中,但是haproxy也支持配置证书,如果配置了,一般客户端和haproxy连接使用的是https,而haproxy和后端服务器用的是http,所以加密解密的作用都有haproxy完成)
示例
配置HAProxy⽀持https协议:
⽀持ssl会话;
bind *:443 ssl crt /PATH/TO/SOME_PEM_FILE
crt 后证书⽂件为PEM格式,且同时包含证书和所有私钥
cat demo.crt demo.key > demo.pem
把80端⼝的请求重向定443(重定向也算是全站https了)
bind *:80
redirect scheme https if !{ ssl_fc }
向后端传递⽤⼾请求的协议和端⼝(frontend或backend)
http_request set-header X-Forwarded-Port %[dst_port]
http_request add-header X-Forwared-Proto https if {ssl_fc }
证书制作
示例
# 创建目录(用于保存证书)
[root@localhost ~]# mkdir -pv /usr/local/haproxy/certs
mkdir: 已创建目录 "/usr/local/haproxy/certs"
# 切换目录
[root@localhost ~]# cd /usr/local/haproxy/certs
# 生成证书
[root@localhost certs]# openssl genrsa -out haproxy.key 2048
Generating RSA private key, 2048 bit long modulus
..........................................+++
.............................+++
e is 65537 (0x10001)
# 自签以下证书
[root@localhost certs]# openssl req -new -x509 -key haproxy.key -out haproxy.crt -subj "/CN=www.helloworld.net"
[root@localhost certs]# ls
haproxy.crt haproxy.key
# 公钥和私钥合并成一个文件.pem文件
[root@localhost certs]# cat haproxy.key haproxy.crt > haproxy.pem
[root@localhost certs]# ls
haproxy.crt haproxy.key haproxy.pem
# 查看证书的签发信息
[root@localhost certs]# openssl x509 -in haproxy.pem -noout -text
# 修改权限(权限为600,安全一点)
[root@localhost certs]# chmod 600 haproxy.*
[root@localhost certs]# ll
总用量 12
-rw-------. 1 600 root 1119 4月 5 17:12 haproxy.crt
-rw-------. 1 600 root 1679 4月 5 17:11 haproxy.key
-rw-------. 1 600 root 2798 4月 5 17:13 haproxy.pem
https配置⽰例
示例
################# 使用frontend和backend方式,定义一个frontend和backend
[root@localhost ~]# vi /etc/haproxy/haproxy.cfg
#web server http
frontend web_server-http
bind 192.168.127.130:80
redirect scheme https if !{ ssl_fc } # 全站https,如果你不是https访问我,就给你重定向到https,需要些在bind绑定在80端口的配置块中
mode http
use_backend web_host
#web server https(在frontend中bind绑定地址和端口,添加证书路径(crt表示证书),frontend引用,backend定义)
frontend web_server-https
bind 192.168.127.130:443 ssl crt /usr/local/haproxy/certs/haproxy.pem
mode http
use_backend web_host # 调用backend web_host
backend default_host
mode http
server web1 192.168.7.102:80 check inter 2000 fall 3 rise 5
backend web_host
mode http
# http-request set-header X-Forwarded-Port %[dst_port]
# http-request add-header X-Forwarded-Proto https if {ssl_fc }
server redis192.168.127.129 192.168.127.129:6379 check inter 3s fall 3 rise 5
server redis192.168.127.131 192.168.127.131:6379 check inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# 访问测试(浏览器强制输入https进行测试,他就转跳到bind 192.168.7.101:443监听的443端口)
https://192.168.127.130/
################# 使用listen方式
listen web_http_80_host
bind 192.168.127.130:80
redirect scheme https if !{ ssl_fc } # 全站https
listen web_https_443_host
bind 192.168.127.130:443 ssl crt /usr/local/haproxy/certs/haproxy.pem
mode http
http-request set-header X-Forwarded-Port %[dst_port] # ip地址透传
http-request add-header X-Forwarded-Proto https if {ssl_fc } # ip地址透传
server redis192.168.127.129 192.168.127.129:6379 check inter 3s fall 3 rise 5
server redis192.168.127.131 192.168.127.131:6379 check inter 3s fall 3 rise 5
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# 访问测试(浏览器强制输入http进行测试,他就转跳到bind 192.168.7.101:443监听的443端口)
http://192.168.127.130/
验证https
- 重点部分
- HAProxy调度算法
- 动静分离与客⼾端源IP透传
- ACL使⽤与报⽂修改
- 服务器动态下线:
- 编写shell脚本,实现能够基于参数传递real server服务器IP,并实现将其从多个HAProxy进程下线与上线(下线需要对haproxy的每一个进程都下线)
示例
# 每一个线程都需要一个socket文件,单独进行管理(haporxy是通过socket进行管理的),/var/lib/haproxy/haproxy1.sock表示第一个工作进程的路径,这个文件不能重名,process 表示进程,1表示进程编号
global
stats socket /var/lib/haproxy/haproxy1.sock mode 600 level admin process 1
stats socket /var/lib/haproxy/haproxy2.sock mode 600 level admin process 2
stats socket /var/lib/haproxy/haproxy3.sock mode 600 level admin process 3
stats socket /var/lib/haproxy/haproxy4.sock mode 600 level admin process 4
nbproc 4
cpu-map 1 0
cpu-map 2 1
cpu-map 3 2
cpu-map 4 3
# 重载haproxy
[root@localhost ~]# systemctl restart haproxy
# 查看创建的socket文件
[root@localhost ~]# ll /var/lib/haproxy/
总用量 4
srw-------. 1 root root 0 4月 5 18:04 haproxy1.sock
srw-------. 1 root root 0 4月 5 18:04 haproxy2.sock
srw-------. 1 root root 0 4月 5 18:04 haproxy3.sock
srw-------. 1 root root 0 4月 5 18:04 haproxy4.sock
-rw-r--r--. 1 root root 5 4月 5 18:04 haproxy.pid
srw-------. 1 root root 0 4月 5 18:02 haproxy.sock
# 下线服务
[root@localhost ~]# echo "disable server web_https_443_host/web1" | socat stdio /var/lib/haproxy/haproxy1.sock
# 但是访问时可以看到服务依然在(这是因为,我们开的4个线程,我们只下线了一个线程中的服务器,另外三个进程依然在提供服务器)
[root@localhost ~]# while true; do curl http://192.168.127.130;sleep 0.2;done
web B
web A
web A
web B
web B
web A
web A
# 4个进程全部下线(从状态页看,我们已经成功下线了一个台服务器)
[root@localhost ~]# echo "disable server web_http_80_host/web1" | socat stdio /var/lib/haproxy/haproxy2.sock
[root@localhost ~]# echo "disable server web_http_80_host/web1" | socat stdio /var/lib/haproxy/haproxy1.sock
[root@localhost ~]# echo "disable server web_http_80_host/web1" | socat stdio /var/lib/haproxy/haproxy3.sock
[root@localhost ~]# echo "disable server web_http_80_host/web1" | socat stdio /var/lib/haproxy/haproxy4.sock
# 访问测试(web A已经不在提供服务)
[root@localhost ~]# while true; do curl http://192.168.127.130;sleep 0.2;done
web B
web B
web B
web B
web B
web B
# 使用脚本下线服务器
[root@localhost ~]# vi haproxy-deploy.sh
#!/bin/bash
NUM=`seq 1 4`
echo $NUM
HOST=$1
UP=$2
for i in ${NUM};do
echo "${UP} server web_http_80_host/$(HOST)" | socat stdio /var/lib/haproxy/haproxy${i}.sock
echo "server $(HOST) in process haproxy${i} ${UP} ok"
done
#!/bin/bash
NUM=`seq 1 4` # 定义进程数,获取进程编号,这个变量会传给/var/lib/haproxy/haproxy$NUM.sock这儿
echo $NUM
HOST=$1 # 执行脚本的时候,传参,比如你想下线哪个服务器
UP=$2 # 启动服务器还是下线服务器disable下线,enable是启动
echo $HOST
for i in ${NUM};do
echo "${UP} server web_http_80_host/${HOST}" | socat stdio /var/lib/haproxy/haproxy${i}.sock # 操作sock文件
echo "server ${HOST} in process haproxy${i} ${UP} ok"
done
# 执行脚本(查看状态页,disable下线成功,enable是启动可以测试玩)
[root@localhost ~]# bash haproxy-deploy.sh web1 disable

浙公网安备 33010602011771号