故障处理报告
悠悠
2025年11月29日

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

排查过程:

# 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 配置

  • 记录: xxxxx
  • 类型: CNAME
  • : xxxxx.elb.us-east-1.amazonaws.com
  • TTL: 300秒

WebSocket 连接要求

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

测试验证命令

1. 检查目标健康状态

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握手

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解析

dig +short xxxxxxx
nslookup xxxxxxx

4. 检查NLB属性

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

文章目录

博主介绍

热爱技术的云计算运维工程师,Python全栈工程师,分享开发经验与生活感悟。
欢迎关注我的微信公众号@运维躬行录,领取海量学习资料

微信二维码