一、haproxy的功能:

    HAProxy vs LVS
        HAProxy支持tcp和http两种代理模式,而lvs仅支持tcp代理模式
        HAProxy相比LVS的使用要简单很多,功能方面也很丰富。当前HAProxy支持两种主要的代理模式;
        tcp:仅在客户端和服务器之间转发双向流量。
        http:分析协议,并且能通过允许,拒绝,交换,增加,修改或删除请求或者回应里指定内容来控制协议,这种协议要基于特定的规则。

    HAProxy vs Nginx
        1. HAProxy可以代理任何基于tcp的协议,而不仅仅是http协议,nginx仅支持http、https、mail等协议。
        2. HAProxy对于后端服务器的检查可以基于端口也可以基于url,nginx仅对后端服务器的检查仅通过端口。
        3. HAProxy对session的保持强与nignx,nginx通过ip_hash来定向客户端ip来访问的后端主机,达到session保持的目的。而haproxy有多种算法来达到session保持的目的:source、uri、url_param、hdr

 

二、haproxy的安装



yum install haproxy -y



    主配置文件:/etc/haproxy/haproxy.cfg

    主配置文件详解:

   haproxy配置中分成五大部分:
        global: 全局配置参数,参数是进程级别的,通常这些参数是与操作系统有关。
        defaults: 配置默认参数,这里的默认参数是相对于后面的frontend 、backend、listen组件而言。
        frontend: 相当于nginx中的server段定义,是接收客户端发起请求,建立socket监听。可根据规则直接指定具体的后端服务器。
        backend: 后端服务器集群配置,相当于nginx的upstream配置段,一个backend对应一个或者多个后端服务器。
        listen: 用于建立虚拟主机,是frontend和backend的结合体,可直接取代frontend和backend

    1. global 段具体参数说明:



global        # 对全局参数的说明

            log         127.0.0.1 local2    # 全局的日志配置,使用log关键字,此日志需要借助rsyslog来进行配置,默认等级为info

            chroot      /var/lib/haproxy       # 改变当前工作目录,基于安全性的考虑
            pidfile     /var/run/haproxy.pid  # 当前进程pid文件
            maxconn     4000                # 当前进程最大的连接数,很重要的一个参数,后面有详细的讲解。
            user        haproxy             # 启动服务所属用户
            group       haproxy             # 启动服务所属组
            daemon                            # 开启守护进程运行模式

            # turn on stats unix socket
            stats socket /var/lib/haproxy/stats        # haproxy socket文件



        注意:在全局参数中,要注意的参数:
            maxconn: 启动服务后,haproxy进程的最大连接数,也就是该服务器haproxy支持的最大并发数。
            nbproc: 开启进程数,默认配置是开启1个进程,建议开启一个进程。如开启2个进程定义: nbproc 2

    2. defaults 段具体参数说明:



defaults    # 开始定义 defaults段
            mode                    http          # haproxy支持两种工作模式tcp、http,默认配置为http
            log                     global        # 应用全局配置的日志
            option                  httplog        # 启用日志记录HTTP请求
            option                  dontlognull # 启用该项,日志中将不会记录关于对后端服务器的检测情况。
            option http-server-close            # 每次请求完毕后主动关闭http通道
            option forwardfor       except 127.0.0.0/8    # 这里是转发客户端ip地址至后端服务器上。根据测试,无需修改此项,在后端服务器上设置{X-Forwarded-For}i就能实现。
            option                  redispatch    # 此项是对backend server内容中的serverID作用的,当backend中定义的server启用了cookie时,haproxy会将请求到的后端服务器的serverID插入到cookie中,以保证session持久性,如果此时后端服务器宕机,但是客户端的cookie是不会刷新的,如果开启了cookie,将会使客户端请求强制定向到另一台后端server上,保证了服务的正常运行。
            retries                 3             # 定义尝试连接后端服务器的失败次数,尝试3次失败后,后端该服务器将标记为不可用状态
            timeout http-request    10s            # http请求超时时间
            timeout queue           1m            # 一个请求在队列里的超时时间
            timeout connect         10s            # 连接超时时间
            timeout client          1m            # 客户端超时时间
            timeout server          1m            # 服务端超时时间
            timeout http-keep-alive 10s            # http keepalived保持时间
            timeout check           10s            # 检测超时时间
            maxconn                 3000        # 每个frontend定义的最大连接数



        注意:在defaults中需要注意的参数:
            mode: 工作模式
            timeout http-keep-alive: http keepalived 超时时间,具体需要测试,一般保持默认
            maxconn:defaults中出现的maxconn值是为frontend做限制的。后面有详细的讲解

    3. listen、frontend、backend定义段
        以下是我自行定义的代码段:



listen stats        # 申明定义一个listen段,命名为stats
            bind *:1080        # bind设置socket 格式:ip:port
            mode http         # 指定工作模式
            stats refresh 30     # 刷新时间,这里30秒刷新一次
            stats enable        # 启用haproxy监控状态
            stats hide-version    # 隐藏haproxy的版本号
            stats uri /haproxy?wsd    # 设置haproxy监控页的uri,可任意设置
            stats auth admin:admin    # 验证用户名密码
            stats admin if TRUE        # 此项是实现haproxy监控页的管理功能的。



        注意:此段配置中 stats admin if TRUE 是很重要的。

    4. 定义一个frontend 和 backend段
        注意:
            haproxy 的 backend 同等于 nginx 的 upstream
            haproxy 的 frontend 同等于 nginx 的 server
                这样说虽然有些牵强,但是对于会使用nginx的童鞋来说,更容易理解



frontend www.test.com    # 定一个frontend 段,命名为www.test.com 命名随意。
            mode http             # 定义工作模式
            bind *:8000         # 定义监听地址和端口 格式:ip:port
            option forwardfor   # 将客户端ip转发到后端真实服务器
            use_backend web check    # 使用web后端服务器群组,并进行健康检查

        backend web             # 定义一个backend 段,命名为web,该命名在frontend中 use_backend使用
            balance roundrobin    # 主机集群的调度算法,此参数很重要,下面详细解释。
            # server 定义中可以使用的参数:
                # weight -- 调整服务器权重
                # check -- 允许对该服务器进行健康检查
                # inter -- 设置连续两次健康检查之间的时间,单位为毫秒(ms),默认是2000(ms) = 2秒
                # rise -- 指定多少次连续成功的健康检查后,即可认定该服务器处于可操作状态,默认为2次
                # fall -- 地址多少次失败的检查后,即认为服务宕机,并标识为不可用状态,默认为3次
                # maxconn -- 指定可被送到后端服务器的最大连接并发数
            server web1 127.0.0.1:8080 check    # 具体定义的后端主机 格式:server 主机名 ip:port check
            server web2 127.0.0.1:80 check

        [root@localhost haproxy]# service haproxy restart        # 重启服务
        Stopping haproxy:                                          [  OK  ]
        Starting haproxy:                                          [  OK  ]
        [root@localhost haproxy]# curl http://localhost:8000
        80
        [root@localhost haproxy]# curl http://localhost:8000
        8080



            通过上面的测试,我们发现成功的代理至后端的服务器上了,并且是通过轮询调度的方式。
            在上面的配置中我们也定义了haproxy的状态监控页。通过浏览器尝试访问:

haproxy 传递IP haproxy转发tcp_ldap

haproxy 传递IP haproxy转发tcp_ldap_02

    5. 配置文件中的关键字及性能调整相关参数

        maxconn 在 global、defaults、frontend、listen、server中都有运用到,在不同的代码段代表的意义也是不同的:

            (1) global代码段中maxconn:设置进程的最大连接数,也就是该haproxy总的并发连接数,可进行修改。但是该并发连接受限与系统具体的文件描述符

            例:设置global maxconn=123456

            修改后可打开haproxy监控页查看到:

           

haproxy 传递IP haproxy转发tcp_ldap_03


            (2) defaults段中maxconn:设置默认代理段的最大连接数,该defaluts是设置frontend的连接数,如果frontend中设置了就以frontend中设置的为主,调整后,在监控页中提现:

            例:设置defaults maxconn = 1111 frontend 不设置maxconn

           

haproxy 传递IP haproxy转发tcp_后端服务_04


            (3) listen段中的maxconn:设置该代理的最大连接数,该设置是定义该listen的socket所能接收的最大并发数,如果没有在listen中定义,则以defaults中为准。

            例:设置listen maxconn = 2222

           

haproxy 传递IP haproxy转发tcp_网络_05


            (4) server中的maxconn:设置该后台服务的最大连接数

            例:设置server中的主机maxconn = 3333

           

haproxy 传递IP haproxy转发tcp_网络_06


            注:对于后端主机的性能,可以分别设置不同的maxconn


            总结:listen maxconn + frontend maxconn + server maxconn =< global maxconn

            优先级:listen maxconn > defaults maxconn  frontend maxconn > defaults maxconn

        balance
            定义负载均衡算法,可用于 defaults、listen、backend,其作用是将一个连接通过对应的规则重新派发至后端服务器。支持的算法:
                (1) roundrobin: 基于权重进行轮叫,在服务器处理时间保持平均分配,这是最常见的负载均衡算法,但是在haproxy中此算法是动态的,这表示其权重可动态调整,每个后端服务器仅能最多并发4128个连接,切记!

                (2) static-rr: 基于权重进行轮叫,与roundrobin类似,但是static-rr为静态方法,在运行时,调整权重是不会生效的,不过后端服务器并发数是没有限制的,因此如果要使用haproxy做轮叫一定要修改 balance 为 static-rr 算法

                (3) leastconn: 新的连接请求被派发至具有最少连接数目的后端主机,在有较长时间会话的场景中推荐使用此算法,如LDAP、SQL等,其并不太适用于较短会话的应用层协议,如http,此算法是动态的,可以运行时调整权重;

                (4) source: 将请求的源地址进行hash运算,并由后端服务器的权重总和相除后派发至某匹配的服务器,这可以使得同一个客户端ip的请求始终被派发至特定主机,不过当某台服务器权重发生变化时,如某台后端服务器宕机或新添加了新的机器,许多客户端的请求可能会被派发至与此前请求不同的主机,因此这种算法常用与负载均衡无cookie功能的基于TCP的协议,其默认为静态,但是可以通过hash-type 来修改此特性

                (5) uri: 对uri左半部分或整个URI进行hash运算,并由服务器的总权重相除后派发至某匹配的服务器,这可以使得对同一个uri的访问并定向至后端同一台主机,除非服务器的权重总数发生了变化,次算法常用与代理缓存或反病毒代理以提高缓存命中率,需要注意的是,此算法仅应用与HTTP后端服务器场景,其默认为静态算法,不过可以使用hash-type 来修改此特性。

                (6) url_param: 通过<argument>为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,通过<argument>为URL指定的参数在每个HTTP GET请求中将会被检索;如果找到了指定的参数且其通过等于号“=”被赋予了一个值,此算法可以通过追踪请求中的用户标识进而确保同一个用户ID的请求将被送往同一个特定的服务器,除非服务器的总权重发生了变化;如果某请求中没有出现指定的参数或其没有有效值,则使用轮叫算法对相应请求进行调度;此算法默认为静态的,不过其也可以使用hash-type修改此特性

                (7) hdr: 对于每个HTTP请求,通过<name>指定的HTTP首部将会被检索;如果响应的首部没有出现或者没有有效值,则使用轮叫算法对响应的请求进行调度;此算法为静态,可以通过hash-type修改。

                (8) rdp-cookie: 远程桌面协议,该算法几乎没有被使用到。

            hash-type类型有两种:
                hash-type map-based    静态hash 取模法
                hash-type consistent 动态hash 一致性hash算法

            这里演示两种最长用的算法:static-rr 和 source 算法:

            static-rr算法:


frontend http-in
                    mode http
                    bind *:8000
                    #maxconn 678
                    use_backend web check
                backend web
                    maxconn 777
                    balance static-rr
                    server web1 127.0.0.1:80 maxconn 3333 check
                    server web2 127.0.0.1:8080 maxconn 3333 check
            访问结果:
                [root@node1 haproxy]# curl http://localhost:8000
                <h1>80</h1>
                [root@node1 haproxy]# curl http://localhost:8000
                <h1>8080</h1>


frontend http-in
                    mode http
                    bind *:8000
                    #maxconn 678
                    use_backend web check
                backend web
                    maxconn 777
                    balance static-rr
                    server web1 127.0.0.1:80 maxconn 3333 check
                    server web2 127.0.0.1:8080 maxconn 3333 check
            访问结果:
                [root@node1 haproxy]# curl http://localhost:8000
                <h1>80</h1>
                [root@node1 haproxy]# curl http://localhost:8000
                <h1>8080</h1>


bind 此指令仅能用于frontend和listen区段,用于定义一个或几个监听套接字
            格式:ip:port

mode {tcp|http|health}    
            设定实例的运行模式或协议,当实现内容交换时,前端和后端必须工作在同一种模式(一般来说是http模式),否则无法开启实例。

            tcp:实例运行于纯tcp模式,在客户端和服务器端建立一个tcp通道,且不会对7层报文做任何的操作,通常用于ssh、smtp等
            http:实例运行于http模式,客户端在转发至后端服务器之前将被深度分析,所有与规则不符合的格式都将被拒绝。
            health:实例运行于health模式,其对入站请求仅响应ok信息并关闭连接,且不会记录任何日志,此模式将用于响应外部组件的健康状态检查请求,目前该模式已经被废弃。

        hash-type:定义将请求hash映射到后端服务器的方法,其不能在frontend区段,可用方法有:
            map-based:静态方法,除模取余法。一旦任何一台主机发生变化将影响到全局session
            consistent:一致性hash算法,动态算法。后端服务器主机的变动只能影响到该服务器session区域的变动。

            注:虽然consistent很好用,但派发至后端服务器未必达到理想的负载均衡,需要测试对权重进行调整,
            因此大多数场景还是推荐使用map-based

三、高阶配置及acl
    1. 在haproxy内定义监控backend server 失效了多少台

            listen site-stats
                bind *:1081
                mode http
                monitor-uri /site_status    # 定义网站检查的uri,用来检查后端主机的socket。正常返回200,不正常返回503
                acl site_dead nbsrv(web) lt 2   # 定义网站down时的策略当挂载负载均衡上的指定backend中,有效机器小于2台时,
                返回503
                monitor fail if site_dead    # 当满足策略时返回503

    2. acl配置部分
      

acl server_web hdr_reg(host) -i ^(www.test.com|host.test.com)$
        #如果请求的域名满足正则表达式则返回true -i是忽视大小写。
        acl server_blog hdr_dom(host) -i blog.test.com
        #如果请求的域名满足 blog.test.com返回true  -i是忽视大小写。
        acl test hdr(host) -i test.com
        #如果请求的域名满足test.com返回true -i是忽视大小写。
        acl file_req_url_sub -i abc= 
        #在请求的url中包含abc= ,则此控制策略返回true,否则为false
        acl dir_req rul_dir -i allow
        #在请求url中存在allow作为部分地址路径,则此控制策略返回true,否则返回false
        acl missing_cl hdr_cnt(Content-length) eq 0
        #当请求的header中Content-length 等于0时返回true

        ---acl策略匹配响应---
        block if missing_cl
        # 当请求header中Content-length等于0阻止请求返回403
        block if !file_req || dir_req
        #block 表示阻止请求,返回403错误,这里表示如果不满足file_req或者dir_req,则阻止请求    常用acl
        use_backend test_web if server_web
        # 当满足server_web的策略时使用test_web的backend
        use_backend test_blog if server_blog
        # 当满足server_blog的策略时使用test_blog的backend

        redirect prefix http://a.test.com code 301 if test
        # 当访问a.test.com时,用http301跳转到http://127.0.0.1:8888
        defalt_backend server_bbs
        #以上都不满足的时候使用默认server_bbs的backend

完整的范例配置:


#---------------------------------------------------------------------
# Example configuration for a possible web application.  See the
# full configuration options online.
#
#   http://haproxy.1wt.eu/download/1.4/doc/configuration.txt
#
#---------------------------------------------------------------------

#---------------------------------------------------------------------
# Global settings
#---------------------------------------------------------------------
global
    # to have these messages end up in /var/log/haproxy.log you will
    # need to:
    #
    # 1) configure syslog to accept network log events.  This is done
    #    by adding the '-r' option to the SYSLOGD_OPTIONS in
    #    /etc/sysconfig/syslog
    #
    # 2) configure local2 events to go to the /var/log/haproxy.log
    #   file. A line like the following can be added to
    #   /etc/sysconfig/syslog
    #
    #    local2.*                       /var/log/haproxy.log
    #
    log         127.0.0.1 local2

    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000
    user        haproxy
    group       haproxy
    daemon

    # turn on stats unix socket
    stats socket /var/lib/haproxy/stats

#---------------------------------------------------------------------
# common defaults that all the 'listen' and 'backend' sections will
# use if not designated in their block
#---------------------------------------------------------------------
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    retries                 3
    timeout http-request    10s
    timeout queue           1m
    timeout connect         10s
    timeout client          1m
    timeout server          1m
    timeout http-keep-alive 10s
    timeout check           10s
    maxconn                 3000
listen stats
    bind *:1080
    mode http
    stats refresh 30
    stats enable
    stats hide-version
    stats uri /haproxy?wsd
    stats auth admin:admin
    stats admin if TRUE
listen site-stats
    bind *:1081
    mode http
    monitor-uri /site_status
    acl site_dead nbsrv(test_web) lt 1
    acl site_dead nbsrv(server_blog) lt 1
    acl site_dead nbsrv(test_bbs) lt 1
    monitor fail if site_dead 

frontend http_80_in
    mode http
    bind *:8000
    option forwardfor
# acl 
    acl server_web hdr_reg(host) -i ^(www.test.cn|host.test.cn)
    acl server_blog hdr_dom(host) -i blog.test.cn
    acl test hdr(host) -i test.cn
    acl file_req url_sub -i abc=
    acl dir_req url_dir -i allow
    acl missing_cl hdr_cnt(Content-length) eq 0
# acl 匹配
    #block if missing_cl
    #block if !file_req || dir_req
    use_backend test_web if server_web
    use_backend server_blog if server_blog
    #redirect prefix http://a.test.cn code 301 if test_web
    default_backend test_bbs

backend test_web
    mode http
    balance static-rr 
    #cookie SERVERID
    option httpchk GET /index.html
    server web1 127.0.0.1:80  check inter 1500 rise 3 fall 3 weight 1
    server web2 127.0.0.1:81  check inter 1500 rise 3 fall 3 weight 1
backend server_blog
    mode http
    balance static-rr
    cookie SERVERID
    option httpchk GET /index.html
    server blog1 127.0.0.1:90 cookie blog1 check inter 1500 rise 3 fall 3 weight 1
    server blog2 127.0.0.1:91 cookie blog2 check inter 1500 rise 3 fall 3 weight 2
backend test_bbs
    mode http
    balance static-rr
    cookie SERVERID
    option httpchk GET /index.html
    server bbs1 127.0.0.1:100 cookie bbs1 check  inter 1500 rise 3 fall 3 weight 1
    server bbs2 127.0.0.1:101 cookie bbs2 check  inter 1500 rise 3 fall 3 weight 2

测试结果:
[root@localhost haproxy]# echo "127.0.0.1 www.test.cn host.test.cn" >> /etc/hosts
[root@localhost haproxy]# curl http://www.test.cn:8000
test_web1:80
[root@localhost haproxy]# curl http://www.test.cn:8000
test_web2:81
[root@localhost haproxy]# curl http://host.test.cn:8000
test_web1:80
[root@localhost haproxy]# curl http://host.test.cn:8000
test_web2:81