news 2026/7/2 2:01:36

RHEL9.3 HAProxy 高级功能配置实战(Cookie 会话保持、状态监控页、四层 / 七层真实 IP 透传)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
RHEL9.3 HAProxy 高级功能配置实战(Cookie 会话保持、状态监控页、四层 / 七层真实 IP 透传)

前言

前面章节我们完成了 HAProxy 基础安装、socat 热运维、负载均衡调度算法配置,本章聚焦生产环境高频必备三大高级功能:

  1. Cookie 基于 Cookie 精准会话保持:粒度优于源 IP 哈希,解决会话粘滞需求
  2. Web 状态监控页面:可视化查看集群运行、节点健康、流量连接统计
  3. 四层 / 七层真实客户端 IP 透传:后端 Web 服务器获取真实访客 IP,用于日志统计、安全风控、访问分析

实验环境沿用前文架构

  • HAProxy 调度器:eth0172.25.254.100,eth1192.168.0.100
  • RS1:192.168.0.10,RS2:192.168.0.20
  • 客户端测试机:172.25.254.99

一、基于 Cookie 的会话保持(七层 HTTP 专用)

1.1 原理说明

cookie会话黏性是 HAProxy 七层模式专属会话保持方案,粒度比source源IP哈希更精准: HAProxy 给不同后端服务器分配唯一 Cookie 标识,首次访问插入 Set-Cookie;后续客户端携带 Cookie 访问时,直接固定调度至对应后端节点。

  • 限制:仅支持mode http七层模式,TCP 四层模式无法使用
  • 对比:源 IP 哈希会存在局域网多用户同 IP 绑定同一节点弊端,Cookie 基于浏览器标识,用户粒度隔离更精细
  • 现状:大规模集群更多采用后端Session共享替代会话保持,但小集群、老旧业务仍广泛使用 Cookie 黏滞

1.2 cookie 完整配置参数解析

cookie name [ rewrite | insert | prefix ][ indirect ] [ nocache ][ postonly ] [ preserve ][ httponly ] [ secure ][ domain ]* [ maxidle <idle> ][ maxlife ]
参数作用解释
nameCookie 键名,自定义名称,用于识别会话
insert客户端首次访问时,自动向响应头插入 Set-Cookie 写入节点标识
indirect客户端已有 Cookie 时,HAProxy 不再重复下发 Set-Cookie,减少头部冗余
nocache防止 CDN、反向代理缓存 Cookie,避免大量客户端被固定分发同一后端
rewrite/prefix重写 Cookie / 前缀式 Cookie(两种进阶模式,insert 最常用)
httponly/secure安全属性,防止 JS 窃取 Cookie、仅 HTTPS 传输

1.3 完整配置示例

修改 HAProxy 配置/etc/haproxy/haproxy.cfg,新增 cookie 会话保持:

listen webserver-cluster-80 bind 172.25.254.100:80 balance roundrobin mode http option forwardfor # 定义Cookie配置:键名WEBCOOKIE,插入模式、防缓存、已有cookie不再重复下发 cookie WEBCOOKIE insert nocache indirect # 给两台后端分别设置唯一cookie标识 web1 / web2 server webserver1 192.168.0.10:80 cookie web1 check inter 3s fall 3 rise 5 weight 1 server webserver2 192.168.0.20:80 cookie web2 check inter 3s fall 3 rise 5 weight 1

校验配置语法并重启生效:

haproxy -c -f /etc/haproxy/haproxy.cfg systemctl restart haproxy

1.4 效果验证

1. 首次访问自动下发 Set-Cookie
[root@client ~]# curl -i 172.25.254.100 HTTP/1.1 200 OK date: Mon, 16 Mar 2026 11:15:37 GMT server: Apache/2.4.57 (Red Hat Enterprise Linux) last-modified: Thu, 29 Jan 2026 03:27:51 GMT etag: "18-6497e710faf2b" accept-ranges: bytes content-length: 24 content-type: text/html; charset=UTF-8 set-cookie: WEBCOOKIE=web1; path=/ cache-control: private webserver1-192.168.0.10

响应头自动携带Set-Cookie: WEBCOOKIE=web1,代表本次绑定 webserver1 节点。

2. 携带 Cookie 固定访问对应后端
# 携带web2标识,永远访问RS2 [root@client ~]# curl -b WEBCOOKIE=web2 172.25.254.100 Webserver2-192.168.0.20 [root@client ~]# curl -b WEBCOOKIE=web2 172.25.254.100 Webserver2-192.168.0.20 # 携带web1标识,永远访问RS1 [root@client ~]# curl -b WEBCOOKIE=web1 172.25.254.100 webserver1-192.168.0.10 [root@client ~]# curl -b WEBCOOKIE=web1 172.25.254.100 webserver1-192.168.0.10

会话黏滞生效,同一个 Cookie 请求始终调度至绑定服务器。

二、HAProxy Web 状态监控页面(运维可视化必备)

2.1 功能介绍

HAProxy 内置 Web 可视化状态页,无需额外部署监控组件,浏览器即可访问查看:

  • 进程运行时长、CPU / 连接上限、当前并发连接、吞吐速率
  • 后端节点健康状态(UP/DOWN/ 维护下线 / 故障检测中)
  • 总会话量、每秒会话速率、流量进出、错误统计、拒绝请求统计
  • 支持账号密码登录鉴权,支持在线手动上下线后端节点(管理权限)

2.2 状态页核心配置参数

配置指令功能说明
stats enable开启状态页面总开关
stats uri /status自定义访问路径,默认访问地址/haproxy?stats
stats hide-version隐藏 HAProxy 版本号,规避安全扫描漏洞暴露
stats refresh 5s页面自动刷新间隔 5 秒,默认关闭自动刷新
stats auth user:pass登录账号密码,可多行配置多组管理员账号
stats admin if TRUE开启页面管理权限,支持页面上下线后端服务器

2.3 独立状态页配置(推荐配置)

在配置文件末尾新增独立listen段,单独监听 8888 端口做监控入口,不与业务端口混杂:

listen stats mode http bind 0.0.0.0:8888 stats enable log global stats uri /status stats hide-version stats refresh 5s stats auth dragon:dragon stats admin if TRUE

重载配置并放行防火墙端口:

haproxy -c -f /etc/haproxy/haproxy.cfg systemctl restart haproxy # 放行8888端口 firewall-cmd --add-port=8888/tcp --permanent firewall-cmd --reload

2.4 浏览器访问方式

访问地址:http://172.25.254.100:8888/status弹窗输入账号:dragon,密码:dragon即可进入监控面板。

2.5 页面关键字段释义

全局运行信息
pid = 27134 (process #1, nbproc = 1, nbthread = 1) uptime = 0d 0h00m04s system limits: memmax = unlimited; ulimit-n = 200029 maxsock = 200029; maxconn = 100000; maxpipes = 0 current conns = 2; conn rate = 2/sec
  • pid:进程 ID、进程 / 线程数量
  • uptime:服务运行时长
  • current conns:当前活跃总连接数
后端节点状态分类
状态标识含义
active UP节点健康在线,正常承接流量
active DOWN, going up故障节点检测恢复中
active or backup DOWN节点健康检查失败,已下线
MAINT管理员手动维护下线
SOFT STOPPED权重置 0 软下线,不再接收新连接
流量与会话统计
  • sessions cur/max/total:当前会话、峰值会话、总请求量
  • In/Out Bytes:入站、出站总流量
  • Errors Req/Conn/Resp:请求错误、连接错误、响应错误统计

三、四层 TCP & 七层 HTTP 真实客户端 IP 透传

业务背景

HAProxy 作为反向代理,后端 Web 服务器默认只能获取 HAProxy 内网 IP,无法拿到真实访客 IP;无法完成访问日志统计、IP 黑名单拦截、地域分析、风控限流等业务。 HAProxy 提供两套方案实现 IP 透传:

  1. 七层 HTTP 模式:X-Forwarded-For 请求头透传(最常用)
  2. 四层 TCP 模式:Proxy Protocol 代理协议透传

3.1 四层 TCP 模式:Proxy Protocol(send-proxy)IP 透传

1、HAProxy 四层配置

mode tcp场景,后端服务器开启proxy_protocol协议接收原始客户端 IP:

listen webserver-cluster-80 bind 172.25.254.100:80 balance roundrobin mode tcp # send-proxy 开启代理协议,向前端传递原始五元组信息 server webserver1 192.168.0.10:80 send-proxy check inter 3s fall 3 rise 5 weight 1 server webserver2 192.168.0.20:80 send-proxy check inter 3s fall 3 rise 5 weight 1

校验重启服务:

haproxy -c -f /etc/haproxy/haproxy.cfg systemctl restart haproxy
2、后端 Nginx 配置接收 Proxy Protocol
RS2(192.168.0.20)开启代理协议监听,日志打印真实 IP
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; listen [::]:80 proxy_protocol; server_name _; root /usr/share/nginx/html; } }

重载 Nginx:systemctl reload nginx

RS1(192.168.0.10)不开启 Proxy Protocol 作为对比

默认日志只能看到 HAProxy 内网地址:

http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; }
3、访问测试 & 日志对比

客户端批量访问:

[root@client ~]# for i in {1..10};do curl 172.25.254.100;done
  • RS1 日志(未开启 Proxy Protocol)
192.168.0.100 - - [16/Mar/2026:20:51:08 +0800] "GET / HTTP/1.1" 200 18 "-" "curl/7.76.1" "-"

只能看到 HAProxy 内网 IP192.168.0.100

  • RS2 日志(开启 Proxy Protocol 成功获取真实 IP)
192.168.0.100 - - [16/Mar/2026:20:51:08 +0800] "GET / HTTP/1.1" "172.25.254.99"200 18 "-" "curl/7.76.1" "-"

成功打印客户端真实源 IP172.25.254.99

3.2 七层 HTTP 模式:X-Forwarded-For 头部透传(生产主流)

原理

option forwardfor指令让 HAProxy 在转发 HTTP 请求时,自动新增X-Forwarded-For请求头,填入客户端真实 IP;后端 Apache/Nginx 修改日志格式读取该头部,记录真实访客地址。

1、HAProxy 全局配置 forwardfor

推荐在defaults段全局开启,所有后端代理自动生效:

defaults mode http log global option httplog option dontlognull option http-server-close # 排除本地回环网段,不对自身IP插入头部 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 webserver-cluster-80 bind 172.25.254.100:80 balance roundrobin mode http option forwardfor server webserver1 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 1 server webserver2 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

重启 HAProxy 生效。

2、后端 Apache httpd 日志配置读取 X-Forwarded-For
RS1(开启读取 XFF 头部)

编辑/etc/httpd/conf/httpd.conf,修改日志格式行:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{X-Forwarded-For}i\" \"%{Referer}i\" \"%{User-Agent}i\"" combined

重启 httpd:systemctl restart httpd

RS2(默认原生日志,不读取 XFF)

保持默认日志格式:

LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
3、后端 Nginx 日志配置读取 X-Forwarded-For
http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; }
4、访问日志验证

客户端循环访问后查看:

  • RS1 httpd 日志(成功获取真实 IP)
192.168.0.100 - - [16/Mar/2026:21:21:17 +0800] "GET / HTTP/1.1" 200 24 "172.25.254.99" "-" "curl/7.76.1"
  • RS2 httpd 日志(仅看到代理 IP)
192.168.0.100 - - [16/Mar/2026:21:23:38 +0800] "GET / HTTP/1.1" 200 24 "-" "curl/7.76.1"

3.3 两种透传方案选型总结

方案适用模式优点缺点
X-Forwarded-For仅七层 HTTP配置简单、兼容性极强,主流方案四层 TCP 无法使用
Proxy Protocol(send-proxy)四层 TCP / 七层 HTTP 通用四层场景唯一透传方案,协议标准化前后端必须成对开启配置,配置繁琐
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 2:00:21

P2279 [HNOI2003] 消防局的设立 题解加总结

思路 因为题目求的是覆盖树上所有点的所放置最少的消防站数量&#xff0c;因此此题需使用树形 DP 解决 状态申明 因为每个"消防局"能覆盖与它距离不超过 2 的节点 &#xff0c;因此 总共设有5个状态 dp[x][0] 为覆盖到 的爷爷&#xff08;包括父亲&#xff09;和…

作者头像 李华
网站建设 2026/7/2 2:00:06

Android 7系统日志(四)日志写入接口—Java层与Native层

系列目录&#xff1a;第一篇&#xff1a;全景图与架构概览 | 第二篇&#xff1a;logd守护进程—启动、初始化与Socket通信 | 第三篇&#xff1a;liblog库—日志写入的完整链路 | 第四篇&#xff1a;日志写入接口—Java层与Native层 | 第五篇&#xff1a;日志读取—logcat源码深…

作者头像 李华
网站建设 2026/7/2 1:59:12

首先从功能最简单的out_ptr讲起。

std::out_ptr其实是一个函数&#xff0c;返回一个类型为std::out_ptr_t的智能指针适配器&#xff0c;函数签名如下&#xff1a; #include <memory>template< class Pointer void, class Smart, class... Args >auto out_ptr( Smart& s, Args&&... arg…

作者头像 李华
网站建设 2026/7/2 1:58:57

算法札记:C++ __int128

老纸不想写高精度故学了下__int128_int128 (有符号)‌_‌类型&#xff1a;128位有符号整数最大能存&#xff1a;约 170,141,183,460,469,231,731,687,303,715,884,105,727 (约 1.7 10⁸)十进制大约能存 39 位数。‌不过&#xff0c;用的时候有两点要特别注意&#xff1a;‌‌它…

作者头像 李华
网站建设 2026/7/2 1:57:00

EM3080-W与PIC32MZ的嵌入式条形码解码系统设计

1. EM3080-W与PIC32MZ的条形码解码系统设计背景在零售仓储、物流分拣和工业自动化领域&#xff0c;条形码识别系统的响应速度和准确率直接决定了整体作业效率。传统方案通常采用通用摄像头软件解码的方式&#xff0c;存在功耗高、延迟大&#xff08;普遍在200-300ms&#xff09…

作者头像 李华