当 HTTP/3(QUIC over UDP)遇上经典的 LVS DR + Nginx 负载均衡架构,有些坑你不踩一遍根本想不到。

架构概览

                         ┌─────────────────────────────┐
                         │        客户端                │
                         │   (Chrome / Firefox / curl)  │
                         └──────────┬──────────────────┘
                                    │
                     ┌──────────────┼──────────────┐
                     │              │              │
                  TCP 80        TCP 443        UDP 443
                (HTTP)        (HTTPS/H2)      (QUIC/H3)
                     │              │              │
                     ▼              ▼              ▼
              ┌──────────────────────────────────────┐
              │         Keepalived + LVS-DR          │
              │      VIP: 192.168.5.5                │
              │   lb_kind DR  |  protocol TCP/UDP    │
              └──────────────┬───────────────────────┘
                             │
                 ┌───────────┴───────────┐
                 │                       │
                 ▼                       ▼
        ┌──────────────┐        ┌──────────────┐
        │  Nginx-01    │        │  Nginx-02    │
        │  192.168.5.8 │        │  192.168.5.9 │
        │  HTTP/1.1    │        │  HTTP/1.1    │
        │  HTTP/2      │        │  HTTP/2      │
        │  HTTP/3 ✓   │        │  HTTP/3 ✓   │
        └──────────────┘        └──────────────┘
                 │                       │
                 └───────────┬───────────┘
                             │
                             ▼
                    ┌────────────────┐
                    │   Backend     │
                    │   Servers     │
                    └────────────────┘

核心链路:客户端 → LVS(VIP)→ Nginx 真实服务器 → 后端应用。HTTP/3 的特殊性在于它跑在 UDP 443 上,而传统的 LVS + Nginx 架构只考虑了 TCP。


一、Keepalived 必须新增 UDP 虚拟服务

问题

HTTP/3 基于 QUIC 协议,运行在 UDP 443 上。如果你的 keepalived 只配了 TCP 80 和 TCP 443 的 virtual_server,UDP 443 的流量根本不会被 LVS 接管——客户端的 HTTP/3 请求会直接绕过 VIP,打到某一台 Nginx 上,导致负载不均甚至不可达。

解决方案

在 keepalived.conf 中新增 UDP 443 的虚拟服务:

# TCP 80 - HTTP
virtual_server 192.168.5.5 80 {
    delay_loop 5
    lb_algo wrr
    lb_kind DR
    protocol TCP
    persistence_timeout 60

    real_server 192.168.5.8 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            retry 2
            delay_before_retry 2
            connect_port 80
        }
    }
    real_server 192.168.5.9 80 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            retry 2
            delay_before_retry 2
            connect_port 80
        }
    }
}

# TCP 443 - HTTPS / HTTP2
virtual_server 192.168.5.5 443 {
    delay_loop 5
    lb_algo wrr
    lb_kind DR
    protocol TCP
    persistence_timeout 60

    real_server 192.168.5.8 443 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            retry 2
            delay_before_retry 2
            connect_port 443
        }
    }
    real_server 192.168.5.9 443 {
        weight 1
        TCP_CHECK {
            connect_timeout 3
            retry 2
            delay_before_retry 2
            connect_port 443
        }
    }
}

# UDP 443 - HTTP3 (QUIC) ← 新增
virtual_server 192.168.5.5 443 {
    delay_loop 5
    lb_algo wrr
    lb_kind DR
    protocol UDP              # ← 关键:UDP
    persistence_timeout 60

    real_server 192.168.5.8 443 {
        weight 1
        UDP_CHECK {           # ← UDP 健康检查(比 TCP 简单)
            connect_timeout 3
        }
    }
    real_server 192.168.5.9 443 {
        weight 1
        UDP_CHECK {
            connect_timeout 3
        }
    }
}

注意事项

  • TCP 443 和 UDP 443 是两个独立的 virtual_server,不能合并。LVS 内部按 (protocol, port) 作为元组区分。
  • lb_kind DR 对 UDP 同样适用,Direct Return 模式不依赖传输层协议。
  • UDP 健康检查能力有限UDP_CHECK 只能做连通性探测(发一个包看有没有回应),不像 TCP_CHECKretrydelay_before_retry 等精细选项。如果 Nginx 的 UDP 443 不可用,LVS 感知到的速度可能比 TCP 慢。
  • 持久化(persistence_timeout):HTTP/3 支持连接迁移(connection migration),客户端可能在 TCP 和 UDP 之间切换。建议两边的 persistence_timeout 保持一致(如 60s),或者根据实际场景调大。

二、Nginx reuseport 冲突

问题

Nginx 开启 HTTP/3 时,配置通常是:

listen 443 ssl;
listen 443 quic reuseport;

如果你有多个 server block(多个域名)都配置了 listen 443 quic reuseportnginx -t 会报错:

nginx: [emerg] duplicate listen options for 0.0.0.0:443

原因

reuseport 是内核的 SO_REUSEPORT 套接字选项,同一个端口只能有一个 socket 持有它。两个 server block 都写 reuseport,等于两个 socket 抢同一个端口的 reuseport,内核拒绝。

解决方案

只有一个 server block 保留 reuseport,其他去掉。 Nginx 会通过 SNI(TLS 握手中的 Server Name Indication)自动路由到正确的 server block。

# 域名 A - 保留 reuseport(主 server block)
server {
    listen 443 ssl;
    listen 443 quic reuseport;    # ← 只有这里用 reuseport
    server_name a.example.com;
    # ...
}

# 域名 B - 去掉 reuseport
server {
    listen 443 ssl;
    listen 443 quic;               # ← 不带 reuseport
    server_name b.example.com;
    # ...
}

流程

客户端 HTTP/3 请求 b.example.com:443/UDP
        │
        ▼
内核收到 UDP 443 包 → 只有 reuseport 的 socket 在收
        │
        ▼
Nginx worker 通过 SNI 解析出 "b.example.com"
        │
        ▼
匹配到域名 B 的 server block → 正常处理

两个域名的 HTTP/3 流量都走同一个 reuseport socket 进来,Nginx 内部按 SNI 分发,不影响功能。


三、防火墙 / 安全组

必须放行的端口

端口协议用途
80TCPHTTP(通常 301 到 HTTPS)
443TCPHTTPS / HTTP/2
443UDPHTTP/3 (QUIC)

很多人只记得开 TCP 443,忘了 UDP 443,导致 HTTP/3 从外网完全不可达。

iptables 示例

# 放行 UDP 443
iptables -A INPUT -p udp --dport 443 -j ACCEPT

# 如果用了 firewalld
firewall-cmd --permanent --add-port=443/udp
firewall-cmd --reload

云厂商安全组

阿里云、腾讯云等云平台的安全组需要同时添加 TCP 443 和 UDP 443 的入站规则。很多人在控制台只加了 TCP,UDP 被默认拒绝。


四、Nginx 完整配置要点

一个同时支持 HTTP/2 和 HTTP/3 的 server block 关键配置:

server {
    # TCP: HTTP/1.1 + HTTP/2
    listen 443 ssl;
    # UDP: HTTP/3 (QUIC) —— 只在第一个 server block 加 reuseport
    listen 443 quic reuseport;

    http2 on;
    http3 on;

    server_name example.com;

    # SSL
    ssl_certificate     /etc/nginx/ssl/example.com.pem;
    ssl_certificate_key /etc/nginx/ssl/example.com.key;
    ssl_protocols TLSv1.2 TLSv1.3;   # QUIC 要求 TLS 1.3
    ssl_prefer_server_ciphers on;
    ssl_session_tickets off;           # 建议关闭,QUIC 自带 0-RTT

    # HTTP/3 通告(告诉浏览器可以用 H3)
    add_header Alt-Svc 'h3=":443"; ma=86400' always;

    # ... 其他配置 ...
}

几个容易忽略的点

  1. QUIC 强制要求 TLS 1.3ssl_protocols 里如果没有 TLSv1.3,HTTP/3 直接不能用。
  2. ssl_session_tickets off:QUIC 的 0-RTT 机制自带会话恢复能力,开启 session tickets 可能导致重放攻击风险。
  3. Alt-Svc 头必须有:这是浏览器发现 HTTP/3 的唯一途径。没有这个头,浏览器会一直用 HTTP/2。
  4. http3 on 可以全局开,也可以单 server block 开:如果只想部分域名开 HTTP/3,就在对应 server block 里单独加。

五、LVS DR 模式的 UDP 转发原理

DR 模式工作流程

1. 客户端发送 UDP 包到 VIP(192.168.5.5:443)
        │
2. LVS Director 收到包,根据调度算法选一台 Real Server
        │
3. Director 将包的目标 MAC 改为 Real Server 的 MAC,目标 IP 保持 VIP 不变
        │
4. Real Server 收到包(因为绑定了 VIP,能识别目标 IP)
        │
5. Real Server 处理后直接回给客户端(不经过 Director)

关键:Real Server 必须绑定 VIP

LVS DR 模式下,Real Server 需要在 lo 接口上绑定 VIP,并配置 ARP 抑制:

# Real Server 上执行(开机自启脚本)
#!/bin/bash
VIP=192.168.5.5

# lo 接口绑定 VIP
ifconfig lo:0 $VIP broadcast $VIP netmask 255.255.255.255 up

# ARP 抑制:不响应 VIP 的 ARP 请求
echo "1" > /proc/sys/net/ipv4/conf/lo/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/lo/arp_announce
echo "1" > /proc/sys/net/ipv4/conf/all/arp_ignore
echo "2" > /proc/sys/net/ipv4/conf/all/arp_announce

注意:这个配置对 TCP 和 UDP 都生效,不需要额外为 UDP 做特殊处理。DR 模式工作在 MAC 层,与传输层协议无关。


六、常见排障清单

现象可能原因排查方法
HTTP/2 正常,HTTP/3 不通UDP 443 未放行nc -u -zv VIP 443 测试 UDP 连通性
HTTP/3 部分域名不通reuseport 冲突检查所有 server block,确保只有一个用 reuseport
LVS 不转发 UDP 流量keepalived 没配 UDP virtual_server检查 ipvsadm -Ln 是否有 UDP 443 条目
浏览器不升级到 HTTP/3缺少 Alt-Svc 响应头curl -I https://example.com 检查响应头
QUIC 连接建立失败TLS 版本不对确认 ssl_protocols 包含 TLSv1.3
LVS 调度不均persistence_timeout 太大减小持久化超时或确认是否需要会话保持
Real Server 收不到包ARP 问题arping -I eth0 VIP 检查 ARP 是否正常

七、性能调优建议

Nginx 侧

# QUIC 连接池大小(影响并发 HTTP/3 连接数)
quic_retry on;                    # 防放大攻击,建议开启

# UDP buffer 调优(高并发场景)
server {
    listen 443 quic reuseport;
    # ...
}

内核侧

# UDP 接收缓冲区(高并发 QUIC 场景)
sysctl -w net.core.rmem_max=8388608
sysctl -w net.core.rmem_default=1048576

# UDP 发送队列
sysctl -w net.core.wmem_max=8388608

# 连接跟踪表(QUIC 连接数多时可能不够)
sysctl -w net.netfilter.nf_conntrack_udp_timeout=30
sysctl -w net.netfilter.nf_conntrack_udp_timeout_stream=120

keepalived 侧

# 缩短 UDP 健康检查间隔(更快感知故障)
virtual_server 192.168.5.5 443 {
    delay_loop 3          # TCP 用 5,UDP 可以更短
    protocol UDP
    # ...
}

八、总结

在 LVS DR + Nginx 架构上启用 HTTP/3,核心就三件事:

  1. Keepalived 加 UDP 虚拟服务——让 LVS 能调度 UDP 443 流量。
  2. Nginx reuseport 只开一次——多域名场景下避免 duplicate listen。
  3. 防火墙放行 UDP 443——最容易忘的一步。

其他都是锦上添花。把这三点做对,HTTP/3 就能在你的架构里跑起来。


写于 2026 年 6 月 15 日,基于实际踩坑经验整理。