NLB WebSocket 连接问题排查与解决方案

问题背景

需要通过Network Load Balancer (NLB) 支持WebSocket连接,但在配置过程中遇到连接失败问题。

环境信息

  • 协议: WebSocket (OCPP 1.6)
  • 后端服务端口: 9521
  • NLB监听端口: 80

NLB 创建步骤(AWS 控制台)

1. 创建目标组

  1. 进入 EC2 控制台 → 左侧菜单 目标组 (Target Groups)
  2. 点击 创建目标组 (Create target group)
  3. 配置基本信息:
    • 目标类型: 实例 (Instances)
    • 目标组名称 : xxx-nlb-tg
    • 协议: TCP
    • 端口: 9521 ⚠️ 注意:必须是后端服务实际监听的端口
    • VPC : 选择 vpc
    • 协议版本: 默认
  4. 配置健康检查:
    • 健康检查协议: TCP ⚠️ 重要:WebSocket服务器使用TCP检查
    • 健康检查间隔: 30秒
    • 健康阈值: 3
    • 不健康阈值: 3
  5. 点击 下一步 (Next)
  6. 注册目标:
    • 选择实例
    • 端口: 9521
    • 点击 包含为待处理项 (Include as pending below)
  7. 点击 创建目标组 (Create target group)

2. 创建 Network Load Balancer

  1. 进入 EC2 控制台 → 左侧菜单 负载均衡器 (Load Balancers)
  2. 点击 创建负载均衡器 (Create load balancer)
  3. 选择 Network Load Balancer → 点击 创建 (Create)
  4. 基本配置:
    • 负载均衡器名称 : test-nlb
    • 方案: 面向互联网 (Internet-facing)
    • IP地址类型: IPv4
  5. 网络映射:
    • VPC : 选择 vpc-xxxxxx
    • 可用区 :
      • ✅ us-east-1d → 子网 subnet-xxxx
      • ✅ us-east-1e → 子网 subnet-0xxxxxf18
  6. 监听器和路由:
    • 协议: TCP
    • 端口 : 80
    • 默认操作: 转发至目标组 xxxx-tg`
  7. 点击 创建负载均衡器 (Create load balancer)
  8. 记录生成的 DNS名称 : xxx-4xxxxxeast-1.amazonaws.com

3. 启用跨可用区负载均衡 ⚠️ 重要

  1. 选择刚创建的 NLB xxxx-nlb
  2. 点击 属性 (Attributes) 标签
  3. 点击 编辑 (Edit)
  4. 找到 跨可用区负载均衡 (Cross-zone load balancing)
  5. 选择 开启 (On)
  6. 点击 保存更改 (Save changes)

说明: 如果后端实例只部署在一个可用区,必须启用此选项,否则会导致50%的连接失败

4. 配置 Route53 DNS 解析

  1. 进入 Route 53 控制台托管区域 (Hosted zones)
  2. 选择域名 xxxxxx
  3. 点击 创建记录 (Create record)
  4. 配置记录:
    • 记录名称: xxxx
    • 记录类型: CNAME
    • : xxxxxxx.amazonaws.com`
    • TTL: 300秒
    • 路由策略: 简单路由
  5. 点击 创建记录 (Create records)

5. 验证配置

  1. 进入目标组 xxxnlb-tg` → 目标 (Targets) 标签
  2. 确认目标状态为 healthy (可能需要等待1-2分钟)
  3. 如果状态为 initialunhealthy ,检查:
    • 端口是否正确
    • 健康检查协议是否为 TCP
    • 实例安全组是否允许端口

问题排查过程

问题 1: 端口配置错误

现象: 目标健康检查失败,WebSocket连接超时

原因:

  • 目标组配置端口为 9520
  • 实际后端服务监听端口为 9521

解决方案(控制台操作):

  1. 进入 EC2 控制台目标组 → 选择 xxx-tg
  2. 点击 目标 (Targets) 标签
  3. 选中错误端口的目标 → 点击 注销 (Deregister)
  4. 点击 注册目标 (Register targets)
  5. 选择实例 i-xxxx
  6. 端口覆盖 : 输入 9521
  7. 点击 包含为待处理项注册待处理目标

问题 2: 健康检查失败

现象 : 目标状态一直为 initial,无法变为 healthy

原因:

  • 9521端口是纯WebSocket服务器
  • HTTP健康检查路径 /asdsadasg 返回 404
  • 响应: 404 WebSocket Upgrade Failure

解决方案(控制台操作): 修改为TCP健康检查

  1. 进入 EC2 控制台目标组 → 选择 xxxxnlb-tg
  2. 点击 健康检查 (Health checks) 标签
  3. 点击 编辑 (Edit)
  4. 修改配置:
    • 健康检查协议 : 选择 TCP
    • 删除健康检查路径(TCP不需要)
  5. 点击 保存更改 (Save changes)
  6. 等待30-60秒,目标状态应变为 healthy

验证:

  • 在目标组的 目标 (Targets) 标签查看状态
  • 状态应显示为 healthy 且带绿色图标

问题 3: 跨可用区连接不稳定

现象:

  • NLB有两个IP地址 (x.x.x.x, a.a.a.a)
  • 其中一个IP连接超时
  • 连接成功率约50%

原因:

  • NLB部署在2个可用区 (us-east-1d, us-east-1e)
  • 后端实例只在 us-east-1d
  • 跨可用区负载均衡未启用
  • 流量路由到 us-east-1e 时无本地目标

解决方案(控制台操作): 启用跨可用区负载均衡

  1. 进入 EC2 控制台负载均衡器 → 选择 xxxx-nlb`
  2. 点击 属性 (Attributes) 标签
  3. 点击 编辑 (Edit) 按钮
  4. 找到 跨可用区负载均衡 (Cross-zone load balancing) 部分
  5. 选择 开启 (On)
  6. 点击 保存更改 (Save changes)
  7. 等待1-2分钟配置生效

验证:

  • 在负载均衡器的 属性 标签确认 "跨可用区负载均衡" 显示为 已启用
  • 多次测试连接,成功率应达到100%

注意: 跨可用区流量会产生数据传输费用 (~$0.01/GB)

问题 4: 域名连接失败 (根本原因)

现象:

  • 直接使用NLB DNS可以连接: ws://xxxxxx.amazonaws.com/dqwdwqd
  • 使用自定义域名连接失败: ws://xxxxxxx/dqwdwqd
  • 错误: Connection reset by peer

排查过程:

bash 复制代码
# 1. 验证DNS解析正确
nslookup xxxxxxx
# 输出: 正确解析到 NLB 的两个IP

# 2. 测试直接IP连接(带Host头)
curl -H "Host: xxxxxxx" \
     -H "Connection: Upgrade" \
     -H "Upgrade: websocket" \
     -H "Sec-WebSocket-Version: 13" \
     -H "Sec-WebSocket-Key: test" \
     -H "Sec-WebSocket-Protocol: ocpp1.6" \
     http://x.x.x.x/dasdwq
# 结果: Connection reset by peer

# 3. 测试直接IP连接(不带自定义Host头)
curl -H "Connection: Upgrade" \
     -H "Upgrade: websocket" \
     -H "Sec-WebSocket-Version: 13" \
     -H "Sec-WebSocket-Key: test" \
     -H "Sec-WebSocket-Protocol: ocpp1.6" \
     http://x.x.x.x/dasdwq
# 结果: HTTP/1.1 101 Web Socket Protocol Handshake ✅

根本原因 :

后端WebSocket服务器对Host头进行了验证,拒绝了 xxxx 域名的请求

解决方案 :

修改后端WebSocket服务器配置,将 xxxxx 添加到允许的域名白名单中


最终配置总结

NLB 配置

  • 名称: iot-nlb
  • 类型: Network Load Balancer
  • 监听器: TCP 80
  • 目标组: iot-nlb-tg
  • 目标端口: 9521
  • 健康检查: TCP (端口9521)
  • 跨可用区: 已启用

DNS 配置

WebSocket 连接要求

  • 协议: ws:// (端口80)
  • 必需请求头 : Sec-WebSocket-Protocol: ocpp1.6
  • Host头: 需要后端服务器允许自定义域名

测试验证命令

1. 检查目标健康状态

bash 复制代码
aws elbv2 describe-target-health \
  --target-group-arn xxxxxx \
  --region us-east-1 \
  --query 'TargetHealthDescriptions[*].[Target.Id,Target.Port,TargetHealth.State]' \
  --output table

2. 测试WebSocket握手

bash 复制代码
curl -i --max-time 3 \
  -H "Connection: Upgrade" \
  -H "Upgrade: websocket" \
  -H "Sec-WebSocket-Version: 13" \
  -H "Sec-WebSocket-Key: test" \
  -H "Sec-WebSocket-Protocol: ocpp1.6" \
  http://xxxxxx.elb.us-east-1.amazonaws.com/asdasds

期望输出: HTTP/1.1 101 Web Socket Protocol Handshake

3. 验证DNS解析

bash 复制代码
dig +short xxxxxxx
nslookup xxxxxxx

4. 检查NLB属性

bash 复制代码
aws elbv2 describe-load-balancer-attributes \
  --load-balancer-arn xxxxxxxx \
  --region us-east-1 \
  --query 'Attributes[?Key==`load_balancing.cross_zone.enabled`]'

常见问题与解决方案

Q1: WebSocket连接超时

检查清单:

  1. 目标健康状态是否为 healthy
  2. 安全组是否允许目标端口入站流量
  3. 后端服务是否正常运行
  4. 端口配置是否正确

Q2: 连接成功率不稳定

可能原因:

  • 跨可用区负载均衡未启用
  • 目标实例分布不均

解决: 启用跨可用区负载均衡或在所有可用区部署实例

Q3: 域名无法连接但直接DNS可以

排查步骤:

  1. 验证DNS解析是否正确
  2. 清除本地DNS缓存
  3. 检查后端服务Host头验证逻辑
  4. 测试带/不带Host头的连接差异

Q4: 健康检查失败

WebSocket服务器特殊处理:

  • 纯WebSocket服务器可能不支持HTTP健康检查
  • 使用TCP健康检查替代
  • 或在后端实现专门的健康检查端点

总结

本次排查解决了以下关键问题:

  1. ✅ 端口配置错误 (9520 → 9521)
  2. ✅ 健康检查协议不匹配 (HTTP → TCP)
  3. ✅ 跨可用区负载均衡未启用
  4. ✅ 后端服务Host头验证限制

最终状态: NLB配置正常,WebSocket连接稳定,需要后端服务添加域名白名单支持自定义域名访问。

相关推荐
BingoGo1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php
JaguarJack1 天前
当你的 PHP 应用的 API 没有限流时会发生什么?
后端·php·服务端
BingoGo2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php
JaguarJack2 天前
OpenSwoole 26.2.0 发布:支持 PHP 8.5、io_uring 后端及协程调试改进
后端·php·服务端
Jony_3 天前
高可用移动网络连接
网络协议
chilix3 天前
Linux 跨网段路由转发配置
网络协议
JaguarJack3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
后端·php·服务端
BingoGo3 天前
推荐 PHP 属性(Attributes) 简洁读取 API 扩展包
php
JaguarJack4 天前
告别 Laravel 缓慢的 Blade!Livewire Blaze 来了,为你的 Laravel 性能提速
后端·php·laravel
郑州光合科技余经理5 天前
代码展示:PHP搭建海外版外卖系统源码解析
java·开发语言·前端·后端·系统架构·uni-app·php