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连接稳定,需要后端服务添加域名白名单支持自定义域名访问。

相关推荐
4***17541 小时前
Spring Boot整合WebSocket
spring boot·后端·websocket
Macbethad2 小时前
基于WPF的Ethernet/IP主站程序技术方案
网络协议·tcp/ip·wpf
ganshenml3 小时前
【Web】证书(SSL/TLS)与域名之间的关系:完整、通俗、可落地的讲解
前端·网络协议·ssl
q***61413 小时前
Java实战:Spring Boot实现WebSocket实时通信
java·spring boot·websocket
JSON_L4 小时前
Fastadmin中使用rabbitmq实现延迟队列
rabbitmq·php·fastadmin
JienDa4 小时前
JienDa聊PHP:CSDN博客仿站实战中PHP框架的协同架构方略
java·架构·php
xu_yule4 小时前
网络和Linux网络-5(应用层)HTTP协议(方法+报头+状态码)
linux·网络·网络协议·http
xxp43215 小时前
Qt 网络编程 网络下载
网络·qt·php
西幻凌云5 小时前
了解计算机网络的“物理根基”——物理层与数据链路层
网络·网络协议·计算机网络·数据链路层·物理层