欢迎光临

VPS搭建高可用负载均衡集群:HAProxy + Keepalived + Consul 实战指南

在互联网服务架构中,单点故障是最大的隐患。一台VPS无论配置多高,一旦宕机就意味着服务中断。对于生产环境来说,高可用不再是可选项,而是必须项。本文将手把手带你使用 HAProxy、Keepalived 和 Consul 搭建一套生产级高可用负载均衡集群,实现自动故障转移、健康检查和服务发现,让你的服务真正达到 99.99% 的可用性目标。

一、架构设计:为什么选择 HAProxy + Keepalived + Consul

在众多负载均衡方案中,为什么我们选择这个组合?让我们逐一分析每个组件的定位和协同方式:

  • HAProxy — 专业级四层/七层负载均衡器,支持丰富的调度算法、健康检查、SSL终端,单机可处理百万级并发连接
  • Keepalived — 基于 VRRP 协议的 VIP 漂移方案,确保入口 IP 永远可用,主节点故障时备用节点秒级接管
  • Consul — 分布式服务发现与配置中心,后端服务注册后 HAProxy 自动感知,无需手动修改配置和重载

三者的协同关系如下:

组件 职责 故障场景
Keepalived VIP 漂移,保证入口 IP 可用 主节点宕机 → 备节点接管 VIP
HAProxy 请求分发,健康检查 后端节点挂 → 自动剔除,恢复后自动加回
Consul 服务注册与发现 新节点上线/下线 → HAProxy 配置自动更新

整体架构是:客户端请求到达 VIP → Keepalived 所在的主 HAProxy 接收请求 → HAProxy 通过 Consul 动态发现后端服务 → 将请求分发到健康的后端节点。如果主 HAProxy 节点故障,Keepalived 将 VIP 迁移到备节点,整个过程对客户端完全透明。

二、环境准备与拓扑规划

2.1 服务器规划

我们需要至少 4 台 VPS 来搭建完整的高可用集群。以下是一个最小化生产拓扑:

角色 数量 最低配置 推荐系统
负载均衡节点(LB) 2 1C/1G Ubuntu 22.04 / Debian 12
Consul Server 3 1C/1G Ubuntu 22.04 / Debian 12
后端应用节点 2+ 2C/4G 按应用需求

如果资源有限,Consul Server 可以与 LB 节点混合部署(测试环境推荐),但生产环境建议独立部署以保证稳定性。

2.2 网络规划

各节点的 IP 分配示例(使用内网 IP 段 10.0.0.0/24):


1
2
3
4
5
6
VIP:           10.0.0.100
LB-Master:     10.0.0.11
LB-Backup:     10.0.0.12
Consul-Server: 10.0.0.21, 10.0.0.22, 10.0.0.23
Backend-1:     10.0.0.31
Backend-2:     10.0.0.32

注意:Keepalived 的 VRRP 需要二层广播可达,LB-Master 和 LB-Backup 必须在同一子网内。如果你的 VPS 提供商支持浮动 IP(如 DigitalOcean、Hetzner),优先使用浮动 IP 替代 VRRP。

三、Consul 集群部署与配置

3.1 安装 Consul

在所有 Consul Server 节点上执行:


1
2
3
4
# 下载并安装 Consul
wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
sudo apt update && sudo apt install -y consul

3.2 配置 Consul Server

在每台 Consul Server 上创建配置文件:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
sudo mkdir -p /etc/consul.d
cat > /etc/consul.d/server.json << 'EOF'
{
  "node_name": "consul-server-1",
  "server": true,
  "bootstrap_expect": 3,
  "datacenter": "dc1",
  "data_dir": "/opt/consul",
  "bind_addr": "10.0.0.21",
  "client_addr": "0.0.0.0",
  "retry_join": ["10.0.0.21", "10.0.0.22", "10.0.0.23"],
  "ui_config": {
    "enabled": true
  },
  "performance": {
    "raft_multiplier": 1
  },
  "enable_local_script_checks": true
}
EOF

sudo mkdir -p /opt/consul
sudo chown -R consul:consul /opt/consul
sudo systemctl enable --now consul

注意每台 Server 的

1
node_name

1
bind_addr

要改成对应的值。集群启动后验证:


1
2
3
4
5
6
7
8
# 查看集群成员
consul members

# 输出应包含3个 Server 节点,状态为 alive
# Node              Address         Status  Type    Build  Protocol  DC   Partition
# consul-server-1   10.0.0.21:8301  alive   server  1.17.0  2         dc1  default
# consul-server-2   10.0.0.22:8301  alive   server  1.17.0  2         dc1  default
# consul-server-3   10.0.0.23:8301  alive   server  1.17.0  2         dc1  default

3.3 后端服务注册

在后端节点上创建服务定义文件:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cat > /etc/consul.d/web-service.json << 'EOF'
{
  "service": {
    "name": "web-app",
    "tags": ["http", "v1"],
    "port": 8080,
    "check": {
      "id": "web-app-health",
      "name": "HTTP Health Check",
      "http": "http://127.0.0.1:8080/health",
      "interval": "10s",
      "timeout": "3s",
      "deregister_critical_service_after": "30s"
    }
  }
}
EOF

# 启动 Consul Agent(Client 模式)
cat > /etc/consul.d/client.json << 'EOF'
{
  "node_name": "backend-1",
  "server": false,
  "datacenter": "dc1",
  "data_dir": "/opt/consul",
  "bind_addr": "10.0.0.31",
  "retry_join": ["10.0.0.21", "10.0.0.22", "10.0.0.23"],
  "enable_local_script_checks": true
}
EOF
1
deregister_critical_service_after

是一个关键配置——当健康检查持续失败超过 30 秒,Consul 会自动将服务从目录中移除,避免 HAProxy 将流量发给已经死掉的节点。

四、HAProxy 配置与 Consul 集成

4.1 安装 HAProxy

在两台 LB 节点上分别安装:


1
2
sudo apt install -y haproxy
sudo systemctl enable haproxy

4.2 启用 Consul Backend 动态解析

HAProxy 原生支持 Consul 作为 DNS 解析后端。这是实现动态服务发现的关键。修改

1
/etc/haproxy/haproxy.cfg


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# 全局配置
global
    log /dev/log local0
    maxconn 50000
    daemon

# 默认配置
defaults
    log     global
    mode    http
    option  httplog
    option  dontlognull
    option  forwardfor
    timeout connect  5s
    timeout client   50s
    timeout server   50s
    retries 3

# Consul DNS 解析器
resolvers consul_dns
    nameserver consul1 10.0.0.21:8600
    nameserver consul2 10.0.0.22:8600
    nameserver consul3 10.0.0.23:8600
    resolve_retries       3
    timeout retry         2s
    hold valid           10s
    hold obsolete        30s
    accepted_payload_size 8192

# 统计页面
frontend stats
    bind *:8404
    mode http
    stats enable
    stats uri /stats
    stats refresh 10s
    stats admin if LOCALHOST

# HTTP 前端
frontend http_in
    bind *:80
    # 绑定域名
    acl host_app hdr(host) -i app.example.com
    use_backend web_app if host_app
    # 默认后端
    default_backend web_app

# 后端:从 Consul 动态发现
backend web_app
    balance roundrobin
    option httpchk GET /health
    http-check expect status 200
    default-server inter 10s fall 3 rise 2 resolvers consul_dns resolve-prefer ipv4
    server-template web 5 _http._tcp.web-app.service.dc1.consul check
1
server-template

是最核心的一行配置。它的含义是:

  • 1
    web

    — 服务器名称前缀

  • 1
    5

    — 最多解析 5 个后端实例

  • 1
    _http._tcp.web-app.service.dc1.consul

    — Consul DNS SRV 记录查询格式

  • 1
    check

    — 启用健康检查

HAProxy 会定期通过 Consul DNS 查询

1
web-app

服务的可用实例,自动添加或移除后端服务器,完全不需要手动修改配置或重载 HAProxy。

4.3 HTTPS 终端配置

对于生产环境,强烈建议在 HAProxy 层面做 SSL 终端。使用 Let’s Encrypt + certbot 自动签发证书:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
sudo apt install -y certbot

# 手动获取证书
certbot certonly --standalone -d app.example.com

# 合并证书格式(HAProxy 需要 PEM 格式)
cat /etc/letsencrypt/live/app.example.com/fullchain.pem \
    /etc/letsencrypt/live/app.example.com/privkey.pem \
    > /etc/haproxy/certs/app.example.com.pem

# 在 haproxy.cfg 前端配置中添加
frontend https_in
    bind *:443 ssl crt /etc/haproxy/certs/app.example.com.pem
    http-request redirect scheme https unless { ssl_fc }
    default_backend web_app

# 自动续期脚本
cat > /etc/cron.d/certbot-haproxy << 'EOF'
0 0 1 */2 * root certbot renew --quiet --deploy-hook "cat /etc/letsencrypt/live/app.example.com/fullchain.pem /etc/letsencrypt/live/app.example.com/privkey.pem > /etc/haproxy/certs/app.example.com.pem && systemctl reload haproxy"
EOF

五、Keepalived 实现 VIP 高可用

5.1 安装 Keepalived


1
2
sudo apt install -y keepalived
sudo systemctl enable keepalived

5.2 主节点配置

在 LB-Master (10.0.0.11) 上创建

1
/etc/keepalived/keepalived.conf


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
global_defs {
    router_id LB_MASTER
    vrrp_skip_check_adv_addr
    vrrp_garp_master_refresh 5
}

# HAProxy 健康检查脚本
vrrp_script chk_haproxy {
    script "/usr/bin/killall -0 haproxy"
    interval 2
    weight -20
    fall 3
    rise 2
}

# VRRP 实例
vrrp_instance VI_1 {
    state MASTER
    interface eth0
    virtual_router_id 51
    priority 100
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass YourSecurePass99
    }

    virtual_ipaddress {
        10.0.0.100/24 dev eth0
    }

    track_script {
        chk_haproxy
    }

    # 主节点成为 MASTER 后执行
    notify_master "/etc/keepalived/notify.sh master"
    # 降级为 BACKUP 后执行
    notify_backup "/etc/keepalived/notify.sh backup"
    # 进入 FAULT 状态后执行
    notify_fault "/etc/keepalived/notify.sh fault"
}

5.3 备节点配置

在 LB-Backup (10.0.0.12) 上创建配置,仅需修改

1
state

1
priority

1
router_id


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
global_defs {
    router_id LB_BACKUP
    vrrp_skip_check_adv_addr
    vrrp_garp_master_refresh 5
}

vrrp_script chk_haproxy {
    script "/usr/bin/killall -0 haproxy"
    interval 2
    weight -20
    fall 3
    rise 2
}

vrrp_instance VI_1 {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 90
    advert_int 1

    authentication {
        auth_type PASS
        auth_pass YourSecurePass99
    }

    virtual_ipaddress {
        10.0.0.100/24 dev eth0
    }

    track_script {
        chk_haproxy
    }

    notify_master "/etc/keepalived/notify.sh master"
    notify_backup "/etc/keepalived/notify.sh backup"
    notify_fault "/etc/keepalived/notify.sh fault"
}

5.4 状态切换通知脚本

创建

1
/etc/keepalived/notify.sh

,用于在状态切换时发送告警和执行清理:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash
STATE=$1
HOSTNAME=$(hostname)
VIPS="10.0.0.100"

case $STATE in
    master)
        logger -t keepalived "[$HOSTNAME] Transition to MASTER - taking over VIPs: $VIPS"
        # 发送告警通知(可接入钉钉/Slack/企业微信 webhook)
        curl -s -X POST "https://your-webhook.example.com/alert" \
            -H 'Content-Type: application/json' \
            -d "{"text": "[$HOSTNAME] Keepalived became MASTER - VIPs: $VIPS"}"
        ;;
    backup)
        logger -t keepalived "[$HOSTNAME] Transition to BACKUP - releasing VIPs"
        ;;
    fault)
        logger -t keepalived "[$HOSTNAME] Entering FAULT state"
        curl -s -X POST "https://your-webhook.example.com/alert" \
            -H 'Content-Type: application/json' \
            -d "{"text": "⚠️ [$HOSTNAME] Keepalived FAULT state detected!"}"
        ;;
esac

关键参数解释:

  • 1
    priority 100 vs 90

    — Master 优先级更高,正常情况下持有 VIP

  • 1
    weight -20

    — 当 HAProxy 进程不可用时,优先级自动减 20(100→80),低于 Backup 的 90,触发自动切换

  • 1
    advert_int 1

    — VRRP 通告间隔 1 秒,确保故障在 3 秒内被检测到

  • 1
    virtual_router_id 51

    — 同一子网内多个 Keepalived 实例必须使用不同的 VRID

六、高级配置与生产优化

6.1 HAProxy 调度算法选择

HAProxy 提供多种调度算法,适用于不同场景:

算法 特点 适用场景
roundrobin 轮询,权重可调 后端性能相近的通用场景
leastconn 最少连接数优先 长连接场景(WebSocket、数据库)
source 源 IP 哈希 需要会话保持的场景
uri URI 哈希 缓存服务
random 随机分配 无状态 API 服务

如果后端节点性能不一致,可以搭配

1
weight

参数:


1
2
3
backend web_app
    balance leastconn
    server-template web 5 _http._tcp.web-app.service.dc1.consul check weight 100

6.2 连接优化与内核参数调优

高并发场景下,系统内核参数的调优与 HAProxy 同等重要。在两台 LB 节点上修改

1
/etc/sysctl.conf


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# TCP 连接队列
net.core.somaxconn = 65535
net.core.netdev_max_backlog = 65535
net.ipv4.tcp_max_syn_backlog = 65535

# TCP 缓冲区
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# TIME_WAIT 优化
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15

# 允许绑定非本地 IP(Keepalived 需要此选项启动前绑定 VIP)
net.ipv4.ip_nonlocal_bind = 1

# TCP 保活
net.ipv4.tcp_keepalive_time = 600
net.ipv4.tcp_keepalive_intvl = 30
net.ipv4.tcp_keepalive_probes = 3

# 连接跟踪表大小
net.netfilter.nf_conntrack_max = 1048576

应用配置:


1
sudo sysctl -p

6.3 HAProxy 连接速率限制

防止突发流量压垮后端,在 HAProxy 中配置连接速率限制:


1
2
3
4
5
6
7
8
9
10
11
12
frontend http_in
    bind *:80

    # 每个源 IP 最大 20 并发连接
    stick-table type ip size 100k expire 30s store conn_rate(10s)
    http-request track-sc0 src
    http-request deny deny_status 429 if { sc_conn_rate(0) gt 100 }

    # 全局最大并发连接数
    maxconn 20000

    default_backend web_app

七、故障测试与验证

7.1 验证 VIP 漂移

在 LB-Master 上手动停止 HAProxy,观察 VIP 是否自动迁移:


1
2
3
4
5
6
7
8
9
10
# 在 LB-Master 上执行
sudo systemctl stop haproxy

# 在 LB-Backup 上查看 IP 地址
ip addr show eth0 | grep 10.0.0.100
# 应该能看到 VIP 已经漂移到 Backup 节点

# 在 LB-Backup 上查看 Keepalived 日志
journalctl -u keepalived -f
# 预期输出:Entering MASTER STATE

7.2 验证后端故障自动剔除


1
2
3
4
5
6
7
8
9
10
# 在某个后端节点停止服务
sudo systemctl stop your-web-app

# 在 HAProxy 统计页面观察
# http://10.0.0.100:8404/stats
# 对应的后端服务器状态应变为 DOWN

# 恢复服务后
sudo systemctl start your-web-app
# 状态自动恢复为 UP

7.3 验证 Consul 服务发现


1
2
3
4
5
6
7
8
# 添加新的后端节点
# 1. 在新节点上启动 Consul Client + Web 服务
# 2. 在 Consul 中注册服务
consul catalog services
# 应能看到 web-app 服务

# 3. 在 HAProxy Stats 页面确认新节点出现
# HAProxy 无需重载,新节点自动被纳入负载均衡池

7.4 模拟整机宕机

最极端的测试——直接关掉主节点:


1
2
3
4
5
6
7
8
9
10
11
12
# 在 LB-Master 上执行(谨慎!)
sudo shutdown -h now

# 在客户端持续请求测试
while true; do
    curl -s -o /dev/null -w '%{http_code}\n' http://10.0.0.100/health
    sleep 0.5
done

# 预期结果:
# 200 → 200 → 200 → (短暂中断 < 3秒) → 200 → 200
# Keepalived 检测到 Master 不可用,Backup 在 3 秒内接管

八、监控与告警体系

8.1 HAProxy 指标导出

使用

1
haproxy_exporter

将 HAProxy 统计数据导出为 Prometheus 格式:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 安装 haproxy_exporter
wget https://github.com/prometheus/haproxy_exporter/releases/download/v0.15.0/haproxy_exporter-0.15.0.linux-amd64.tar.gz
tar xzf haproxy_exporter-0.15.0.linux-amd64.tar.gz
sudo cp haproxy_exporter-0.15.0.linux-amd64/haproxy_exporter /usr/local/bin/

# 创建 systemd 服务
cat > /etc/systemd/system/haproxy-exporter.service << 'EOF'
[Unit]
Description=HAProxy Exporter
After=network.target

[Service]
ExecStart=/usr/local/bin/haproxy_exporter \
    --haproxy.scrape-uri=http://127.0.0.1:8404/stats;csv \
    --web.listen-address=:9101
Restart=always

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now haproxy-exporter

8.2 Consul 健康检查监控

Consul 自带健康检查 API,可以直接查询集群整体健康状况:


1
2
3
4
5
6
7
8
9
10
11
# 查看所有不健康的服务
consul health service web-app --passing=false

# 输出示例:
# Node       ID        Name              Status
# backend-2  web-app   web-app           critical

# 通过 API 查询(适合集成到监控脚本)
curl -s http://127.0.0.1:8500/v1/health/service/web-app?passing | \
    python3 -m json.tool | grep -c '"Status": "passing"'
# 返回健康实例数量

8.3 关键告警规则

以下是推荐配置的 Prometheus 告警规则:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
groups:
- name: haproxy
  rules:
  - alert: HAProxyBackendDown
    expr: haproxy_server_status{state="DOWN"} > 0
    for: 2m
    labels:
      severity: critical
    annotations:
      summary: "HAProxy backend {{ $labels.server }} is DOWN"

  - alert: HAProxyHighErrorRate
    expr: rate(haproxy_server_response_errors_total[5m]) / rate(haproxy_server_responses_total[5m]) > 0.05
    for: 5m
    labels:
      severity: warning
    annotations:
      summary: "HAProxy backend {{ $labels.server }} error rate exceeds 5%"

  - alert: HAProxyHighQueue
    expr: haproxy_server_current_queue > 100
    for: 3m
    labels:
      severity: warning
    annotations:
      summary: "HAProxy server {{ $labels.server }} queue exceeds 100"

- name: keepalived
  rules:
  - alert: KeepalivedStateChange
    expr: keepalived_vrrp_state != 2
    for: 1m
    labels:
      severity: critical
    annotations:
      summary: "Keepalived VRRP instance {{ $labels.instance }} is not MASTER"

- name: consul
  rules:
  - alert: ConsulServiceCritical
    expr: consul_health_service_status{status="critical"} > 0
    for: 3m
    labels:
      severity: critical
    annotations:
      summary: "Consul service {{ $labels.service_name }} is critical on {{ $labels.node }}"

九、常见问题与排错指南

9.1 VIP 无法漂移

最常见的排查步骤:


1
2
3
4
5
6
7
8
9
10
11
# 1. 检查防火墙是否放行 VRRP 协议(IP 协议号 112)
sudo iptables -A INPUT -p 112 -j ACCEPT

# 2. 检查 Keepalived 日志
journalctl -u keepalived --since '10 minutes ago'

# 3. 确认两端配置的 virtual_router_id 和 auth_pass 完全一致

# 4. 确认 ip_nonlocal_bind 已启用
cat /proc/sys/net/ipv4/ip_nonlocal_bind
# 应输出 1

9.2 HAProxy 无法解析 Consul 服务


1
2
3
4
5
6
# 手动测试 Consul DNS 解析
dig @10.0.0.21 -p 8600 web-app.service.dc1.consul SRV

# 预期返回 SRV 记录,包含后端 IP 和端口
# 如果返回空结果,检查 Consul 中服务是否注册成功:
consul catalog services

9.3 后端节点频繁上下线

如果后端节点在 HAProxy 统计页面上频繁闪烁 UP/DOWN,通常是健康检查超时导致。调整参数:


1
2
3
backend web_app
    # 增加健康检查间隔和超时时间
    default-server inter 10s fall 5 rise 3 timeout check 5s

同时在 Consul 侧也调整检查间隔:


1
2
3
4
5
"check": {
    "interval": "15s",
    "timeout": "5s",
    "deregister_critical_service_after": "60s"
}

十、总结

通过 HAProxy + Keepalived + Consul 的组合,我们构建了一个具备以下能力的高可用负载均衡集群:

  • 入口高可用:Keepalived 通过 VIP 漂移实现秒级故障切换,客户端无感知
  • 后端高可用:HAProxy 的健康检查 + Consul 的服务发现实现故障自动剔除和自动纳管
  • 水平扩展:新后端节点上线后自动加入负载均衡池,无需任何人工干预
  • 可观测性:通过 Prometheus + Grafana 实现全链路监控和告警

这套架构的运维成本并不高——大部分组件开箱即用,且故障自愈能力很强。对于正在从单机架构向集群架构演进的团队来说,这是一个经过大规模生产验证的方案,值得在实际项目中落地。

下一步的演进方向可以考虑:引入 Consul Connect 实现服务网格(mTLS 加密)、添加 HAProxy Data Plane API 实现更灵活的配置管理、以及结合 GitOps 实现配置版本化与自动化部署。

【本站文章皆为原创,未经允许不得转载】:汤不热吧 » VPS搭建高可用负载均衡集群:HAProxy + Keepalived + Consul 实战指南
分享到: 更多 (0)