算法简介

一、算法分类与核心概念铺垫

在讲解具体算法前,先明确 HAProxy 算法的核心分类逻辑:

  • 静态算法:仅依赖配置文件中的后端服务器权重,运行过程中不动态调整,不考虑服务器的实时状态(如连接数、负载)。
  • 动态算法:会实时监控后端服务器的状态(如当前连接数),并根据实时状态动态调整请求分发策略。
  • 混合算法:结合 “静态规则” 和 “请求特征”(如客户端 IP、请求 URI)进行分发,部分场景下也会参考服务器实时状态。

二、各类算法详细解析

1. 静态算法
(1)static-rr(静态轮询)
  • 核心原理:完全按照配置的服务器权重,循环分发请求,运行过程中不调整权重,也不感知服务器的在线 / 离线状态(即使某台服务器宕机,仍会尝试分发请求)。
  • 权重规则:比如后端有两台服务器,server1 weight 2,server2 weight 1,则分发顺序为 server1 → server1 → server2 → server1 → server1 → server2... 严格按权重比例循环。
  • 配置示例
    backend web_servers
        balance static-rr  # 指定静态轮询算法
        server s1 192.168.1.10:80 weight 2 check
        server s2 192.168.1.11:80 weight 1 check
    
  • 适用场景:服务器性能完全一致、且能确保所有服务器始终在线的场景(如静态资源服务器集群);不推荐在生产环境单独使用(无故障自动规避)。
(2)first(优先分发)
  • 核心原理:优先将所有请求分发到列表中第一台可用服务器,只有当第一台服务器不可用时,才会分发到第二台,以此类推。权重对该算法无效。
  • 工作特点:极端的 “独占式” 分发,第一台服务器会承接所有流量,直到其不可用。
  • 配置示例
    backend web_servers
        balance first  # 指定优先分发算法
        server s1 192.168.1.10:80 check  # 优先分发到s1
        server s2 192.168.1.11:80 check  # s1不可用时才用s2
    
  • 适用场景:灾备场景(主服务器承接所有流量,备服务器仅在主服务器故障时启用);测试环境(优先使用某台服务器,其他作为备用)。
2. 动态算法
(1)roundrobin(动态轮询,默认算法)
  • 核心原理:基础逻辑是轮询,但会动态感知服务器状态(通过 check 检测),自动跳过不可用服务器;同时支持运行时调整权重(无需重启 HAProxy)。
  • 权重规则:和 static-rr 类似,但权重可动态修改(如通过echo "set weight web_servers/s1 3" | socat stdio /var/run/haproxy.sock调整)。
  • 配置示例
    backend web_servers
        balance roundrobin  # 默认算法,可省略
        server s1 192.168.1.10:80 weight 2 check
        server s2 192.168.1.11:80 weight 1 check
        server s3 192.168.1.12:80 weight 1 check
    
  • 适用场景:绝大多数通用场景,尤其是后端服务器性能接近、请求处理时间短且均匀的场景(如普通 Web 服务)。
(2)leastconn(最小连接数)
  • 核心原理:优先将请求分发到当前活跃连接数最少的服务器,会动态计算各服务器的连接数,兼顾权重(权重越高,可承接的连接数越多)。
  • 工作特点:适合长连接场景,能避免某台服务器因连接堆积导致负载过高。
  • 配置示例
    backend db_servers
        balance leastconn  # 最小连接数算法
        server db1 192.168.1.20:3306 weight 2 check
        server db2 192.168.1.21:3306 weight 2 check
    
  • 适用场景:长连接服务(如数据库、RPC 服务、WebSocket);请求处理时间差异大的场景(如复杂查询的 API 服务)。
3. 混合算法(基于请求特征的哈希算法)

这类算法的核心是对请求特征做哈希计算,将相同特征的请求固定分发到同一台服务器(实现 “会话粘滞”),部分算法可结合动态状态调整。

(1)source(基于客户端 IP 哈希)
  • 核心原理:对客户端 IP 地址做哈希计算,将同一 IP 的所有请求分发到同一台服务器;支持hash-type(如 modular、consistent),可结合权重。
  • 工作特点:实现简单的会话粘滞,无需额外存储会话信息;但如果客户端是 NAT 网关后的集群(如同一公司所有员工共用一个公网 IP),会导致请求集中到某台服务器。
  • 配置示例
    backend web_servers
        balance source  # 基于客户端IP哈希
        hash-type consistent  # 一致性哈希,减少服务器上下线时的分发波动
        server s1 192.168.1.10:80 weight 2 check
        server s2 192.168.1.11:80 weight 1 check
    
  • 适用场景:需要简单会话粘滞的场景(如未做会话共享的 Web 应用);客户端 IP 分布均匀的场景。
(2)uri(基于请求 URI 哈希)
  • 核心原理:对请求的 URI(如/index.html/api/user)做哈希计算,相同 URI 的请求分发到同一台服务器;可指定uri_depth(截取 URI 的前 N 层)。
  • 工作特点:适合静态资源服务器集群,能利用服务器缓存(同一静态资源的请求始终到同一台服务器,提升缓存命中率)。
  • 配置示例
    backend static_servers
        balance uri  # 基于URI哈希
        uri_depth 1  # 仅截取URI的第一层(如/api/user只取/api)
        server s1 192.168.1.30:80 check
        server s2 192.168.1.31:80 check
    
  • 适用场景:静态资源服务(图片、CSS、JS);CDN 节点分发。
(3)url_param(基于 URL 参数哈希)
  • 核心原理:提取 URL 中指定参数的值做哈希,比如指定userid,则/login?userid=123/profile?userid=123会分发到同一台服务器。
  • 配置示例
    backend app_servers
        balance url_param userid  # 基于userid参数哈希
        server s1 192.168.1.40:80 check
        server s2 192.168.1.41:80 check
    
  • 适用场景:需要按业务参数粘滞的场景(如按用户 ID 分发请求,确保同一用户的请求到同一服务器)。
(4)hdr(基于 HTTP 请求头哈希)
  • 核心原理:提取指定 HTTP 请求头的值做哈希,比如hdr(Cookie)(基于 Cookie)、hdr(Host)(基于域名)、hdr(X-Real-IP)(基于真实客户端 IP);如果指定的头不存在,会降级到 roundrobin 算法。
  • 配置示例
    backend web_servers
        balance hdr(Cookie)  # 基于Cookie哈希实现会话粘滞
        server s1 192.168.1.10:80 check
        server s2 192.168.1.11:80 check
    
  • 适用场景:精准的会话粘滞(如基于 SessionID 的 Cookie);多域名服务(基于 Host 头分发到不同服务器)。

总结

  1. 静态算法(static-rr、first):仅依赖配置权重,无动态调整,适用于服务器状态稳定的场景(如灾备、静态资源),但故障容错性差。
  2. 动态算法(roundrobin、leastconn):实时感知服务器状态,roundrobin 适用于短连接通用场景,leastconn 适用于长连接 / 请求耗时不均的场景。
  3. 混合算法(source、uri、url_param、hdr):基于请求特征哈希实现会话粘滞,分别适用于 IP 粘滞、静态资源缓存、业务参数粘滞、请求头粘滞等场景。

静态算法

1.static-rr

[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10

#检测是否支持热更新
[root@haproxy yxs]# echo "get  weight webcluster/haha" | socat  stdio /var/lib/haproxy/stats
2 (initial 2)

[root@haproxy yxs]# 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%'
2026/02/08 14:40:05 socat[3172] E exactly 2 addresses required (there are 16); use option "-h" for help

2.first

[root@haproxy yxs]#  vim /etc/haproxy/haproxy.cfg
listen webcluster
    bind        *:80
    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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试:在一个shell中执行持续访问
[root@test yxs]# while true; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10

#在其他设立了中建立持续访问并观察
[root@test2 yxs]# while true; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20   #此处出现20信息
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10

动态算法

1.roundrobin

[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10

#动态权重更新
[root@haproxy yxs]# echo "get  weight webcluster/haha" | socat  stdio /var/lib/haproxy/stats
2 (initial 2)

[root@haproxy yxs]# echo "set  weight  webcluster/haha 1  " | socat stdio /var/lib/haproxy/stats  

[root@haproxy yxs]# echo "get  weight webcluster/haha" | socat  stdio /var/lib/haproxy/stats
1 (initial 2)


#测试
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100; done
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10

2.leastconn

[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20
webserver1 - 192.168.0.10
webserver2 - 192.168.0.20

混合算法

1.source

[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10

#source动态算法
[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10

2.uri

#主备实验环境
[root@webserver1 yxs]# echo RS1 - 192.168.0.10 > /var/www/html/index1.html
[root@webserver1 yxs]# echo RS1 - 192.168.0.10 > /var/www/html/index2.html
[root@webserver2 yxs]# echo RS2 - 192.168.0.20 > /var/www/html/index1.html
[root@webserver2 yxs]# echo RS2 - 192.168.0.20 > /var/www/html/index2.html

#设定uri算法
[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100/index2.html; done
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20
RS2 - 192.168.0.20

3.url_param

#主备实验环境
[root@webserver1 yxs]# echo RS1 - 192.168.0.10 > /var/www/html/index1.html
[root@webserver1 yxs]# echo RS1 - 192.168.0.10 > /var/www/html/index2.html
[root@webserver2 yxs]# echo RS2 - 192.168.0.20 > /var/www/html/index1.html
[root@webserver2 yxs]# echo RS2 - 192.168.0.20 > /var/www/html/index2.html

#设定url_param算法
[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100/index.html?name=lee; done
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
webserver2 - 192.168.0.20
[root@test yxs]# for i in {1..10}; do curl 172.25.254.100/index.html?name=redhat; done
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10
webserver1 - 192.168.0.10

4.hdr

[root@haproxy yxs]# vim /etc/haproxy/haproxy.cfg
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
[root@haproxy yxs]# systemctl restart haproxy.service

#测试
[root@test yxs]# curl -A "lee" 172.25.254.100
webserver2 - 192.168.0.20
[root@test yxs]# curl -A "lee" 172.25.254.100
webserver2 - 192.168.0.20
[root@test yxs]# curl -A "timinglee" 172.25.254.100
webserver2 - 192.168.0.20
[root@test yxs]# curl -A "timing" 172.25.254.100
webserver1 - 192.168.0.10

更多推荐