一、Haproxy简介

1、Haproxy的介绍

 HAProxy是法国开发者Willy Tarreau开发的一个开源软件,是一款具备高并发、高性能的TCP和HTTP负载均衡器,支持基于cookie的持久性,自动故障切换,支持正则表达式及web状态统计。

2、Haproxy的功能

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

二、Haproxy安装

1、编译安装过程

 (1) 准备源码包,可到官网下载 https://www.haproxy.org

[root@centos7 ~]# ll haproxy-1.8.20.tar.gz 
-rw-r--r-- 1 root root 2083917 Jan 10 20:39 haproxy-1.8.20.tar.gz

 (2) 安装相应依赖包

[root@centos7 ~]# yum install -y gcc gcc-c++ pcre pcre-devel openssl openssl-devel systemd-devel

 (3) 解压源码包,并进行编译

[root@centos7 ~]# tar -zxvf haproxy-1.8.20.tar.gz 
[root@centos7 ~]# cd haproxy-1.8.20/
[root@centos7 haproxy-1.8.20]# 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
[root@centos7 haproxy-1.8.20]# make install PREFIX=/usr/local/haproxy
[root@centos7 haproxy-1.8.20]# cp haproxy /usr/sbin/

 (4) 创建启动脚本

[root@centos7 haproxy-1.8.20]# vim /usr/lib/systemd/system/haproxy.service

[Unit]
Description=HAProxy Load Balancer
After=syslog.target network.target

[Service]
ExecStartPre=/usr/sbin/haproxy -f /etc/haproxy/haproxy.cfg -c -q
ExecStart=/usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /usr/local/haproxy/run/haproxy.pid
ExecReload=/bin/kill -USR2 $MAINPID

[Install]
WantedBy=multi-user.target

 (5) 创建用户与相关目录以及配置文件

[root@centos7 haproxy-1.8.20]# useradd -r -s /sbin/nologin haproxy
[root@centos7 haproxy-1.8.20]# mkdir /etc/haproxy
[root@centos7 haproxy-1.8.20]# mkdir /usr/local/haproxy/run
[root@centos7 haproxy-1.8.20]# mkdir /var/lib/haproxy
[root@centos7 haproxy-1.8.20]# chown -R haproxy:haproxy /var/lib/haproxy/
[root@centos7 haproxy-1.8.20]# vim /etc/haproxy/haproxy.cfg

haproxy需要用户认证 haproxy proxy protocol_centos

haproxy需要用户认证 haproxy proxy protocol_后端服务_02

[root@centos7 haproxy-1.8.20]# cat /etc/haproxy/haproxy.cfg
global
maxconn 100000
chroot /usr/local/haproxy
#stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin
#uid 981
#gid 981
user haproxy
group haproxy
daemon
#nbproc 4
#cpu-map 1 0
#cpu-map 2 1
#cpu-map 3 2
#cpu-map 4 3
pidfile /usr/local/haproxy/run/haproxy.pid
log 127.0.0.1 local3 info

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 0.0.0.0:80
 mode http
 log global
 server web1  127.0.0.1:8080  check inter 3000 fall 2 rise 5

配置文件

 (6) 启动haproxy服务

[root@centos7 haproxy-1.8.20]# systemctl start haproxy
[root@centos7 haproxy-1.8.20]# ps -ef|grep haproxy
root     58693     1  0 23:29 ?        00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /usr/local/haproxy/run/haproxy.pid
haproxy  58697 58693  0 23:29 ?        00:00:00 /usr/sbin/haproxy -Ws -f /etc/haproxy/haproxy.cfg -p /usr/local/haproxy/run/haproxy.pid
root     58708  6403  0 23:29 pts/0    00:00:00 grep --color=auto haproxy

三、Haproxy配置项解析

1、global 全局配置段

• chroot    #锁定运行目录
• deamon    #以守护进程运行
• stats socket /var/lib/haproxy/haproxy.sock mode 600 level admin    #socket文件
• user, group, uid, gid    #运行haproxy的用户身份
• nbproc    #开启的haproxy进程数,与CPU保持一致
• nbthread    #指定每个haproxy进程开启的线程数,默认为每个进程一个线程
• cpu-map 1 0    #绑定haproxy 进程至指定CPU
• maxconn    #每个haproxy进程的最大并发连接数
• maxsslconn    #SSL每个haproxy进程ssl最大连接数
• maxconnrate    #每个进程每秒最大连接数
• spread-checks    #后端server状态check随机提前或延迟百分比时间,建议2-5(20%-50%)之间
• pidfile    #指定pid文件路径
• log 127.0.0.1 local3 info    #定义全局的syslog服务器;最多可以定义两个

2、proxies 代理配置段

 defaults [<name>]  #默认配置项,针对以下的frontend、backend和listen生效,可以多个name

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

 frontend <name>  #前端servername,类似于Nginx的一个虚拟主机server

• bind [<address>]:<port_range> [, ...] [param*]    #指定HAProxy的监听地址,可以是IPV4或IPV6,可以同时监听多个IP或端口,可同时用于listen字段中
• mode http/tcp    #指定负载协议类型
• use_backend backend_name    #调用的后端服务器组名称

 示例:

frontend WEB_PORT
  bind 192.168.27.7:80
  mode tcp
  use_backend backend_name

 backend <name>  #后端服务器组,等于Nginx的upstream

• mode http/tcp    #指定负载协议类型
• option    #配置选项,可加httpchk,smtpchk, mysql-check, pgsql-check,ssl-hello-chk等方法,可用于实现更多应用层检测功能
• server    #定义后端real server,后可接 check 对指定real进行健康状态检查,默认不开启
check    #对指定real server进行健康状态检查,默认不开启
• 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.xxx.com/    #将请求临时重定向至其它URL,只适用于http模式
• mbacklog axconn <maxconn>    #当前后端server的最大并发连接数
• <backlog>    #当server的连接数达到上限后的后援队列长度

haproxy需要用户认证 haproxy proxy protocol_centos

haproxy需要用户认证 haproxy proxy protocol_后端服务_02

frontend WEB_PORT_80
  bind 192.168.27.7:80
  mode http
  use_backend web_prot_http_nodes

backend web_prot_http_nodes
  mode http
  option forwardfor
  server web1 192.168.27.17:8080 weight 1 check inter 3000 fall 3 rise 5
  server web2 192.168.27.27:8080 weight 1 check inter 3000 fall 3 rise 5
  server web2 192.168.27.37:8080 check inter 3000 fall 3 rise 5 backup

frontend和backend配置案例

 listen <name>  #将 frontend 和 backend 合并在一起配置

listen WEB_PORT_80
  bind 192.168.27.7:80
  mode http
  option forwardfor
  server web1 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server web2 192.168.27.27:8080 check inter 3000 fall 3 rise 5

 注:name字段只能使用 " - "、" _ "、" . "、" : ",并且严格区分大小写

四、Haproxy的调度算法

 通过 balance 指明对后端服务器的调度算法,配置在listen或backend。调度算法有以下几种:

1、first

 根据服务器在列表中的位置,自上而下进行调度,但是其只会当第一台服务器的连接数达到上限,新请求才会分配给下一台服务,因此会忽略服务器的权重设置;

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #可以为tcp或http
  balance first
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

2、static-rr

 基于权重的轮询静态调度算法,不支持权重的运行时调整及后端服务器慢启动,其后端主机数量没有限制;

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #可以为tcp或http
  balance static-rr
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

3、roundrobin

 基于权重的轮询动态调度算法,支持权重的运行时调整,不等于lvs 的 rr,支持慢启动即新加的服务器会逐渐增加转发数,每个后端backend中最多支持4095个server,此为默认调度算法;

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #可以为tcp或http
  balance rountrobin
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

4、leastconn

 加权的最少连接动态调度算法,支持权重的运行时调整和慢启动,即当前后端服务器连接最少的优先调度,比较适合长连接的场景使用,比如MySQL等场景;

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #可以为tcp或http
  balance leastconn
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

5、source

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

  •  map-based:取模法,基于服务器权重的hash数组取模,该hash是静态的即不支持在线调整权重,不支持慢启动,其对后端服务器调度均衡,缺点是当服务器的总权重发生变化时,即有服务器上线或下线,都会因权重发生变化而导致调度结果整体改变;

  •  consistent:一致性哈希,该hash是动态的,支持在线调整权重,支持慢启动,优点在于当服务器的总权重发生变化时,对调度结果影响是局部的,不会引起大的变动;

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #可以为tcp或http
  balance source
  hash-type consistent
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

6、uri

 基于对用户请求的uri做hash并将请求转发到后端指定服务器;

  • map-based:取模法

  • consistent:一致性哈希

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #只能是http
  balance uri
  hash-type consistent
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

7、url_param

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

 假设url=http://www.xx.com/index.php?k1=v1&k2=v2,则url_param="k1=v1&k2=v2";

  • map-based:取模法

  • consistent:一致性哈希

#假设url=http://192.168.27.7/index.html?name=tom
listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #只能是http
  balance url_param
  hash-type consistent
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

8、hdr

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

  • map-based:取模法

  • consistent:一致性哈希

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http  #只能是http
  balance hdr(User_Agent)
  hash-type consistent
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

9、rdp-cookie

 对远程桌面的负载,使用cookie保持会话;

  • map-based:取模法

  • consistent:一致性哈希

listen RDP
  bind 192.168.27.7:3389
  mode tcp  #只能是tcp
  balance rdp_cookie
  hash-type consistent
  option forwardfor
  server 192.168.27.17 192.168.27.17:3389 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:3389 check inter 3000 fall 3 rise 5

五、部分配置实例

1、基于cookie实现的session保持

 cookie <value>:为当前server指定cookie值,实现基于cookie的会话黏性

 cookie <name> [ rewrite | insert | prefix ] [ indirect ] [ nocache ] [ postonly ] [ preserve ] [ httponly ] [ secure ] [ domain <domain> ]* [ maxidle <idle> ] [ maxlife <life> ]

  <name>:cookie名称,用于实现持久连接
   rewrite:重写
   insert:插入
   prefix:前缀
   nocache:当client和hapoxy之间有缓存时,不缓存cookie

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http
  cookie SERVER-COOKIE insert indirect nocache
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 cookie web1 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 cookie web2 check inter 3000 fall 3 rise 5

2、Haproxy状态页实现

• stats enable    #基于默认的参数启用stats page
• stats hide-version    # 隐藏版本
• 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 refresh 5s    #定义页面自动刷新间隔时间
• stats admin { if | unless } <cond>    #启用stats page中的管理功能
listen stats
  bind 192.168.27.7:9009
  stats enable
  stats hide-version 
  stats uri /haproxy-status
  stats realm HAPorxy\ Stats\ Page
  stats auth haadmin:123456
  stats auth admin:123456    #可以有多个    
  stats refresh 30s
  stats admin if TRUE

3、Haproxy日志配置

在haproxy配置文件default配置项定义:
    log 127.0.0.1 local{1-7} info #基于syslog记录日志到指定设备,级别有(err、warning、info、debug)

配置rsyslog: 
    $ModLoad imudp
    $UDPServerRun 514
     local3.*     /var/log/haproxy.log

配置HAProxy:
listen web_port
    bind 127.0.0.1:80
    mode http
    log global
    option tcplog   #允许记录tcp连接的状态和时间
    server web1 127.0.0.1:8080 check inter 3000 fall 2 rise 5

重启rsyslog服务与haproxy服务

4、三种后端服务器的监测

 (1) 基于四层传输端口监测

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http
  log global
  option forwardfor
  server 192.168.27.17 192.168.27.17:8080 check port 9000 addr 172.168.27.17 inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check port 9000 addr 172.168.27.27 inter 3000 fall 3 rise 5

 (2) 基于指定URI 做状态监测

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http
  log global
  option forwardfor
  option httpchk GET /wp-includes/js/jquery/jquery.js?ver=1.12.4 HTTP/1.0 #基于指定URL
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

 (3) 基于指定URI的request请求头部内容做状态监测

listen web_prot_http_nodes
  bind 192.168.27.7:80
  mode http
  log global
  option forwardfor
  option httpchk HEAD /wp-includes/js/jquery/jquery.js?ver=1.12.4 HTTP/1.0\r\nHost:\ 192.168.27.7    #通过request获取的头部信息进行匹配进行健康检测
  server 192.168.27.17 192.168.27.17:8080 check inter 3000 fall 3 rise 5
  server 192.168.27.27 192.168.27.27:8080 check inter 3000 fall 3 rise 5

5、自定义错误页面

• errorfile 500 /usr/local/haproxy/html/500.html    #自定义错误页面跳转
• errorloc 503 http://192.168.7.103/error_page/503.html    #自定义错误页面跳转

6、基于acl+文件后缀实现动静分离

listen web_port
  bind 192.168.27.7:80
  mode http
  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
  default_backend default_host

backend default_host
  mode http
  server web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5

backend php_server_host
  mode http
  server web1 192.168.27.27:8080 check inter 2000 fall 3 rise 5

backend image_server_host
  mode http
  server web1 192.168.27.37:8080 check inter 2000 fall 3 rise 5

7、acl匹配访问路径

listen web_port
  bind 192.168.27.7:80
  mode http
  acl static_path path_beg -i /static /images /javascript
  use_backend static_path_host if static_path
  default_backend default_host

backend default_host
  mode http
  server web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5

backend static_path_host
  mode http
  server web1 192.168.27.27:8080 check inter 2000 fall 3 rise 5

8、基于http策略的访问控制

listen web_port
  bind 192.168.27.7:80
  mode http
  acl badguy_deny src 192.168.4.1
  http-request deny if badguy_deny
  http-request allow
  default_backend default_host

backend default_host
  mode http
  server web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5

backend static_path_host
  mode http
  server web1 192.168.27.27:8080 check inter 2000 fall 3 rise 5

9、https的配置

#web server http
frontend web_server-http
  bind 192.168.27.7:80
  mode http
  redirect scheme https if !{ ssl_fc }        #把80端口的请求重向定443
  use_backend web_host
  
#web server https
frontend web_server-https
  bind 192.168.27.7:443 ssl crt /usr/local/haproxy/certs/haproxy.pem  #crt后的证书文件为PEM格式,且同时包含证书和所有私钥
  mode http
  use_backend web_host

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 web1 192.168.27.17:8080 check inter 2000 fall 3 rise 5
  server web2 192.168.27.27:8080 check inter 2000 fall 3 rise 5

haproxy需要用户认证 haproxy proxy protocol_centos

haproxy需要用户认证 haproxy proxy protocol_后端服务_02

# mkdir /usr/local/haproxy/certs
# cd /usr/local/haproxy/certs
# openssl genrsa -out haproxy.key 2048
# openssl req -new -x509 -key haproxy.key -out haproxy.crt -subj "/CN=www.xxx.com"
# cat haproxy.key haproxy.crt > haproxy.pem    #将私钥和证书导入到一个文件中
# openssl x509 -in haproxy.pem -noout -text    #查看证书

https证书制作

10、Haproxy后端服务器的动态上下线

# yum install socat 
# echo "show info" | socat stdio /var/lib/haproxy/haproxy.sock
# echo "get weight web_host/192.168.7.101" | socat stdio /var/lib/haproxy/haproxy.sock 
# echo "disable server web_host/192.168.7.101" | socat stdio /var/lib/haproxy/haproxy.sock 
# echo "enable server web_host/192.168.7.101" | socat stdio /var/lib/haproxy/haproxy.sock