HAProxy是法国开发者 威利塔罗(Willy Tarreau) 在2000年使用C语言开发的一个开源软件,是一款具备高并发(一万以上)、高性能的TCP>和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态统计。
  HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在当前的硬件上,完全可以支持数以万计的并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。
  包括 GitHub、Bitbucket、Stack Overflow、Reddit、Tumblr、Twitter和 Tuenti[7]在内的知名网站,及亚马逊网络服务系统都使用了HAProxy。

HAProxy功能

HAProxy功能:

  • TCP和HTTP反向代理
  • SSL/TSL服务器
  • 可以针对HTTP请求添加cookie,进行路由后端服务器
  • 可平衡负载至后端服务器,并支持持久连接
  • 支持所有主服务器故障切换至备用服务器
  • 支持专用端口实现监控服务
  • 支持不影响现有连接情况下停止接受新连接请求
  • 可以在双向添加,修改或删除HTTP报文首部
  • 响应报文压缩
  • 支持基于pattern实现连接请求的访问控制
  • 通过特定的URI为授权用户提供详细的状态信息

不具备的功能:

  • 正向代理–squid,nginx
  • 缓存代理–varnish
  • web服务–nginx、tengine、apache、php、tomcat
  • UDP–目前不支持UDP协议,2.1版本会支持UDP协议代理
  • 单机性能–LVS

HAProxy安装

  HAProxy 支持基于lua实现功能扩展,lua是一种小巧的脚本语言,于1993年由巴西里约热内卢天主教大学(Pontifical Catholic University of Rio de Janeiro)里的一个研究小组开发,其设计目的是为了嵌入应用程序中,从而为应用程序提供灵活的扩展和定制功能。
  由于centos自带的lua版本比较低并不符合HAProxy要求的lua最低版本(5.3)的要求,因此需要编译安装较新版本的lua环境,然后才能编译安装HAProxy。

安装lua环境

  配置lua环境

1
yum install libtermcap-devel ncurses-devel libevent-devel readline-devel gcc make

  下载lua源码tar包

1
wget http://www.lua.org/ftp/lua-5.3.5.tar.gz

  编译安装lua

1
2
3
tar xvf lua-5.3.5.tar.gz
cd lua-5.3.5
make linux test

安装HAProxy

  下载haproxy源码包

1
wget http://www.haproxy.org/download/2.0/src/haproxy-2.0.8.tar.gz

  安装依赖包

1
yum install gcc gcc-c++ glibc glibc-devel pcre pcre-devel openssl openssl-devel systemd-devel

  (附加工具包net-tools vim iotop bc zip unzip zlib-devel lrzsz tree screen lsof tcpdump wget ntpdate
  编译安装haproxy
  cd haproxy-2.0.8
  HAProxy 1.8及1.9版本编译参数:

1
2
3
4
5
6
7
8
make ARCH=x86_64 \
TARGET=linux2628 \
USE_PCRE=1 \
USE_OPENSSL=1 \
USE_ZLIB=1 \
USE_SYSTEMD=1 \
USE_CPU_AFFINITY=1 \
PREFIX=/apps/haproxy

  HAProxy 2.0编译参数:

1
2
3
4
5
6
7
8
9
10
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=/data/tar/lua-5.3.5/src/ \
LUA_LIB=/data/tar/lua-5.3.5/src/ \
PREFIX=/apps/haproxy
1
2
make install PREFIX=/apps/haproxy
cp haproxy /usr/sbin/

  haproxy启动脚本
  vim /usr/lib/systemd/system/haproxy.service

1
2
3
4
5
6
7
8
9
[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target
[Service]
ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /var/lib/haproxy/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID
[Install]
WantedBy=multi-user.target\

  haproxy配置文件(基本配置文件)
  mkdir /etc/haproxy
  vim /etc/haproxy/haproxy.cfg

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
global
chroot /apps/haproxy #锁定运行目录
stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin #socket文件
uid 99 #运行haproxy的用户身份,也可设user,group
gid 99
daemon #以守护进程运行
# nbproc 4 #指定每个haproxy进程开启的线程数,默认为每个进程一个线程
# cpu-map 1 0 #绑定haproxy 进程至指定CPU
# cpu-map 2 1
# cpu-map 3 2
# cpu-map 4 3
maxconn 100000 #每个haproxy进程的最大并发连接数
#maxsslconn #每个haproxy进程ssl最大连接数,用于haproxy配置了证书的场景下
#spread-checks #后端server状态check随机提前或延迟百分比时间,建议2-5(20%-50%)之间
pidfile /var/lib/haproxy/haproxy.pid
log 127.0.0.1 local3 info #定义全局的syslog服务器;最多可以定义两个



defaults
option http-keep-alive
option forwardfor
maxconn 100000
mode http
timeout connect 300000ms
timeout client 300000ms
timeout server 300000ms

listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /haproxy-status
stats auth haadmin:q1w2e3r4ys
listen web_port
bind 192.168.32.84:80
mode http
log global
server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5

  设置haproxypid及socket创建权限
  useradd -s /sbin/nologin -r -u 99 haproxy
  mkdir /var/lib/haproxy
  chown 99.99 /var/lib/haproxy/ -R

  至此,才完成haproxy的安装与配置,启动并查看haproxy的状态是否正常吧。
  systemctl enable --now haproxy
  systemctl status haproxy

配置web均衡

  haproxy最主要的功能就是为后端服务器做反向代理,例如我们要为后面的四个web服务器做反向代理,配置文件如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
global
maxconn 100000
chroot /apps/haproxy
stats socket /var/lib/haproxy/haproxy.sock1 mode 600 level admin process 1
stats socket /var/lib/haproxy/haproxy.sock2 mode 600 level admin process 2
uid 99
gid 99
daemon
nbproc 2 #指定每个haproxy进程开启的线程数,默认为每个进程一个线程
cpu-map 1 0 #cpu工作线程绑定
cpu-map 2 1
# cpu-map 3 2
# cpu-map 4 3
pidfile /var/lib/haproxy/haproxy.pid
log 127.0.0.1 local3 info

defaults
option redispatch #当server Id对应的服务器挂掉后,强制定向到其他健康的服务器
option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接
option http-keep-alive #开启与客户端的会话保持
option forwardfor #透传客户端真实IP至后端web服务器
mode http #默认工作类型
timeout connect 600s #客户端请求到后端server的最长连接等待时间(TCP之前)
timeout server 600s #客户端请求到后端服务端的超时超时时长(TCP之后)
timeout client 600s #与客户端的最长非活动时间
timeout http-keep-alive 120s #session会话保持超时时间,范围内会转发到相同的后端服务器
timeout check 50s #对后端服务器的检测超时时间option http-keep-alive

#frontend WEB_PORT_80
# bind 192.168.32.84:80
# mode http
# use_backend web_prot_http_nodes

#backend web_prot_http_nodes
# mode http
# option forwardfor
# balance static-rr
# server web0 192.168.32.8:80 check inter 3000 fall 3 rise 5
# server web3 192.168.32.83:80 check inter 3000 fall 3 rise 5
# server web2 192.168.32.82:80 check inter 3000 fall 3 rise 5
# server web1 192.168.32.81:80 check inter 3000 fall 3 rise 5


listen stats
bind 0.0.0.0:9999
mode http
stats enable
log global
stats uri /proxy_status #进入后台状态页url路径
stats auth haadmin:hapasswd #进入后台的账号密码

listen web_host #使用listen替换frontend+backend的配置方式
bind 192.168.32.84:80
mode http
log global
balance roundrobin #定义调度算法为roundrobin
server web0 192.168.32.8:80 weight 1 check addr 192.168.32.8 port 9000 inter 3000 fall 2 rise 5
server web1 192.168.32.81:80 weight 1 check addr 192.168.32.81 port 9000 inter 3000 fall 2 rise 5
server web2 192.168.32.82:80 weight 1 check addr 192.168.32.82 port 9000 inter 3000 fall 2 rise 5
server web3 192.168.32.83:80 weight 1 check addr 192.168.32.83 port 9000 inter 3000 fall 2 rise 5

  重启服务systemctl restart haproxy,便可登陆本机的状态页(haadmin:hapasswd)查看后端服务器状态。

在这里插入图片描述
  刷新几次可以看到,不同pid也就是不同线程提供的status页面。
在这里插入图片描述

配置详解

globe 全局配置段
1
2
3
进程及安全配置相关的参数
性能调整相关参数
Debug参数

  全局配置一般大多类似不用多说,须注意的是nbproc若开启多线程,socket设置最好也分开设置,最好每个线程用process #指定固定的socket,方便后期用命令行socat工具管理(echo "disable server web_host/web1" | socat stdio /var/lib/haproxy/haproxy.sock2),例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
global
maxconn 100000
chroot /apps/haproxy
stats socket /var/lib/haproxy/haproxy.sock1 mode 600 level admin process 1
stats socket /var/lib/haproxy/haproxy.sock2 mode 600 level admin process 2
uid 99
gid 99
daemon
nbproc 2 #指定每个haproxy进程开启的线程数,默认为每个进程一个线程
cpu-map 1 0 #cpu工作线程绑定
cpu-map 2 1
pidfile /var/lib/haproxy/haproxy.pid
log 127.0.0.1 local3 info

  其他详细信息参见官方文档:https://cbonte.github.io/haproxy-dconv/2.0/intro.html

proxies:代理配置段
1
2
3
4
defaults [&ltname&gt]  #默认配置项,针对以下的frontend、backend和lsiten生效,可以多个name
frontend &ltname&gt #前端servername,类似于Nginx的一个虚拟主机 server。
backend &ltname&gt #后端服务器组,等于nginx的upstream
listen &ltname&gt #将frontend和backend合并在一起配置

  注:name字段只能使用”-”、”_”、”.”、和”:”,并且严格区分大小写,例如:Web和web是完全不同的两组服务器。

  • defaults

option redispatch #当server Id对应的服务器挂掉后,强制定向到其他健康的服务器
option abortonclose #当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接
option http-keep-alive #开启与客户端的会话保持
option forwardfor #透传客户端真实IP至后端web服务器
mode http #默认工作类型
timeout connect 120s #客户端请求到后端server的最长连接等待时间(TCP之前)
timeout server 600s #客户端请求到后端服务端的超时超时时长(TCP之后)
timeout client 600s #与客户端的最长非活动时间
timeout http-keep-alive 120s #session 会话保持超时时间,范围内会转发到相同的后端服务器
timeout check 5s #对后端服务器的检测超时时间

  • frontend

bind:指定HAProxy的监听地址,可以是IPV4或IPV6,可以同时监听多个IP或端口,可同时用于listen字段中

1
bind [&ltaddress&gt]:&ltport_range&gt [, ...] [param*]
1
2
3
4
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
1
2
3
listen http_https_proxy #https监听
bind :80
bind :443 ssl crt /etc/haproxy/site.pem
1
2
3
4
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 accept-proxy
1
2
listen external_bind_app1 #监听file descriptor
bind "fd@${FD_APP1}"

  企业生产示例:

1
2
3
4
5
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 #调用的后端服务器组名称
  • backend
    定义一组后端服务器,backend服务器将被frontend进行调用。
1
2
3
mode http/tcp #指定负载协议类型
option #配置选项
server #定义后端real server

  注意:mode要与frontend一致。option后面加httpchk,smtpchk,mysql-check,pgsql-check,ssl-hello-chk方法,可用于实现更多应用层检测功能。

1
2
3
4
5
6
7
8
9
10
11
12
check #对指定real进行健康状态检查,默认不开启
addr IP #可指定的健康状态监测IP
port num #指定的健康状态监测端口
inter num #健康状态检查间隔时间,默认2000 ms
fall num #后端服务器失效检查次数,默认为3
rise num #后端服务器从下线恢复检查次数,默认为2
weight #默认为1,最大值为256,0表示不参与负载均衡
backup #将后端服务器标记为备份状态
disabled #将后端服务器标记为不可用状态
redirect prefix http://www.example.net/ #将请求临时重定向至其它URL,只适用于http模式
maxconn &ltmaxconn&gt:当前后端server的最大并发连接数
backlog &ltbacklog&gt:当server的连接数达到上限后的后援队列长度

  frontend+backend配置实例:

1
2
3
4
5
6
7
8
9
10
#官网业务访问入口======================================
frontend WEB_PORT_80
bind 192.168.7.248:80
mode http
use_backend web_prot_http_nodes
backend web_prot_http_nodes
mode http
option forwardfor
server 192.168.7.101 192.168.7.101:8080 check inter 3000 fall 3 rise 5
server 192.168.7.102 192.168.7.102:8080 check inter 3000 fall 3 rise 5
  • listen
    listen相当于frontend+backend的结合,即定义前端监听代理,又定义了后端服务器,例如上面的frontend+backend组合可用下面这种listen方式代替:
1
2
3
4
5
6
7
#官网业务访问入口=====================================
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的调度算法分为静态和动态调度算法,但是有些算法可以根据参数在静态和动态算法中相互转换。

静态算法

  • static-rr
    基于权重的轮询调度,不支持权重的运行时调整及后端服务器慢启动,其后端主机数量没有限制
  • first
    根据服务器在列表中的位置,自上而下进行调度,但是其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置。(生产不常用)

动态算法

  • roundrobin
    基于权重的轮询动态调度算法,支持权重的运行时调整,不完全等于lvs中的rr轮训模式,HAProxy中的roundrobin支持慢启动(新加的服务器会逐渐增加转发数),其每个后端backend中最多支持4095个real server,roundrobin为默认调度算法,且支持对real server权重动态调整。
  • leastconn
    加权的最少连接的动态,支持权重的运行时调整和慢启动,即当前后端服务器连接最少的优先调度(新客户端连接),比较适合长连接的场景使用,比如MySQL等场景。

其他算法

source

  源地址hash,基于用户源地址hash并将请求转发到后端服务器,默认为静态即取模方式,但是可以通过hash-type支持的选项更改,后续同一个源地址请求将被转发至同一个后端web服务器,比较适用于session保持/缓存业务等场景。
  源地址有两种转发客户端请求到后端服务器的服务器选取计算方式,分别是取模法和一致性hash

  • map-base取模法
      map-based:取模法,基于服务器总权重的hash数组取模,该hash是静态的即不支持在线调整权重,不支持慢启动,其对后端服务器调度均衡,缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因权重发生变化而导致调度结果整体改变。
      所谓取模运算,就是计算两个数相除之后的余数,10%7=3, 7%4=3,(2^32-1)%(1+1+2)
      取模法示意图:
    在这里插入图片描述取模法配置示例:

    1
    2
    3
    4
    5
    6
    7
    listen web_host
    bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
    mode tcp
    log global
    balance source
    server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
    server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5
  • 一致性hash
      一致性哈希,该hash是动态的,支持在线调整权重,支持慢启动,优点在于当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动,hash(o)mod n 。
      Hash对象到后端服务器的映射关系:
    在这里插入图片描述  一致性hash后端服务器在线与离线的调度方式示意图:
    在这里插入图片描述
      一致性hash配置示例:

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

  基于对用户请求的uri做hash并将请求转发到后端指定服务器,也可以通过map-based和consistent定义使用取模法还是一致性hash。
  uri 取模法配置示例:

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

  uri 一致性hash配置示例:

1
2
3
4
5
6
7
8
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
url_param

  url_param对用户请求的url中的 params 部分中的参数name作hash计算,并由服务器总权重相除以后派发至某挑出的服务器;通常用于追踪用户,以确保来自同一个用户的请求始终发往同一个real server

1
2
3
4
假设url = http://www.example.com/foo/bar/index.php?k1=v1&k2=v2
则:
host = "www.example.com"
url_param = "k1=v1&k2=v2"

  url_param取模法配置示例:

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

  url_param一致性hash配置示例:

1
2
3
4
5
6
7
8
listen web_host
bind 192.168.7.101:80,:8801-8810,192.168.7.101:9001-9010
mode http
log global
balance url_param name,age #支持对单个及多个url_param 值hash
hash-type consistent
server web1 192.168.7.103:80 weight 1 check inter 3000 fall 2 rise 5
server web2 192.168.7.104:80 weight 1 check inter 3000 fall 2 rise 5
hdr

  针对用户每个http头部(header)请求中的指定信息做hash,此处由 name 指定的http首部将会被取出并做hash计算,然后由服务器总权重相除以后派发至某挑出的服务器,假如无有效的值,则会使用默认的轮询调度。
  hdr取模法配置示例:

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

一致性hash配置示例:

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

  rdp-cookie对远程桌面的负载,使用cookie保持会话
  rdp-cookie取模法配置示例:

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

  rdp-cookie一致性hash配置示例:

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

  基于iptables实现:

1
2
3
net.ipv4.ip_forward = 1
# iptables -t nat -A PREROUTING -d 192.168.7.101 -p tcp --dport 3389 -j DNAT --todestination 172.18.139.20:3389
# iptables -t nat -A POSTROUTING -s 192.168.0.0/21 -j SNAT --to-source 192.168.7.101
random

  在1.9版本开始增加一个叫做random的负载平衡算法,其基于一个随机数作为一致性hash的key,随机负载平衡对于大型服务器场或经常添加或删除服务器非常有用,因为它可以避免在这种情况下由roundrobin或leastconn导致的锤击效应。
  random配置实例:

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

算法总结

1
2
3
4
5
6
7
8
9
10
static-rr--------->tcp/http 静态
first------------->tcp/http 静态
roundrobin-------->tcp/http 动态
leastconn--------->tcp/http 动态
random------------>tcp/http 动态
source------------>tcp/http
Uri--------------->http
url_param--------->http 取决于hash_type是否consistent
hdr--------------->http
rdp-cookie-------->tcp
1
2
3
4
5
6
7
8
9
10
first #使用较少
static-rr #做了session共享的web集群
roundrobin
random
leastconn #数据库
source #基于客户端公网IP的会话保持
Uri--------------->http #缓存服务器,CDN服务商,蓝汛、百度、阿里云、腾讯
url_param--------->http
hdr #基于客户端请求报文头部做下一步处理
rdp-cookie #很少使用

  详细可参见官方文档:https://cbonte.github.io/haproxy-dconv/2.0/configuration.html#4

haproxy工作模式

tcp:四层负载

  在四层负载设备中,把client发送的报文目标地址(原来是负载均衡设备的IP地址),根据均衡设备设置的选择web服务器的规则选择对应的web服务器IP地址,这样client就可以直接跟此服务器建立TCP连接并发送数据。

四层工作模式的IP透传:

  haproxy配置中在后端服务器定义中加入关键字send-proxy(注意不要加在check关键字属性的中间了),并重启服务。
  在后端nginx服务器配置中监听端口处也加上协议名proxy_protocol,并修改日志格式,在开头加入变量$proxy_protocol_addr,重启服务后即可在日志中看到访问的源地址。
  send-proxy是haproxy后端设置的关键字,写错会报错,可以用来启用代理协议Proxy protocol。Proxy protocol是HAProxy的作者Willy Tarreau于2010年开发和设计的一个Internet协议,通过为tcp添加一个很小的头信息,来方便的传递客户端信息(协议栈、源IP、目的IP、源端口、目的端口等),在网络情况复杂又需要获取用户真实IP时非常有用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
haproxy 配置:
listen web_prot_http_nodes
bind 172.18.32.249:80
mode tcp
balance roundrobin
server web1 192.168.32.81:80 send-proxy check inter 3000 fall 3 rise 5

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

server {
listen 80 proxy_protocol;
#listen 80;
内核参数优化

  haproxy在做四层负载时,如果要监听bind由keepalived生成的虚拟IP(VIP)时,需要修改内核参数,支持监听非本机IP,否则监听VIP的80端口时会导致haproxy服务无法启动。。
  vim /etc/sysctl.conf

1
net.ipv4.ip_nonlocal_bind = 1

  如果多网卡,且VIP与后端VIP不在一个网段,还需要加上地址转发参数。

1
net.ipv4.ip_forward = 1

  然后sysctl -p使配置文件生效。

1
2
3
4
[root@CentOS8 ~]#sysctl -p
net.ipv4.ip_nonlocal_bind = 1
net.ipv4.ip_forward = 1
[root@CentOS8 ~]#

  当然,也可以将haproxy改为监听0.0.0.0:80,表示监听本机所有网卡的IP的80端口,当keepalived的VIP漂到本机是,自然也可以被haproxy监听,没有时也不影响启动。不过这样的话,haproxy只能对一个项目集群做负载均衡了,而我们实际生产中,都是同时代理多个服务项目集群的转发,需通过bind不同IP的80/443端口来实现,如果直接一个服务bind0.0.0.0:80,占用了所有的80/443端口,显然就没法和其他项目共存了。
  所以我们建议在四层负载工作模式下,不要监听0.0.0.0:80,而是监听指定的VIP。

http:七层代理

  七层负载均衡服务器起了一个反向代理服务器的作用,服务器建立一次TCP连接要三次握手,而client要访问webserver要先与七层负载设备进行三次握手后建立TCP连接,把要访问的报文信息发送给七层负载均衡;然后七层负载均衡再根据设置的均衡规则选择特定的webserver,然后通过三次握手与此台webserver建立TCP连接,然后webserver把需要的数据发送给七层负载均衡设备,负载均衡设备再把数据发送给client;所以,七层负载均衡设备起到了代理服务器的作用。

七层工作模式的IP透传:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
haproxy 配置:
defaults
option forwardfor
或者:
option forwardfor header X-Forwarded-xxx #自定义传递IP参数,后端web服务器写X-Forwardedxxx
#如果写option forwardfor则后端服务器web格式为X-Forwarded-For
listen配置:
listen web_host
bind 192.168.7.101:80
mode http
log global
balance random
server web1 192.168.32.81:80 weight 1 check inter 3000 fall 2 rise 5
server web2 192.168.32.82:80 weight 1 check inter 3000 fall 2 rise 5

  配置web服务器,记录负载均衡透传的客户端IP地址

1
2
3
4
5
6
7
8
9
#apache 配置:
LogFormat "%{X-Forwarded-For}i %a %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{UserAgent}i\"" combined
#tomcat 配置:
pattern='%{X-Forwarded-For}i %l %T %t "%r" %s %b "%{UserAgent}i"'/>
#nginx 日志格式:
http {
log_format main '"$http_x_forwarded_For" - $remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" ';

haproxy功能实现

  初步调整好haproxy的配置文件之后,启动haproxy服务,就已经可以对后端服务器进行代理来实现负载均衡了,不过很多情况下我们需要对后端服务器进行动态操作,例如修改某些主机的负载权重,对某些主机上线或下线等等,而这时,再不影响业务正常访问的情况下,对haproxy动态操作方式一般有两种:在图形界面status状态页下操作,以及使用socat命令行工具通过socket通信。

图形界面

  想实现在status界面拥有修改权限,需在配置文件中加入选项stats admin if TRUE。注意,TRUE要大写,否则服务起不来会报错parsing [/etc/haproxy/haproxy.cfg:52] : error detected while parsing a 'stats admin' rule : no such ACL : 'true'.
  最终如下面所示

1
2
3
4
5
6
7
8
listen stats
mode http
bind 0.0.0.0:9999
stats enable
log global
stats uri /proxy_status
stats auth haadmin:hapasswd
stats admin if TRUE

  这是再刷新status界面,就可以看到界面已经发生了变化
在这里插入图片描述
在这里插入图片描述
  就可以对选择的主机进行操作了。

命令行方式

  这是通过直接与haproxy的socekt通信,socket路径就是配置文件中指定的socket路径了,只支持本地通信。而且这需要借主socat的工具,需要先进行安装socat工具。

1
yum install socat

  用echo信息的方式通过管道传递给socat工具指定haproxy的socket,就可以发送与接收haproxy的信息了。
  查看haproxy工作的详细信息

1
echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock1

  查看haproxy控制命令

1
echo "help" | socat stdio /var/lib/haproxy/haproxy.sock1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
help           : this message
prompt : toggle interactive mode with prompt
quit : disconnect
show tls-keys [id|*]: show tls keys references or dump tls ticket keys when id specified
set ssl tls-key [id|keyfile] &lttlskey&gt: set the next TLS key for the &ltid&gt or &ltkeyfile&gt listener to &lttlskey&gt
show sess [id] : report the list of current sessions or dump this session
shutdown session : kill a specific session
shutdown sessions server : kill sessions on a server
clear counters : clear max statistics counters (add 'all' for all counters)
show info : report information about the running process [json|typed]
show stat : report counters for each proxy and server [json|typed]
show schema json : report schema used for stats
disable agent : disable agent checks (use 'set server' instead)
disable health : disable health checks (use 'set server' instead)
disable server : disable a server for maintenance (use 'set server' instead)
enable agent : enable agent checks (use 'set server' instead)
enable health : enable health checks (use 'set server' instead)
enable server : enable a disabled server (use 'set server' instead)
set maxconn server : change a server's maxconn setting
set server : change a server's state, weight or address
get weight : report a server's current weight
set weight : change a server's weight (deprecated)
show resolvers [id]: dumps counters from all resolvers section and associated name servers
clear table : remove an entry from a table
set table [id] : update or create a table entry's data
show table [id]: report table usage stats or dump this table's contents
show peers [peers section]: dump some information about all the peers or this peers section
disable frontend : temporarily disable specific frontend
enable frontend : re-enable specific frontend
set maxconn frontend : change a frontend's maxconn setting
show servers state [id]: dump volatile server information (for backend &ltid&gt)
show backend : list backends in the current running config
shutdown frontend : stop a specific frontend
set dynamic-cookie-key backend : change a backend secret key for dynamic cookies
enable dynamic-cookie backend : enable dynamic cookies on a specific backend
disable dynamic-cookie backend : disable dynamic cookies on a specific backend
show errors : report last request and response errors for each proxy
set maxconn global : change the per-process maxconn setting
set rate-limit : change a rate limiting value
set severity-output [none|number|string] : set presence of severity level in feedback information
set timeout : change a timeout setting
show env [var] : dump environment variables known to the process
show cli sockets : dump list of cli sockets
show cli level : display the level of the current CLI session
show fd [num] : dump list of file descriptors in use
show activity : show per-thread activity stats (for support/developers)
operator : lower the level of the current CLI session to operator
user : lower the level of the current CLI session to user
show startup-logs : report logs emitted during HAProxy startup
show cache : show cache status
add acl : add acl entry
clear acl &ltid&gt : clear the content of this acl
del acl : delete acl entry
get acl : report the patterns matching a sample for an ACL
show acl [id] : report available acls or dump an acl's contents
add map : add map entry
clear map &ltid&gt : clear the content of this map
del map : delete map entry
get map : report the keys and values matching a sample for a map
set map : modify map entry
show map [id] : report available maps or dump a map's contents
show pools : report information about the memory pools usage
show profiling : show CPU profiling options
set profiling : enable/disable CPU profiling
show threads : show some threads debugging information

  查看线程1工作下的web_host集群中web1主机的权重

1
2
3
4
[root@CentOS8 ~]#echo "get weight web_host/web1" | socat stdio /var/lib/haproxy/haproxy.sock1
1 (initial 1)

[root@CentOS8 ~]#

  设置线程2工作下的web_host集群中web1主机的权重为2。设置时,不回应信息,说明设置成功。

1
2
3
[root@CentOS8 ~]#echo "set weight web_host/web1 2" | socat stdio /var/lib/haproxy/haproxy.sock2

[root@CentOS8 ~]#

  需要注意的一点就是,多线程工作模式下,每个线程是独立的,设置1线程的权重,在其他线程上并不生效。这就意味着,如果想将某个服务器下线的话,需要在每个线程上都分别下线,上线是,也需要在每个线程中enable server。可以用脚本写一个循环来实现。


一个低调的男人