Haproxy负载均衡算法全解析

Haproxy 算法实验

本文档整理并补全了各类负载均衡算法(静态/动态/混合)在实验环境下的配置、行为与验证方法,保留了原始实验中的截图与命令输出,便于复现与学习。


目录

  • 实验拓扑(说明)
  • 公共说明(healthcheck / weight / stats socket)
  • 静态算法
    • static-rr(静态加权轮询)
    • first(优先/首选)
  • 动态算法
    • roundrobin(动态轮询)
    • leastconn(最少连接)
  • 混合/一致性哈希类
    • source(基于源 IP)
    • uri(基于请求 URI)
    • url_param���基于 URL 参数)
    • hdr(基于请求头)
  • 常见问题与注意事项
  • 常用命令速查

实验拓扑(说明)

实验环境同前:haproxy(双网卡调度器)前端 IP 为 172.25.254.100:80,后端两台 webserver:192.168.0.10 与 192.168.0.20。后端用简单的 index.html 返回标识文本。

(原图:static-rr 用图示)


公共说明(healthcheck / weight / stats socket)

  • health check 常用参数说明:
    • check:启用健康检查
    • inter 3s:每 3s 检查一次
    • fall N:连续 N 次失败判定为 DOWN
    • rise N:连续 N 次成功判定为 UP
  • weight:配置在 server 行上,表示权重(影响算法行为,详见各算法)
  • stats socket(用于运行时查询/修改):
    • 示例:echo "get weight webcluster/haha" | socat stdio /var/lib/haproxy/stats
    • 修改权重(动态支持的算法):echo "set weight webcluster/haha 1" | socat stdio /var/lib/haproxy/stats
    • 注意:某些静态算法(例如 static-rr)限制通过 stats socket 修改权重(只接受 0% / 100% 或根本不接受),输出会提示原因。

校验配置语法:

  • haproxy -c -f /etc/haproxy/haproxy.cfg

重启服务:

  • systemctl restart haproxy

静态算法

1. static-rr(静态加权轮询)

描述:

  • static-rr 是"静态轮询",权重在启动或配置载入时生效,属于静态分配。运行时不接受任意百分比的权重更新(通常只允许 0%/100% 或完全不接受),因此不适合需要动态调整权重的场景。

配置示例:

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     static-rr
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

重启并测试:

bash 复制代码
systemctl restart haproxy.service

# 测试(示例)
for i in {1..10}; do curl 172.25.254.100; done
# 输出示例(webserver1 比 webserver2 多两倍)

运行时权重查询/修改示例(会提示限制):

bash 复制代码
echo "get  weight webcluster/haha" | socat stdio /var/lib/haproxy/stats
# 2 (initial 2)

echo "set  weight  webcluster/haha 1" | socat stdio /var/lib/haproxy/stats
# Backend is using a static LB algorithm and only accepts weights '0%' and '100%'

要点:

  • 启动后权重是固定的,不能像动态算法那样平滑调整。
  • 适用于需要非常简单且启动时即可确定分配比例的场景。

2. first

描述:

  • first 算法会依次尝试按 server 配置顺序选择第一个可用服务器,当该服务器达到 maxconn(或不可用)时才会选择下一个。它更"倾向"于前面的服务器,通常用于主/备或优先级场景。

示例配置:

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     first
    server haha 192.168.0.10:80 maxconn 1 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

验证(观察行为):

  • 在一个终端持续发送请求到 haproxy(curl 循环),会发现大多数请求都分配到"首选"可用服务器(server hehe,或取决于哪个先满足条件)。
  • 当首选达到 maxconn 或不可用时,才会回退到下一台。

要点:

  • 适合主/备或"优先前端"的部署。
  • 注意 maxconn 的设置决定何时切换到下一个服务器。

动态算法(支持运行时权重修改)

3. roundrobin(轮询)

描述:

  • 动态轮询,按顺序轮流选择后端;支持权重,且支持通过 stats socket 在运行时调整权重,影响后续请求分配。

配置示例:

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     roundrobin
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

动态权重调整示例:

bash 复制代码
# 查看初始权重
echo "get  weight webcluster/haha" | socat stdio /var/lib/haproxy/stats
# 2 (initial 2)

# 设置新的权重
echo "set  weight  webcluster/haha 1" | socat stdio /var/lib/haproxy/stats

# 验证新权重
echo "get  weight webcluster/haha" | socat stdio /var/lib/haproxy/stats
# 1 (initial 2)

测试效果(权重变化后的请求分配):

  • 修改权重后再次循环 curl,分发会按新权重反映(更接近 1:1 或按新权重比例)。

要点:

  • 支持在线调整,适合需要根据后端真实负载调整流量的场景。

4. leastconn(最少连接)

描述:

  • 将新请求分配给当前连接数最少的后端服务器(动态),对于长连接或连接时间差异较大的场景效果更好。

配置示例:

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     leastconn
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

测试示例:

  • 在短请求场景可能看起来像是交替分配;在并发长连接场景最少连接效果明显。

要点:

  • 适用于连接保持时间不一致或长连接服务(例如 WebSocket、长轮询)场景。

混合 / 一致性哈希类算法

说明:这些算法通常通过某个请求属性(源 IP / URI / 参数 / header)做哈希,从而将同一类请求路由到同一后端(常用于会话粘性或缓存命中率优化)。可与 hash-type consistent 配合以降低节点变更时的抖动。

5. source(基于源 IP)

描述:

  • 基于客户端源 IP 的哈希来决定后端,使同一客户端 IP 一般会被分配到同一后端。默认行为为简单散列,若要更稳定(在后端变动时尽量少变),可以启用一致性哈希。

示例(默认):

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     source
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

示例(启用一致性哈希):

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     source
    hash-type   consistent
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

测试(示例):

  • 多次 curl 会发现相同客户端 IP 保持到同一后端。

要点:

  • 适合需要客户端粘性但不想做 cookie/session 的场景(局限:同一公网出口的多个客户端会被视为同一 IP)。

(原图)

6. uri(基于 URI)

描述:

  • 根据请求 URI(path + query 部分)进行哈希,能把相同资源请求路由到相同后端,常用于缓存或资源分片策略。

配置示例:

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     uri
    hash-type   consistent
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

实验准备(主备示例):

bash 复制代码
# webserver1:
echo "RS1 - 192.168.0.10" > /var/www/html/index1.html
echo "RS1 - 192.168.0.10" > /var/www/html/index2.html

# webserver2:
echo "RS2 - 192.168.0.20" > /var/www/html/index1.html
echo "RS2 - 192.168.0.20" > /var/www/html/index2.html

测试示例:

bash 复制代码
# /index.html 全部命中 RS1
for i in {1..10}; do curl 172.25.254.100/index.html; done
# 多次结果均为 webserver1 - 192.168.0.10

# /index2.html 全部命中 RS2
for i in {1..10}; do curl 172.25.254.100/index2.html; done
# 多次结果均为 webserver2 - 192.168.0.20

要点:

  • 可用于把不同 URI 的请求固定路由到指定后端(便于缓存命中或资源定位)。

(原图)

7. url_param(基于 URL 参数)

描述:

  • 根据 URL 中指定参数名的值进行哈希(例如 ?name=xxx),非常适合按用户标识或会话参数做粘性路由。

配置示例:

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     url_param name
    hash-type   consistent
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

测试示例:

bash 复制代码
for i in {1..10}; do curl "172.25.254.100/index.html?name=lee"; done
# 多次命中同一后端(例如 webserver2)

for i in {1..10}; do curl "172.25.254.100/index.html?name=redhat"; done
# 多次命中另一个后端(例如 webserver1)

要点:

  • 参数名必须存在,若不存在可能会用空值或落入其他分配策略(具体行为请根据 haproxy 版本确认)。
  • 注意对 URL 编码与特殊字符的处理。

8. hdr(基于请求头)

描述:

  • 根据指定请求头的值做哈希,例如 User-AgentCookie 等,实现基于头部的路由与粘性。

正确语法示例(注意半角符号):

haproxy 复制代码
listen webcluster
    bind        *:80
    balance     hdr(User-Agent)
    hash-type   consistent
    server haha 192.168.0.10:80 check inter 3s fall 3 rise 5 weight 2
    server hehe 192.168.0.20:80 check inter 3s fall 3 rise 5 weight 1

测试示例:

bash 复制代码
curl -A "lee" 172.25.254.100   # User-Agent: lee
curl -A "timing" 172.25.254.100
curl -A "timinglee" 172.25.254.100
# 不同 User-Agent 的哈希值不同,可能会命中不同后端

(原图)


常见问题与注意事项

  • 配置文件语法:使用 haproxy -c -f /etc/haproxy/haproxy.cfg 检查配置。
  • stats socket:用于运行时监控与某些可动态调整的设置(如 roundrobin 的 weight)。不是所有算法/参数在运行时都支持修改。
  • static-rr 的运行时限制:许多实现不允许对权重进行任意实时修改(仅允许 0%/100% 或拒绝),因为分配是静态计算好的。
  • hash-type consistent:在使用基于 hash 的算法(source/uri/url_param/hdr)时建议配合使用 hash-type consistent,减少集群成员变更时的分流抖动。
  • hdr/uri/url_param 等算法对字符串的处理可能与 haproxy 版本有关(如是否忽略 query 排序、编码处理等),测试时请以实际版本为准。
  • 首选(first)与 maxconn:first 算法强烈依赖 server 顺序与 maxconn 的设置以控制"何时换后端"。
  • healthcheck 太严格/太宽松会导致后端频繁上下线或误判,按真实服务响应速度设置 inter/fall/rise。

常用命令速查

  • 检查配置:haproxy -c -f /etc/haproxy/haproxy.cfg
  • 重启服务:systemctl restart haproxy
  • 查看状态:systemctl status haproxy
  • 查看日志:journalctl -u haproxy -f
  • stats socket 查询权重:echo "get weight /" | socat stdio /var/lib/haproxy/stats
  • stats socket 设置权重(动态算法):echo "set weight / " | socat stdio /var/lib/haproxy/stats
  • 测试后端可达性:curl -I http://192.168.0.10/ 或 telnet 192.168.0.10 80

temctl status haproxy

  • 查看日志:journalctl -u haproxy -f
  • stats socket 查询权重:echo "get weight /" | socat stdio /var/lib/haproxy/stats
  • stats socket 设置权重(动态算法):echo "set weight / " | socat stdio /var/lib/haproxy/stats
  • 测试后端可达性:curl -I http://192.168.0.10/ 或 telnet 192.168.0.10 80
相关推荐
永远都不秃头的程序员(互关)4 小时前
【决策树深度探索(四)】揭秘“混乱”:香农熵与信息纯度的量化之旅
算法·决策树·机器学习
永远都不秃头的程序员(互关)4 小时前
【决策树深度探索(三)】树的骨架:节点、分支与叶子,构建你的第一个分类器!
算法·决策树·机器学习
Σίσυφος19004 小时前
OpenCV - SVM算法
人工智能·opencv·算法
清酒难咽10 小时前
算法案例之递归
c++·经验分享·算法
让我上个超影吧10 小时前
【力扣26&80】删除有序数组中的重复项
算法·leetcode
张张努力变强11 小时前
C++ Date日期类的设计与实现全解析
java·开发语言·c++·算法
沉默-_-11 小时前
力扣hot100滑动窗口(C++)
数据结构·c++·学习·算法·滑动窗口
钱彬 (Qian Bin)11 小时前
项目实践19—全球证件智能识别系统(优化检索算法:从MobileNet转EfficientNet)
算法·全球证件识别
feifeigo12311 小时前
基于EM算法的混合Copula MATLAB实现
开发语言·算法·matlab