使用场景

假如要实现这样的环境:haproxy反向代理4个nginx节点,nginx1和nginx2结合php提供动态web服务,nginx3和nginx4提供静态web服务。如下图:

haproxy反向代理功能配置_第1张图片

由于默认配置文件中和超时时间相关的设置比较不合理,所以建议修改这些时间。另外还有些建议开启或关闭的的项也尽量开启或关闭。

haproxy配置说明

关于 haproxy 安装与配置,可详见HaProxy安装和常用命令

haproxy 默认配置说明

#查看默认 haproxy.cfg 配置文件
cat /usr/local/haproxy/conf/haproxy.cfg

global
    log         127.0.0.1 local2      # 需要设置/etc/rsyslog.conf加上local2设备的日志记录级别和日志路径
    chroot      /usr/local/haproxy    #这里通过编译安装到/usr/local/haproxy,yum安装默认在/var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     4000                  # 这是前端对外的最大连接数。代理http时,1G空闲内存承载20000以上没大问题
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats  # 开启动态查看、管理haproxy的状态文件
                                         # 另外建议设置spread-checks全局项,且百分比建议为2-5之间
defaults
    mode                    http         # 7层http代理,另有4层tcp代理
    log                     global
    option                  httplog      # 在日志中记录http请求、session信息等
    option                  dontlognull  # 不要在日志中记录空连接
    option http-server-close             # 后端为动态应用程序建议使用http-server-close,后端为静态建议使用http-keep-alive
    option forwardfor       except 127.0.0.0/8  # haproxy将在发往后端的请求中加上"X-Forwarded-For"首部字段
    option                  redispatch   # 当某后端down掉使得haproxy无法转发携带cookie的请求到该后端时,将其转发到别的后端上
    timeout http-request    10s     # 此为等待客户端发送完整请求的最大时长,应该设置较短些防止洪水***,如设置为2-3秒
                                    # haproxy总是要求一次请求或响应全部发送完成后才会处理、转发,
    timeout queue           1m      # 请求在队列中的最大时长,1分钟太长了。设置为10秒都有点长,10秒请求不到资源客户端会失去耐心
    timeout connect         10s     # haproxy和服务端建立连接的最大时长,设置为1秒就足够了。局域网内建立连接一般都是瞬间的
    timeout client          1m      # 和客户端保持空闲连接的超时时长,在高并发下可稍微短一点,可设置为10秒以尽快释放连接
    timeout server          1m      # 和服务端保持空闲连接的超时时长,局域网内建立连接很快,所以尽量设置短一些,特别是并发时,如设置为1-3秒
    timeout http-keep-alive 10s     # 和客户端保持长连接的最大时长。优先级高于timeout http-request高于timeout client
    timeout check           10s     # 和后端服务器成功建立连接后到最终完成检查的时长(不包括建立连接的时间,只是读取到检查结果的时长),
                                    # 可设置短一点,如1-2秒
    maxconn                 3000    # 默认和前段的最大连接数,但不能超过global中的maxconn硬限制数

说明⚠️:

(1)haproxy是单进程、事件驱动模型的软件,单进程下工作效率已经非常好,不建议开启的多进程/多实例。

(2)maxconn指令控制最大并发连接数,可以在多处设置,设置位置不同,代表意义不同:

  <1> 设置在global段或frontend/listen/defaults段的maxconn代表的是和客户端(即frontend)的最大连接并发数;其中global段的值是硬限制,frontend/listen/defaults段的maxconn值不能超过global段的值。

  <2> 设置在server指令中时,代表的是haproxy和某台后端服务器维持的最大并发连接数。

  <3> 前端的最大并发数(即global段的maxconn)可以根据内存来估算,haproxy为每个连接维持两个缓存区,每个大致16K左右,加上一些额外数据,共约33-34K左右,因此理论上1G的空闲内存能维持2W-2.5W个纯HTTP的并发连接(只是理论上),如果代理的是https,则允许的最大并发数量要小的多。前端maxconn默认值为2000,非常有必要将其增加几倍。一般代理纯http服务时,如果后端能处理及时,这里设置20000以上都不会有什么问题。以上只是大致估算代理能力,实际设置时必须根据后端处理能力以及haproxy自身能力设置前端maxconn,否则将前端接进来后端也无法立即处理。

  <4> 后端所有服务器的maxconn值之和应接近前端的maxconn值,计算两者差距时,还需要考虑后端的等待队列长度maxqueue。其中和静态web服务器的maxconn可以设置大一些。

haproxy按需修改后配置说明

global
    log         127.0.0.1 local2
    chroot      /var/lib/haproxy
    pidfile     /var/run/haproxy.pid
    maxconn     20000
    user        haproxy
    group       haproxy
    daemon
    stats socket /var/lib/haproxy/stats
    spread-checks 2
defaults
    mode                    http
    log                     global
    option                  httplog
    option                  dontlognull
    option http-server-close
    option forwardfor       except 127.0.0.0/8
    option                  redispatch
    timeout http-request    2s
    timeout queue           3s
    timeout connect         1s
    timeout client          10s
    timeout server          2s
    timeout http-keep-alive 10s
    timeout check           2s
    maxconn                 18000 

frontend http-in
    bind             0.0.0.0:80                 # 表示haproxy监听所有地址,监听的端口为80
    mode             http
    log              global
    capture request  header Host len 20
    capture request  header Referer len 60
    ####### 定义访问控制,表示url以.css .js .html .php结尾的分别调度到哪台服务器上访问 #########
    #ACL本意是access control list(访问控制列表),用来定义一组黑名单或白名单。
    acl url_static   path_beg  -i /static /images /stylesheets     
    acl url_static   path_end  -i .jpg .jpeg .gif .png .ico .bmp .css .js
    acl url_static   path_end  -i .html .htm .shtml .shtm .pdf .mp3 .mp4 .rm .rmvb .txt
    acl url_static   path_end  -i .zip .rar .gz .tgz .bz2 .tgz
    ####### usr_backend表示使用backend服务,if表示如果满足url_static这个条件就调度到这台服务器上 ########
    use_backend      static_group   if url_static
    #不满足则响应backend的默认动态页面
    default_backend  dynamic_group

backend static_group
    balance            roundrobin        #haproxy反向代理调度算法。如果后端是静态web,建议使用roundrobin算法。
    option             http-keep-alive   #分析并处理所有的request和response(默认),当后端为静态web或静态缓存服务器时,使用http-keep-alive模型。由于响应速度快,频繁建立tcp连接的代价比较大;
    http-reuse         safe              #开启 haproxy 连接重用功能,safe:这是建议使用的策略。
    option httpchk     GET /index.html   #开启 haproxy 健康检查,本例是基于http协议检查。默认会使用tcp协议进行检查,如果要基于其它协议检查,需要使用协议对应的option指令显式指定要检查的对象。且前提是server中必须指定check,这是控制检查与否的开关。
    http-check expect  status 200        #使用http-check expect指定要检查到状态码200才认为健康。如果不指定http-check expect指令,那么基于http协议检查的时候,只要状态码为2xx或3xx都认为是健康的。
    server staticsrv1  192.168.100.62:80 check rise 1 maxconn 5000  #check设置的是是否开启健康检查功能,以及检查的时间间隔、判断多少次不健康后就认为后端下线了以及成功多少次后认为后端重新上线了。
    server staticsrv2  192.168.100.63:80 check rise 1 maxconn 5000  #rise :设定健康状态检查中,某离线的server从离线状态转换至正常状态需要成功检查的次数;
                                                                    #maxconn :指定此服务器接受的最大并发连接数;如果发往此服务器的连接数目高于此处指定的值,其将被放置于请求队列,以等待其它连接被释放;
backend dynamic_group
    cookie appsrv insert nocache      #向响应报文中插入了一个cookie,保证被调度过的服务端和客户端能保持会话。
    balance roundrobin                #如果后端需要保持会话信息,但又不使用cookie时,可以使用源地址hash算法source,保证将同一客户端引导到同一后端服务器上。如果使用cookie,则可以使用roundrobin或leastconn算法。源地址hash算法,一般只在没有办法的时候但又要调度到同一后端服务器时,才作为最后手段。
    option http-server-close          #处理完第一个response后关闭和server端的连接,但和客户端的连接仍然保持,后端为动态应用程序服务器组建议使用此模式。
    option httpchk     GET /index.php #设置通过获取index.php来做健康状况检查
    http-check expect  status 200     #使用http-check expect指定要检查到状态码200才认为健康。
    server appsrv1 192.168.100.60:80  check rise 1 maxconn 3000 cookie appsrv1  #cookie :为指定server设定cookie值,此处指定的值将在请求入站时被检查,第一次为此值挑选的server将在后续的请求中被选中,其目的在于实现持久连接的功能;
    server appsrv2 192.168.100.61:80  check rise 1 maxconn 3000 cookie appsrv2

listen report_stats
        bind 0.0.0.0:8081                        #监听端口
        stats refresh 30s                  #统计页面自动刷新时间 
        stats enable                       #启用管理界面
        stats hide-version                 #隐藏统计页面上HAProxy的版本信息
        stats uri    /hastats              #统计页面url 
        stats realm  "pls enter your name" #统计页面密码框上提示文本 
        stats auth   admin:admin           #统计页面用户名和密码设置 
        stats admin  if TRUE               #如果登录成功就可以管理在线服务器

##### 定义错误页面 #####
errorfile 403 /etc/haproxy/errorfiles/403.http
errorfile 500 /etc/haproxy/errorfiles/500.http
errorfile 502 /etc/haproxy/errorfiles/502.http
errorfile 503 /etc/haproxy/errorfiles/503.http

上面的配置中:

  • (1)静态请求将分配给static_group并进行roundrobin调度,同时通过获取index.html来做健康状况检查,此外还设置了haproxy和后端连接重用的功能。

  • (2)动态请求将分配给dynamic_group并进行roundrobin调度,但是向响应报文中插入了一个cookie,保证被调度过的服务端和客户端能保持会话。此外还设置了通过获取index.php来做健康状况检查。

配置nginx和php+php-fpm

yum -y install nginx php php-fpm

为了区分,分别为nginx1/nginx2的index.php、nginx3/nginx4的index.html文件中加入响应的主机来源提示,并在php文件中设置cookie项。其中index.php的内容参考如下:

response from webapp 192.168.100.60

".$_SERVER['SERVER_ADDR'].""."
"; echo "Server Name: "."".$_SERVER['SERVER_NAME'].""."
"; echo "SESSIONNAME: "."".session_name().""."
"; echo "SESSIONID: "."".session_id().""."
"; ?>

测试。其中php页面返回内容大致如此:

haproxy反向代理功能配置_第2张图片

参考文档

  • haproxy配置示例和需要考虑的问题

  • HAProxy用法详解 全网最详细中文文档

  • HAproxy(二)动静分离