haproxy简介

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

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

haproxy部署

 首先通过科学上网的方式下载haproxy  下载地址:www.haproxy.org/#down

 安装部署haproxy-1.8.13

[root@linux-node1 tools]# tar xf  haproxy-1.8.13.tar.gz
[root@linux-node1 tools]# cd haproxy-1.8.13
[root@linux-node1 haproxy-1.8.13]# make TARGET=linux26 PREFIX=/usr/local/haproxy-1.8.13
[root@linux-node1 haproxy-1.8.13]# make install PREFIX=/usr/local/haproxy-1.8.13
[root@linux-node1 haproxy-1.8.13]# ln -s  /usr/local/haproxy-1.8.13  /usr/local/haproxy
#拷贝haproxy启动脚本到/etc/init.d/目录,并授予可执行权限
[root@linux-node1 haproxy-1.8.13]# cp  examples/haproxy.init   /etc/init.d/haproxy
[root@linux-node1 haproxy-1.8.13]# chmod  +x  /etc/init.d/haproxy

 根据haproxy的启动脚本,创建haproxy的配置文件所在的目录,修改启动脚本对应的haproxy的二进制文件位置

#修改haproxy启动脚本对应的二进制文件位置
[root@linux-node1 ~]# vim  /etc/init.d/haproxy 
#!/bin/sh
#
# chkconfig: - 85 15
# description: HA-Proxy is a TCP/HTTP reverse proxy which is particularly suited
 \
#              for high availability environments.
# processname: haproxy
# config: /etc/haproxy/haproxy.cfg
# pidfile: /var/run/haproxy.pid
BIN=/usr/local/haproxy/sbin/$BASENAME
#根据上面haproxy启动脚本的说明,创建haproxy配置文件的目录
[root@linux-node1 ~]# mkdir  /etc/haproxy/
#根据上面haproxy启动脚本的说明,创建haproxy进程需要的用户
[root@linux-node1 ~]# useradd -r haproxy -s /sbin/nologin

 通过rsyslog系统日志配置文件来配置haproxy日志文件

[root@linux-node1 ~]# vim  /etc/rsyslog.conf 
# Provides UDP syslog reception
$ModLoad imudp
$UDPServerRun 514

# Provides TCP syslog reception
$ModLoad imtcp
$InputTCPServerRun 514

local3.*                                                /var/log/haproxy.log

#重启rsyslog使配置haproxy日志文件生效
[root@linux-node1 ~]# /etc/init.d/rsyslog restart

 创建haproxy配置文件haproxy.cfg

[root@linux-node1 ~]# vim /etc/haproxy/haproxy.cfg 
global
        log 127.0.0.1 local3 info 
        chroot /usr/local/haproxy
        #下面的进程ID一定要和haproxy启动脚本定义的一致
        pidfile /var/run/haproxy.pid
        #配置haproxy的sock文件,权限是600,等级是admin权限,超时2分钟
        stats socket /usr/local/haproxy/haproxy.sock mode 660 level admin
        stats timeout 2m
        user haproxy
        group  haproxy
        daemon
        nbproc 1
        maxconn 30000

defaults
        log global
        mode http
        option httplog        
        option dontlognull
        option http-server-close
        option forwardfor  except 127.0.0.0/8
        timeout http-request 10s
        timeout http-keep-alive 10s
        timeout connect 5000
        timeout client 50000
        timeout server 50000
        timeout check 10000
        maxconn 30000
#定义haproxy状态监控页面
listen haproxy_status
        bind 192.168.80.171:8888
        stats enable
        stats refresh 100s
        stats hide-version
        stats uri /haproxy-status
        stats realm "HAProxy/ static"
        stats auth admin:admin123
        stats admin if TRUE
        #安全起见,还可以定义允许的网段,拒绝其他网段访问
        #acl allow_ips src 192.168.80.0/24
        #tcp-request content accept if allow_ips
        #tcp-request content reject

frontend  webs 
        bind  192.168.80.171:80
        use_backend   srvs_backend
backend srvs_backend
        mode http
        balance roundrobin
        option forwardfor header X-FORWARDED-FOR
        server web-node1  192.168.80.172:80  check inter 2000 rise 2 fall 3 weight 1
        server web-node2  192.168.80.173:80  check inter 2000 rise 2 fall 3 weight 1

 上述haproxy.cfg配置文件部分参数说明

#global段中的参数为进程级别的参数,且通常与其运行的OS相关。
#与代理相关的配置参数可以在这些段中配置:“defaults”、“listen”、“frontend”和“backend”
- chroot <jail dir>:修改haproxy的工作目录至指定的目录并在放弃权限之前执行chroot()操作,可以提升haproxy的安全级别,不过需要注意的是要确保指定的目录为空目录且任何用户均不能有写权限;
- daemon:让haproxy以守护进程的方式工作于后台,其等同于“-D”选项的功能,当然,也可以在命令行中以“-db”选项将其禁用;
- nbproc <number>:指定启动的haproxy进程个数,只能用于守护进程模式的haproxy;默认只启动一个进程,鉴于调试困难等多方面的原因,一般只在单进程仅能打开少数文件描述符的场景中才使用多进程模式;
- node:定义当前节点的名称,用于HA场景中多haproxy进程共享同一个IP地址时;
- mode:设置haproxy实例默认运行模式,有tcp、http、health三个值
- option httplog:启用记录HTTP请求、会话状态和计时器的功能。默认情况下,日志输入格式非常简陋,因为其仅包括源地址、目标地址和实例名称,而“option httplog”参数将会使得日志格式变得丰富许多,其通常包括但不限于HTTP请求、连接计时器、会话状态、连接数、捕获的首部及cookie、“frontend”、“backend”及服务器名称,当然也包括源地址和端口号等。
- retries:设置后端服务器的失败重试次数
- option dontlognull:不记录空连接的日志
- timeout http request:断开客户端连接的超时时长
- timeout queue 在队列中等待的时长
- timeout connect 设定在haproxy转发至后端upstream server时等待的超时时长
- timeout client client的一次非活动状态的超时时长
- timeout server 等待服务器端的非活动的超时时长
- timeout http-keep-alive 保持连接的超时时长
- timeout check:检查请求连接的超时时长
- option  redispatch:如果后端有服务器宕机,强制切换到正常服务器
- option httpchk:用于指定对http协议的server的检测方法
- hash-type:map-based:使用/权重取模;consistent:一致性hash
- cookie:cookie <name> [rewite(重写)|insert(插入)|prefix] ,insert 一般使用nocache
- option http-server-close:在使用长连接时,一定要使用这个参数,这是为了避免客户端超时没有关闭长连接,此功能可以使服务器端关闭长连接
- option httpclose:每次请求完毕后,关闭http通道。如果使用这个参数,那么就不可用长连接参数
- balance:表示haproxy要使用的调度算法,有如下算法:
          roundrobin:轮询,基于权重轮询,动态权重调整,每个后端主机最多支持4128个连接
          static-rr:静态权重轮询,不支持动态调整权重,若调整需要重启,每个后端主机支持的数量没有上线
          leastconn:最少连接数,动态算法,新的连接请求被派发至具有最少连接数据的后端服务器。
                     在有着较长时间会话的场景中推荐使用,如ldap、sql等,不适应较短时间会话场景,如http等
          source:静态算法,将请求的源地址进行hash,除模取余的算法,除以服务器个数
                  可以使同一个客户端ip的请求始终被派发至某特定的服务器(缺点就是如果其中某个服务器 宕机了或者增加了,那么除模取余将会改变,会话信息就不复存在)
                  如果需要将静态改为动态,可以使用hash-type进行修改
          uri:对uri的左半部分或对整个uri进行hash,除模取余的算法,除以服务器个数(总权重),可以使用hash-type进行修改到底是静态算法还是动态算法
          url_param:根据url中的指定的参数的值进行调度,然后进行hash,可以实现类似会话绑定
          hdr(name):header,请求报文首部进行调度,如报文的user-agent浏览器进行调度
                    把指定的header的值进行hash调度,可以使用hash-type进行修改到底是静态算法还是动态算法设置如:hdr(User-Agent

 配置好haproxy的配置文件后,根据haproxy的启动脚本的要求就可以启动haproxy了 

[root@linux-node1 ~]# /etc/init.d/haproxy start 
#配置开启自启动
[root@linux-node1 ~]# chkconfig  --level  35  haproxy  on

 配置好后端的web服务(略),通过http://192.168.80.171:8888/haproxy-status地址展示haproxy的监控界面如下:

haproxy配置转发443端口流量 haproxy多个端口转发_haproxy配置转发443端口流量

 配置当后端服务器出现问题的时候客户端显示的错误页面

[root@linux-node1 haproxy-1.8.13]# cp -r examples/errorfiles/    /usr/local/haproxy/
[root@linux-node1 haproxy]# vim  /etc/haproxy/haproxy.cfg 
backend srvs_backend
        balance  roundrobin
        option forwardfor header X-FORWARDED-FOR
        errorfile 400 /usr/local/haproxy/errorfiles/400.http
        errorfile 403 /usr/local/haproxy/errorfiles/403.http
        errorfile 503 /usr/local/haproxy/errorfiles/503.http
        server web-node1  192.168.80.172:80  check
        server web-node2  192.168.80.173:80  check

 根据客户端访问的域名不同haproxy反向代理到不同的上游服务器,需要用到acl(类似于nginx反向代理的location)

  acl方法,HAProxy定义了很多ACL方法,经常使用的有:hdr_reg(host),hdr_dom(host),hdr_beg(host),url_sub,url_dir,path_beg,path_end

#haproxy.cfg配置文件部分配置如下
frontend  webs 
        bind  192.168.80.171:80
        acl www  hdr_beg(host) -i www.goser.com
        acl bbs  hdr_beg(host) -i bbs.goser.com
        use_backend   www_srvs if www
        use_backend   bbs_srvs  if  bbs
        default_backend   default_srvs
#其他acl控制不符的时候,走默认的后端服务器,比如客户端使用ip访问或其他地址访问等
backend default_srvs
        balance roundrobin
        option forwardfor header X-FORWARDED-FOR
        server web-node1  192.168.80.172:80  check
        server web-node2  192.168.80.173:80  check
backend bbs_srvs
        balance  roundrobin
        option forwardfor header X-FORWARDED-FOR
        server web-node1  192.168.80.172:80  check
backend www_srvs
        balance   roundrobin
        option forwardfor header X-FORWARDED-FOR
        server web-node2  192.168.80.173:80  check

 基于cookie会话保持:由于现实上网的方式多为nat转换,多个局域网私有ip对应一个公网ip,如果使用source算法来绑定到上游某台服务器的话,那么这个服务器压力要很大。所以使用cookie的方式让每个客户端访问时haproxy都会根据cookie转发到后端某台服务器

frontend  webs
        bind  192.168.80.171:80
        use_backend   srvs_backend 
backend srvs_backend
        balance  roundrobin
        cookie  node1  insert indirect  nocache
        cookie  node2  insert indirect  nocache
        option forwardfor header X-FORWARDED-FOR
        server web-node1  192.168.80.172:80  check   cookie  node1
        server web-node2  192.168.80.173:80  check   cookie  node2

 设置一致性hash:hash-type  consistent 要和balance  soure或balance  uri配置使用

backend srvs_backend
        balance  uri
        hash-type  consistent
        option forwardfor header X-FORWARDED-FOR
        server web-node1  192.168.80.172:80  check
        server web-node2  192.168.80.173:80  check

 haproxy负载均衡MySQL服务的配置示例

#---------------------------------------------------------------------
# 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

defaults
    mode                    tcp
    log                     global
    option                  httplog
    option                  dontlognull
    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                 600

listen stats
    mode http
    bind 0.0.0.0:1080
    stats enable
    stats hide-version
    stats uri     /haproxyadmin?stats
    stats realm   Haproxy\ Statistics
    stats auth    admin:admin
    stats admin if TRUE


frontend mysql
    bind *:3306
    mode tcp
    log global
    default_backend mysqlservers

backend mysqlservers
#这里使用最小连接数算法,将客户端请求放到连接数最小的mysql服务上
    balance leastconn
    server dbsrv1 192.168.80.180:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300
    server dbsrv2 192.168.80.190:3306 check port 3306 intval 2 rise 1 fall 2 maxconn 300

 动静分离案例

#部分配置代码如下:
frontend  web_static
    bind  0.0.0.0:80
    acl url_static       path_beg       -i /static /images /javascript /stylesheets
    acl url_static       path_end       -i .jpg .gif .png .css .js

    use_backend static          if url_static
    default_backend              dynamic

backend static
    balance     roundrobin
    server      web-node1 192.168.80.172 check
    server      web-node2 192.168.80.173 check

backend dynamic
    balance     roundrobin
    server      tomcat-noide1  192.168.80.180 check
    server      tomcat-node2   192.168.80.181 check

 通过acl来控制客户端访问的重定向redirect

acl  clear  dst_port 80
acl  secure dst_port 8080
acl  login_page  url_beg /login
acl  logout url_beg /logout
acl  uid_given  url_reg /login?userid=[^&]+
acl  cookie_set hdr_sub(cookie)  SEEN=1
redirect prefix https://goser.com  set-cookie SEEN=1 if !cookie_set
redirect prefix https://goser.com  if login_page !secure
redirect prefix http://goser.com  drop-query if login_page !uid_given
redirect location http://www.goser.com/ if !login_page secure
redirect location / clear-cookie USERID= if logout

 通过acl来实现访问控制

http-request :7层过滤,主要对web站点访问的控制
tcp-request content 4层过滤,主要对非web站点的访问控制,比如mysql的访问控制

 通过socat命令操作haproxy-api来动态管理上游服务的上下线

#安装socat工具
[root@linux-node1 ~]# yum  install  socat  -y
#查看haproxy-api通过socat命令支持的操作
[root@linux-node1 ~]# echo "help" | socat stdio  /usr/local/haproxy/haproxy.sock
#查看haproxy的状态信息
[root@linux-node1 ~]# echo "show info" | socat stdio  /usr/local/haproxy/haproxy.sock
#查看haproxy的上游服务的状态
[root@linux-node1 ~]# echo "show servers state" | socat stdio  /usr/local/haproxy/haproxy.sock 
1
# be_id be_name srv_id srv_name srv_addr srv_op_state srv_admin_state srv_uweight srv_iweight srv_time_since_last_change srv_check_status srv_check_result srv_check_health srv_check_state srv_agent_state bk_f_forced_id srv_f_forced_id srv_fqdn srv_port
4 srvs_backend 1 web-node1 192.168.80.172 2 0 1 1 4390 6 3 4 6 0 0 0 - 80
4 srvs_backend 2 web-node2 192.168.80.173 2 0 1 1 4539 6 3 4 6 0 0 0 - 80
#让某台上游服务停止web服务
[root@linux-node1 ~]# echo "disable server srvs_backend/web-node1" | socat stdio  /usr/local/haproxy/haproxy.sock  
#让某台上游服务启动web服务
[root@linux-node1 ~]# echo "enable server srvs_backend/web-node1" | socat stdio  /usr/local/haproxy/haproxy.sock

 对haproxy大并发连接性能调优

[root@linux-node1 ~]# vim /etc/sysctl.conf  

#调整客户端和服务端连接需要的随机端口范围
net.ipv4.ip_local_port_range = 30000  60000
#允许将TIME-WAIT sockets重新用于新的TCP连接
net.ipv4.tcp_tw_reuse = 1
#开启TCP连接中TIME-WAIT sockets的快速回收
net.ipv4.tcp_tw_recycle = 1
#表示如果套接字由本端要求关闭,这个参数决定了它保持在FIN-WAIT-2状态的时间(可改为30,一般来说FIN-WAIT-2的连接也极少)
net.ipv4.tcp_fin_timeout = 30

#使配置生效
[root@linux-node1 ~]# sysctl -p