haproxy高级功能及设置

[复制链接]
发表于 2026-10-3 15:59:55 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

章节概览

本文整理 HAProxy 的两类进阶用法:一是基于 cookie 的会话保持,二是客户端真实 IP 的透传(分别讲七层与四层两种场景)。两者都是生产负载均衡里绕不开的问题。

一、基于 cookie 的会话保持

会话保持要解决的是"同一个用户的请求必须落到同一台后端"。HAProxy 除了按源地址哈希之外,还精确支持 cookie 粘滞。

cookie <value>:给当前 server 指定一个 cookie 值,实现基于 cookie 的会话黏性。相比基于 source(源地址)的 hash 调度算法,cookie 模式的调度粒度更精准;代价是 HAProxy 要为每个请求插入并维护 cookie,会增加一点负载。目前这种模式用得不算多——更主流的做法是把 session 提到共享存储(Redis 等)里做 session 共享,从根上解耦。

1.1 命名 cookie 并赋予取值

注意:该场景不支持 tcp 模式,必须工作在 http 模式。

listen webcluster
    bind *:80
    mode http                  # 不支持 tcp mode
    balance roundrobin
    # insert:在响应头中插入一个新的 cookie
    # nocache:禁用缓存,防止浏览器缓存该 cookie
    # indirect:间接方式保存会话关联的服务信息,cookie 里不直接写服务器名
    cookie WEBCOOKIE insert nocache indirect
    server web1 192.168.239.10:80 cookie lee1 check inter 2 fall 3 rise 5 weight 1
    server web2 192.168.239.20:80 cookie lee2 check inter 2 fall 3 rise 5 weight 1
    server web3_sorry 192.168.239.100:8080 backup

几个参数的含义:

  • insert:由 HAProxy 在响应里插入 Set-Cookie 头;
  • nocache:给带 cookie 的响应打上不可缓存标记;
  • indirect:客户端第一次请求不插 cookie,等后端选定后在下一次响应里带上,避免"未选定就先给 cookie";
  • cookie lee1:为该 server 固定的 cookie 取值,浏览器回带它就一路粘在这台机器上;
  • check inter 2 fall 3 rise 5:健康检查每 2 秒一次,连续 3 次失败摘除,连续 5 次成功再拉回;
  • backup:把所有主节点都判死之后才启用的兜底节点(本例的 sorry 页)。

1.2 怎么验证 cookie 生效

Windows 浏览器验证:反复点刷新,页面内容始终是同一份(比如始终是 web1 的页面),就说明粘滞生效了。

Linux 命令行验证:用 curl 手动带不同的 cookie 值访问,后端返回的内容应该跟着变:

[root@localhost ~]# curl -b 'WEBCOOKIE=lee1' 192.168.239.100
this is web1
[root@localhost ~]# curl -b 'WEBCOOKIE=lee2' 192.168.239.100
this is web2
[root@localhost ~]# curl -b 'WEBCOOKIE=lee2' 192.168.239.100
this is web2
[root@localhost ~]# curl -b 'WEBCOOKIE=lee1' 192.168.239.100
this is web1

看到带 lee1 就落到 web1、带 lee2 就落到 web2,且重复请求不会漂移,cookie 会话保持就配置正确了。

二、IP 透传:让后端看到真实客户端

后端 web 服务器需要记录客户端真实 IP,用于访问统计、安全防护、行为分析、区域排行等。但在反向代理后面,后端看到的永远是代理的 IP,必须显式把真实 IP 传下去。

2.1 四层与七层透传的区别

先分清两者的转发方式:

  • 四层(L4):基于 IP + 端口转发,报文里的目标地址被改成某台后端 IP,之后客户端直接与这台后端建 TCP 连接。LVS 属于这种"真四层",而 HAProxy 是伪四层——它得分别跟前端客户端、后端服务器各建一次连接。这也是为什么基于 cookie 的会话保持必须跑 http 模式。
  • 七层(L7):基于协议和内容做交换,起反向代理作用。客户端与负载均衡三次握手建连、发请求;负载均衡按规则挑后端,再与后端三次握手建连、转发请求;后端响应回来后,负载均衡再转给客户端。所以七层代理要和客户端、后端分别建立连接。

2.2 七层 IP 透传(X-Forwarded-For)

HAProxy 工作在七层时,在发给后端的请求报文里加一个 X-Forwarded-For 首部,值就是前端客户端地址。

option forwardfor [except <network>] [header <name>] [if-none]
  • except:来自该网段的请求不加这个首部,典型用途是跳过 HAProxy 自身所在的网络,避免叠加假 IP;
  • header:用自定义首部名替代默认的 X-Forwarded-For,例如 header X-Client;
  • if-none:只有原请求里没有该首部时才添加,避免被上游多层代理重写。

配置示例:

[root@haproxy ~]# vim /etc/haproxy/haproxy.cfg
defaults
    option forwardfor except 127.0.0.0/8

后端日志日志格式要同步改

加了首部还不够,后端读取的日志日志变量也得改,否则日志日志里还是记不到。

NGINX 侧:在 nginx.conf 的 http 段里加进 $proxy_add_x_forwarded_for 或 $http_x_forwarded_for,然后 systemctl restart nginx。区别是:$proxy_add_x_forwarded_for 会在已有值后面追加(适合多级代理),$http_x_forwarded_for 只读客户端原样带过来的值。

log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                '"$proxy_add_x_forwarded_for" '
                '$status $body_bytes_sent "$http_referer" '
                '"$http_user_agent" "$http_x_forwarded_for"';

Apache 侧(web2):在配置里加 %{X-Forwarded-For}i,然后 systemctl restart httpd。之后再 curl 测试,看 nginx 与 httpd 的访问日志里记到的客户端地址是不是真实 IP。

2.3 四层透传(proxy protocol)

四层 TCP 模式下没有 HTTP 头可用,只能靠 PROXY 协议这个"带外"方式传递客户端 IP。

HAProxy 配置:把 mode 改成 tcp,server 上加 send-proxy。

listen webcluster
    bind *:80
    mode tcp
    balance roundrobin
    server web1 192.168.239.10:80 send-proxy check inter 2 fall 3 rise 5 weight 1
    server web2 192.168.239.20:80 check inter 2 fall 3 rise 5 weight 1

NGINX 配置:加 $proxy_protocol_addr 变量记录透传过来的客户端 IP,并启用 proxy_protocol 代理功能。

http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '"$proxy_protocol_addr" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';
    server {
        listen 80 proxy_protocol;   # 启用后,不能直接本机访问此站,只能经四层代理进来
        server_name 192.168.239.10;
    }
}

在 web1(nginx)上查访问日志,就能看到 $proxy_protocol_addr 记录的是真实客户端 IP,而不是负载均衡的地址。

注意:listen 80 proxy_protocol 一旦启用,这台 nginx 就不再接受"直接访问"了,只认带 PROXY 头的连接。作为后端直连的站点这是想要的效果,但如果你还要单独调试这台机器,就得先摘掉这个参数,否则会一直连不上。

两种透传方式怎么选

  • 走七层(http 模式 + option forwardfor):配置简单,后端 nginx/apache 原生支持,日志改造量小;代价是代理要拆连接,性能略低,且依赖 HTTP 头(中途有别的代理时会叠加或被覆盖)。
  • 走四层(tcp 模式 + send-proxy):转发性能好,能透传任意 TCP 协议(不只是 HTTP);代价是两端都必须支持 PROXY 协议,nginx 要开 proxy_protocol,否则直接拿不到 IP。

实际部署中还有一种常见组合:L4(LVS 或四层 HAProxy)负责扛连接、L7(nginx)负责做内容转发,此时 IP 透传Nginx 那一段交给 proxy_protocol,Nginx 之上再靠 X-Forwarded-For 往应用传。

小结

HAProxy 的高级用法集中在两处:cookie 会话保持(cookie <name> insert nocache indirect + 每个 server 配 cookie <value>,且必须 http 模式)和 IP 透传(七层用 option forwardfor + 后端改日志格式,四层用 mode tcp + send-proxy + 后端 proxy_protocol)。

排障时的判断顺序很简单:后端日志里 IP 是负载均衡地址 → 先确认代理侧有没有开透传指令;开了透传但日志没变 → 去核对后端日志格式变量有没有同步改成 $proxy_add_x_forwarded_for 或 $proxy_protocol_addr。九成的"IP 透传不生效"都卡在这第二步。

(本文由 qidao123.com企服评测-应用市场 编辑提示整理:配置示例基于 HAProxy 2.x 与 Nginx/Apache 主流版本,适用于 CentOS / Rocky / Ubuntu 环境的实验验证,生产改动前请先备份 haproxy.cfg。)

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表