1. 关于haproxy

1.1 简介

(1)HAProxy 是一款提供高可用性、负载均衡以及基于TCP(第四层)和HTTP(第七层)应用的代理软件,支持虚拟主机,它是免费、快速并且可靠的一种解决方案。 HAProxy特别适用于那些负载特大的web站点,这些站点通常又需要会话保持或七层处理。HAProxy运行在时下的硬件上,完全可以支持数以万计的 并发连接。并且它的运行模式使得它可以很简单安全的整合进您当前的架构中, 同时可以保护你的web服务器不被暴露到网络上。

(2)HAProxy 实现了一种事件驱动、单一进程模型,此模型支持非常大的并发连接数。多进程或多线程模型受内存限制 、系统调度器限制以及无处不在的锁限制,很少能处理数千并发连接。事件驱动模型因为在有更好的资源和时间管理的用户端(User-Space) 实现所有这些任务,所以没有这些问题。此模型的弊端是,在多核系统上,这些程序通常扩展性较差。这就是为什么他们必须进行优化以 使每个CPU时间片(Cycle)做更多的工作。

(3)HAProxy 支持连接拒绝 : 因为维护一个连接的打开的开销是很低的,有时我们很需要限制攻击蠕虫(attack bots),也就是说限制它们的连接打开从而限制它们的危害。 这个已经为一个陷于小型DDoS攻击的网站开发了而且已经拯救了很多站点,这个优点也是其它负载均衡器没有的。

(4)HAProxy 支持全透明代理(已具备硬件防火墙的典型特点): 可以用客户端IP地址或者任何其他地址来连接后端服务器. 这个特性仅在Linux 2.4/2.6内核打了cttproxy补丁后才可以使用. 这个特性也使得为某特殊服务器处理部分流量同时又不修改服务器的地址成为可能。

1.2 调度算法

HAProxy在balance中定义

格式为 balance <algorithm> [ <arguments> ]
  • roundrobin 根据服务器权重轮询的算法,可以自定义权重,它支持慢启动,并能在运行时修改权重,所以是一种动态算法。最多支持4095台后端主机。
  • .static-rr 与roundrobin类似,static-rr也是一种轮询算法,但它是静态的,对后端主机数量无限制。
  • leastconn 最小连接数算法,一种可以根据后端主机连接数情况进行调度的动态算法,支持慢启动和运行时调整,可将新的请求调度至连接数较少的后端主机。与LVS中lc算法类似。
  • first 根据服务器标识顺序选择服务器,当服务器承载的连接数达到maxconn的值后便将新情求调度至下一台服务器。此算法只在一些特殊场景下使用。
  • source 对请求的源IP地址进行hash处理,根据hash运算处理结果调度至后端服务器。可使固定IP的请求始终调度至统一服务器。
  • uri 根据请求的uri进行hash处理并调度之后端主机。
  • url_param 将URL的参数进行判断并进行hash计算,参数可以自定义,任何的URL参数都可以。
  • hdr 根据请求中的HTTP报文首部的值进行hash计算并调度。name可以是GET、USERAGENT等首部名。

1.3 工作模式

  • mode tcp模式:该模式下,在客户端和服务器之间将建立一个全双工的连接,且不会对7层的报文做任何处理的简单模式。四层代理
  • mode http模式(一般使用):该模式下,客户端请求在转发给后端服务器之前会被深度分析,七层代理
  • mode health模式 : 仅做健康检查

注意:当实现内容交换时,前端和后端必须工作于同一种模式(一般都是HTTP模式),否则将无法启动实例。
工作模式可通过mode参数在default,frontend,listen,backend中实现定义。
两种模块分别是:通过mod_tcp来限定反代模式和mod_http来实现负载均衡

2. 部署和验证

2.1 服务器规划

主机

IP地址

角色

系统版本

host1

192.168.1.127

haproxy1/keepalived

7

host2

192.168.1.115

haproxy2/keepalived

7

host3

192.168.1.125

webserver11

7

host4

192.168.1.116

webserver2

7

2.2 源码安装haproxy

源码安装和配置部分,host1和host2相同,步骤如下

5  yum -y install pcre-devel bzip2-devel gcc gcc-c++
    6  tar -zxf haproxy-1.4.24.tar.gz 
    7  cd haproxy-1.4.24/
    8  uname -r
    9  make TARGET=linux31
   10  make install
   11  ln -s /usr/local/sbin/haproxy /usr/sbin
   12  mkdir /etc/haproxy
   13  cp examples/haproxy.cfg /etc/haproxy/
   14  cp examples/haproxy.init /etc/init.d/haproxy
   15  chmod +x /etc/init.d/haproxy

编辑haproxy配置文件内容

# vim /etc/haproxy/haproxy.cfg
注释掉chroot这一行,这行为工作目录,我们没有
redispatch这一行书写不规范,前边应该加上option
下边的listen全都删除掉,自己写,如下
listen webcluster 0.0.0.0:80
option httpchk GET /index.html
balance roundrobin
server inst1 192.168.1.125:80 check inter 2000 fall 3
server inst2 192.168.1.116:80 check inter 2000 fall 3

listen stats  #状态监控
        bind 0.0.0.0:1080
        mode http
        option httplog
        maxconn 10
        stats refresh 30s
        stats uri /stats
        stats realm XingCloud\ Haproxy  #登陆时候的提示信息 加上\才会显示后边的单词,否则只显示第一个单词
        stats auth admin:admin #用这个账号登录,可以自己设置
        stats auth Frank:Frank



# /etc/init.d/haproxy check  进行启动前的检查,发现启动脚本有一点小bug
/etc/init.d/haproxy: line 26: [: =: unary operator expected
Configuration file is valid

修改启动脚本:
vim /etc/init.d/haproxy  修改26行
把${NETWORKING} 加上双引号

启动haproxy:
/etc/init.d/haproxy start

后端web节点编辑简单web页面:
第一个: <h1>hello world</h1>
第二个:<h1>hello work</h1>

访问本机IP进行测试:
[root@localhost haproxy-1.4.24]# curl 192.168.1.115
<h1>hello world</h1>
[root@localhost haproxy-1.4.24]# curl 192.168.1.115
<h1>hello work</h1>

如果换成最小链接的调度算法,测试结果如下:
[root@localhost haproxy-1.4.24]# curl 192.168.1.115
<h1>hello work</h1>
[root@localhost haproxy-1.4.24]# curl 192.168.1.115
<h1>hello world</h1>

在两台haproxy上搭建keepalived服务

59  yum -y install popt-devel kernel-devel openssl-devel
   60  tar -zxf keepalived-1.2.13.tar.gz 
   61  cd keepalived-1.2.13/
   62  ./configure --prefix=/
   63  make
   64  make install
   65  cp /etc/keepalived/keepalived.conf{,.bak}

host1 修改keepalived配置文件
# vim /etc/keepalived/keepalived.conf
在vrrp_instance VI_1里吧网卡名字改为本机网卡名字 ens33
在下边的virtual_ipaddress里边把三个虚拟IP都删除掉,写上我们自己设定的192.168.1.188

其他不变,启动keepalived
[root@localhost keepalived-1.2.13]# /etc/init.d/keepalived start
Reloading systemd:                                         [  OK  ]
Starting keepalived (via systemctl):                       [  OK  ]

host2 修改keepalived配置文件
# vim /etc/keepalived/keepalived.conf
状态status改为BACKUP
在vrrp_instance VI_1里吧网卡名字改为本机网卡名字 ens33
优先级priority改为90
下边的虚拟IP跟host1一样


在host1上查看IP地址,多了一个192.168.1.188
宕掉host1的网卡,查看host2的IP,发现虚拟IP漂移到host2上
当host1网卡恢复后,虚拟IP又回到host1上,这样证明keepalived搭建完成

客户机访问虚拟IP,获得后端服务内容,并且可以按照既定的调度算法出现轮询

[root@localhost ~]# curl 192.168.1.188
<h1>hello world</h1>
[root@localhost ~]# curl 192.168.1.188
<h1>hello work</h1>

2.3 haproxy配置文件详解

global   # 全局参数的设置
    log 127.0.0.1 local0 info
    # log语法:log <address_1>[max_level_1] # 全局的日志配置,使用log关键字,指定使用127.0.0.1上的syslog服务中的local0日志设备,记录日志等级为info的日志
    user haproxy
    group haproxy
    # 设置运行haproxy的用户和组,也可使用uid,gid关键字替代之
    daemon
    # 以守护进程的方式运行
    nbproc 16
    # 设置haproxy启动时的进程数,根据官方文档的解释,我将其理解为:该值的设置应该和服务器的CPU核心数一致,即常见的2颗8核心CPU的服务器,即共有16核心,则可以将其值设置为:<=16 ,创建多个进程数,可以减少每个进程的任务队列,但是过多的进程数也可能会导致进程的崩溃。这里我设置为16
    maxconn 4096
    # 定义每个haproxy进程的最大连接数 ,由于每个连接包括一个客户端和一个服务器端,所以单个进程的TCP会话最大数目将是该值的两倍。
 #chroot /usr/share/haproxy #haproxy工作目录,没有,注释掉
    #ulimit -n 65536
    # 设置最大打开的文件描述符数,在1.4的官方文档中提示,该值会自动计算,所以不建议进行设置
    pidfile /var/run/haproxy.pid
    # 定义haproxy的pid 
defaults # 默认部分的定义
    mode http
    # mode语法:mode {http|tcp|health} 。http是七层模式,tcp是四层模式,health是健康检测,返回OK
    log 127.0.0.1 local3 err
    # 使用127.0.0.1上的syslog服务的local3设备记录错误信息
    retries 3
    # 定义连接后端服务器的失败重连次数,连接失败次数超过此值后将会将对应后端服务器标记为不可用
    option httplog
    # 启用日志记录HTTP请求,默认haproxy日志记录是不记录HTTP请求的,只记录“时间[Jan 5 13:23:46] 日志服务器[127.0.0.1] 实例名已经pid[haproxy[25218]] 信息[Proxy http_80_in stopped.]”,日志格式很简单。
    option redispatch
    # 当使用了cookie时,haproxy将会将其请求的后端服务器的serverID插入到cookie中,以保证会话的SESSION持久性;而此时,如果后端的服务器宕掉了,但是客户端的cookie是不会刷新的,如果设置此参数,将会将客户的请求强制定向到另外一个后端server上,以保证服务的正常。
    option abortonclose
    # 当服务器负载很高的时候,自动结束掉当前队列处理比较久的链接
    option dontlognull
    # 启用该项,日志中将不会记录空连接。所谓空连接就是在上游的负载均衡器或者监控系统为了探测该服务是否存活可用时,需要定期的连接或者获取某一固定的组件或页面,或者探测扫描端口是否在监听或开放等动作被称为空连接;官方文档中标注,如果该服务上游没有其他的负载均衡器的话,建议不要使用该参数,因为互联网上的恶意扫描或其他动作就不会被记录下来
    option httpclose
    # 这个参数我是这样理解的:使用该参数,每处理完一个request时,haproxy都会去检查http头中的Connection的值,如果该值不是close,haproxy将会将其删除,如果该值为空将会添加为:Connection: close。使每个客户端和服务器端在完成一次传输后都会主动关闭TCP连接。与该参数类似的另外一个参数是“option forceclose”,该参数的作用是强制关闭对外的服务通道,因为有的服务器端收到Connection: close时,也不会自动关闭TCP连接,如果客户端也不关闭,连接就会一直处于打开,直到超时。
    contimeout 5000
    # 设置成功连接到一台服务器的最长等待时间,默认单位是毫秒,新版本的haproxy使用timeout connect替代,该参数向后兼容
    clitimeout 3000
    # 设置连接客户端发送数据时的成功连接最长等待时间,默认单位是毫秒,新版本haproxy使用timeout client替代。该参数向后兼容
    srvtimeout 3000
    # 设置服务器端回应客户度数据发送的最长等待时间,默认单位是毫秒,新版本haproxy使用timeout server替代。该参数向后兼容

listen status # 定义一个名为status的部分
    bind 0.0.0.0:1080
    # 定义监听的套接字
    mode http
    # 定义为HTTP模式
    log global
    # 继承global中log的定义
    stats refresh 30s
    # stats是haproxy的一个统计页面的套接字,该参数设置统计页面的刷新间隔为30s
    stats uri /admin?stats
    # 设置统计页面的uri为/admin?stats
    stats realm Private lands
    # 设置统计页面认证时的提示内容
    stats auth admin:password
    # 设置统计页面认证的用户和密码,如果要设置多个,另起一行写入即可
    stats hide-version
    # 隐藏统计页面上的haproxy版本信息

frontend http_80_in # 定义一个名为http_80_in的前端部分
    bind 0.0.0.0:80
    # http_80_in定义前端部分监听的套接字
    mode http
    # 定义为HTTP模式
    log global
    # 继承global中log的定义
    option forwardfor
    # 启用X-Forwarded-For,在requests头部插入客户端IP发送给后端的server,使后端server获取到客户端的真实IP
    acl static_down nbsrv(static_server) lt 1
    # 定义一个名叫static_down的acl,当backend static_sever中存活机器数小于1时会被匹配到
    acl php_web url_reg /*.php$
    #acl php_web path_end .php
    # 定义一个名叫php_web的acl,当请求的url末尾是以.php结尾的,将会被匹配到,上面两种写法任选其一
    acl static_web url_reg /*.(css|jpg|png|jpeg|js|gif)$
    #acl static_web path_end .gif .png .jpg .css .js .jpeg
    # 定义一个名叫static_web的acl,当请求的url末尾是以.css、.jpg、.png、.jpeg、.js、.gif结尾的,将会被匹配到,上面两种写法任选其一
    use_backend php_server if static_down
    # 如果满足策略static_down时,就将请求交予backend php_server
    use_backend php_server if php_web
    # 如果满足策略php_web时,就将请求交予backend php_server
    use_backend static_server if static_web
    # 如果满足策略static_web时,就将请求交予backend static_server

backend php_server #定义一个名为php_server的后端部分
    mode http
    # 设置为http模式
    balance source
    # 设置haproxy的调度算法为源地址hash
    cookie SERVERID
    # 允许向cookie插入SERVERID,每台服务器的SERVERID可在下面使用cookie关键字定义
    option httpchk GET /test/index.php
    # 开启对后端服务器的健康检测,通过GET /test/index.php来判断后端服务器的健康情况
    server php_server_1 10.12.25.68:80 cookie 1 check inter 2000 rise 3 fall 3 weight 2
    server php_server_2 10.12.25.72:80 cookie 2 check inter 2000 rise 3 fall 3 weight 1
    server php_server_bak 10.12.25.79:80 cookie 3 check inter 1500 rise 3 fall 3 backup
    # server语法:server [:port] [param*] # 使用server关键字来设置后端服务器;为后端服务器所设置的内部名称[php_server_1],该名称将会呈现在日志或警报中、后端服务器的IP地址,支持端口映射[10.12.25.68:80]、指定该服务器的SERVERID为1[cookie 1]、接受健康监测[check]、监测的间隔时长,单位毫秒[inter 2000]、监测正常多少次后被认为后端服务器是可用的[rise 3]、监测失败多少次后被认为后端服务器是不可用的[fall 3]、分发的权重[weight 2]、最后为备份用的后端服务器,当正常的服务器全部都宕机后,才会启用备份服务器[backup]

backend static_server
    mode http
    option httpchk GET /test/index.html
    server static_server_1 10.12.25

3. haproxy代理MySQL

主机规划:
haproxy: 192.168.1.115
MySQL01: 192.168.1.125
MySQL02: 192.168.1.116
客户机MySQL: 192.168.1.127

除haproxy的其他三台主机均安装MySQL,步骤相同

19  yum -y install mariadb mariadb-server mariadb-devel
   24  systemctl start mariadb  
   #如果启动失败,提示:Failed to start mariadb.service: Unit not found. 那就 yum -y install mariadb*
   25  mysqladmin -uroot password 123456

两台MySQL都给haproxy主机授权,命令相同

[root@localhost ~]# mysql -uroot -p123456
MariaDB [(none)]> grant all on *.* to 'root'@'192.168.1.115' identified by '123456';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

haproxy修改配置文件,listen部分做修改,如下:

# vim /etc/haproxy/haproxy.cfg 
listen mysqlcluster 0.0.0.0:3306
mode tcp
balance roundrobin
server m1 192.168.1.125:3306 check inter 2000 fall 3
server m2 192.168.1.116:3306 check inter 2000 fall 3

haproxy主机重启haproxy

97  systemctl status haproxy
   98  /etc/init.d/haproxy restart  
   #如果haproxy启动失败,请检查3306端口是否有其他应用,如果有,干掉

在客户机对haproxy的MySQL轮询进行验证:

[root@localhost ~]# mysql -uroot -h 192.168.1.115 -p123456
MariaDB [(none)]> create database t3;

[root@localhost ~]# mysql -uroot -h 192.168.1.115 -p123456
MariaDB [(none)]> create database t4;

在MySQL1上登陆数据库,查询所有库,结果如下:
[root@localhost ~]# mysql -uroot -p123456
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| t3                 |
| test               |
+--------------------+
5 rows in set (0.00 sec)

在MySQL2上登陆数据库,查询所有库,结果如下:
[root@localhost ~]# mysql -uroot -p123456
MariaDB [(none)]> show databases;
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
| performance_schema |
| t4                 |
| test               |
+--------------------+
5 rows in set (0.00 sec)

以上证明haproxy代理MySQL,实现了对MySQL的轮询

在haproxy管理界面查看代理情况:

firefox haproxyIP:1080/stats

haproxy源码安装 haproxy原理_IP

4. haproxy日志

haproxy日志默认不产生,如果需要记录,要结合rsyslog来记录

1. 创建记录日志文件
mkdir /var/log/haproxy
chmod a+w /var/log/haproxy
 2. 开启rsyslog记录haproxy日志功能
编辑“/etc/rsyslog.conf”打开如下配置项: (#由于haproxy的日志是用udp传输的,所以要启用rsyslog的udp监听)
# Provides UDP syslog reception
$ModLoad imudp 这一行取消注释
$UDPServerRun 514  这一行取消注释
添加如下内容:

# Save haproxy log
local0.*                       /var/log/haproxy/haproxy.log
3. 修改“/etc/sysconfig/rsyslog”文件,内容如下
# Options for rsyslogd
# Syslogd options are deprecated since rsyslog v3.
# If you want to use them, switch to compatibility mode 2 by "-c 2"
# See rsyslogd(8) for more details
SYSLOGD_OPTIONS="-r -m 0 -c 2"
4. 配置haproxy
编辑haproxy配置文件,进行如下内容修改
log 127.0.0.1 local0 info
5. 验证是否生效
###重启服务
service rsyslog restart
systemctl restart haproxy
###查看日志记录
tailf /var/log/haproxy/haproxy.log

关于/etc/sysconfig/rsyslog文件中的参数

  • -r 允许接受外来日志消息
  • -m 0表示给日志添加-- MARK --标记,0表示关闭标记。举例,-m 240,表示每隔240分钟(每天6次)在日志文件里增加一行时间戳消息。日志文件里的“–MARK–”消息可以让你知道中央日志服务器上的syslog守护进程没有停工偷懒
  • -c 2

syslogd选项在3版本的rsyslog中即将去除,如果你想使用的话,可以加上-c 2,让rsyslog兼容2的配置