故障排除网络连接
概述
本指南与网络指南相辅相成,重点关注网络连接故障排除。
对于使用 TLS 的连接,还有一份关于 TLS 故障排除的指南。
故障排除方法论
网络连接问题的故障排除是一个广泛的主题。有专门的书籍对此进行阐述。本指南将介绍一种方法论和常用的网络工具,以帮助高效地缩小最常见问题的范围。
网络协议是分层的。它们的问题也是如此。有效的故障排除策略通常采用排除法来定位问题(或多个问题),从较高级别开始。特别是对于消息传递技术,以下步骤通常有效且足够:
- 验证客户端配置
- 验证服务器配置,使用
rabbitmq-diagnostics listeners、rabbitmq-diagnostics status、rabbitmq-diagnostics environment - 检查服务器日志
- 验证主机名解析
- 验证使用的 TCP 端口及其可访问性
- 验证 IP 路由
- 如果需要,捕获并分析流量转储(流量捕获)
- 验证客户端是否成功进行身份验证
这些步骤按顺序执行,通常有助于确定绝大多数网络问题的根本原因。低于互联网(网络)层的故障排除工具和技术超出了本指南的范围。
某些问题仅出现在连接频繁波动的环境中。可以使用管理 UI 来检查客户端连接。还可以检查节点的全部 TCP 连接及其状态。这些收集到的信息,结合服务器日志,将有助于检测连接频繁波动、文件描述符耗尽及相关问题。
验证客户端配置
所有开发人员和运维人员都经历过这种情况:拼写错误、过时值、配置工具问题、公钥和私钥路径混淆等等。第一步是仔细检查应用程序和客户端库配置。
验证服务器配置
验证服务器配置有助于证明 RabbitMQ 正在使用预期的网络相关设置运行。它还验证节点是否实际在运行。以下是建议的步骤:
- 确保节点正在运行,使用
rabbitmq-diagnostics status - 验证配置文件是否放置正确,并且语法/结构正确
- 使用
rabbitmq-diagnostics listeners或rabbitmq-diagnostics status中的listeners部分来检查监听器 - 使用
rabbitmq-diagnostics environment检查有效配置
请注意,在旧版 RabbitMQ 中,status 和 environment 命令仅作为 rabbitmqctl 的一部分提供:rabbitmqctl status 等等。在现代版本中,两个工具都可以用来运行这些命令,但 rabbitmq-diagnostics 是大多数文档指南通常会推荐的。
监听器部分看起来会像这样:
Interface: [::], port: 25672, protocol: clustering, purpose: inter-node and CLI tool communication
Interface: [::], port: 5672, protocol: amqp, purpose: AMQP 0-9-1 and AMQP 1.0
Interface: [::], port: 5671, protocol: amqp/ssl, purpose: AMQP 0-9-1 and AMQP 1.0 over TLS
Interface: [::], port: 15672, protocol: http, purpose: HTTP API
Interface: [::], port: 15671, protocol: https, purpose: HTTP API over TLS (HTTPS)
Interface: [::], port: 1883, protocol: mqtt, purpose: MQTT
在上面的示例中,节点上有 6 个 TCP 监听器:
- 端口
25672上的节点间和 CLI 工具通信 - 用于非 TLS 连接的 AMQP 0-9-1(以及 AMQP 1.0,如果已启用)监听器,端口
5672 - 用于 TLS 启用的连接的 AMQP 0-9-1(以及 AMQP 1.0,如果已启用)监听器,端口
5671 - 端口 15672(HTTP)和 15671(HTTPS)上的 HTTP API 监听器
- 用于非 TLS 连接的 MQTT 监听器,端口 1883
在第二个示例中,节点上有 4 个 TCP 监听器:
- 端口
25672上的节点间和 CLI 工具通信 - 用于非 TLS 连接的 AMQP 0-9-1(以及 AMQP 1.0,如果已启用)监听器,
5672 - 用于 TLS 启用的连接的 AMQP 0-9-1(以及 AMQP 1.0,如果已启用)监听器,
5671 - 端口 15672(仅限 HTTP)上的 HTTP API 监听器
所有监听器都绑定到所有可用的接口。
检查节点使用的 TCP 监听器有助于发现非标准端口配置、应配置但未配置的协议插件(例如 MQTT)、节点仅限于少数网络接口的情况等。如果端口不在监听器列表中,则表示节点无法在该端口上接受任何连接。
检查服务器日志
RabbitMQ 节点会记录关键客户端连接生命周期事件。TCP 连接必须成功建立,并且对等方至少发送 1 字节数据,连接才会被视为(并记录为)已接受。
从这一点开始,连接握手和协商按照所使用的消息传递协议(例如 AMQP 0-9-1、AMQP 1.0 或 MQTT)的规范进行。
如果没有记录任何事件,这意味着没有成功的入站 TCP 连接,或者它们没有发送数据。
主机名解析
应用程序在使用主机名或包含主机名的 URI 连接到 RabbitMQ 时非常普遍。dig 和nslookup 是用于故障排除主机名解析的常用工具。
端口访问
除了主机名解析和 IP 路由问题外,TCP 端口对于外部连接不可访问也是导致客户端连接失败的常见原因。telnet 是一个常用的、非常简单的工具,用于测试到特定主机名和端口的 TCP 连接。
以下示例使用 telnet 连接到主机 localhost 上的端口 5672。在 localhost 上运行着一个具有默认设置的节点,并且没有任何东西阻止访问该端口,因此连接成功。然后输入 12345 并按 Enter。这些数据将通过打开的连接发送到节点。
由于 12345 不是正确的 AMQP 0-9-1 或 AMQP 1.0 协议头,因此服务器关闭了 TCP 连接。
telnet localhost 5672
# => Trying ::1...
# => Connected to localhost.
# => Escape character is '^]'.
12345 # enter this and hit Enter to send
# => AMQP Connection closed by foreign host.
telnet 连接成功后,请使用 Control + ] 然后 Control + D 退出。
以下示例连接到 localhost 上的端口 5673。连接失败(被操作系统拒绝),因为没有进程在该端口上监听。
telnet localhost 5673
# => Trying ::1...
# => telnet: connect to address ::1: Connection refused
# => Trying 127.0.0.1...
# => telnet: connect to address 127.0.0.1: Connection refused
# => telnet: Unable to connect to remote host
telnet 连接失败或超时强烈表明存在代理、负载均衡器或防火墙阻止目标端口上的入站连接。这也可能是由于 RabbitMQ 进程未在目标节点上运行,或使用了非标准端口。这些情况应在仔细检查服务器监听器配置的步骤中排除。
存在大量的防火墙、代理和负载均衡器工具和产品。iptables 是 Linux 和其他类 UNIX 系统上常用的防火墙。网上有大量的 iptables 教程。
可以使用 netstat、ss、lsof 来检查节点的端口、TCP 和 UDP 连接。
以下示例使用 lsof 来显示监听端口 5672 并使用 IPv4 的操作系统进程:
sudo lsof -n -i4TCP:5672 | grep LISTEN
同样,对于使用 IPv6 的程序:
sudo lsof -n -i6TCP:5672 | grep LISTEN
在端口 1883 上:
sudo lsof -n -i4TCP:1883 | grep LISTEN
sudo lsof -n -i6TCP:1883 | grep LISTEN
如果上述命令没有输出,则表示没有本地操作系统进程在该端口上监听。
以下示例使用 ss 来显示监听的 TCP 套接字,这些套接字使用 IPv4 及其操作系统进程:
sudo ss --tcp -f inet --listening --numeric --processes
同样,对于使用 IPv6 的 TCP 套接字:
sudo ss --tcp -f inet6 --listening --numeric --processes
有关 RabbitMQ 及其各种插件使用的端口列表,请参见上文。通常,所有用于外部连接的端口都必须被防火墙和代理允许。
rabbitmq-diagnostics listeners 和 rabbitmq-diagnostics status 可用于列出 RabbitMQ 节点上启用的监听器及其端口。
IP 路由
RabbitMQ 支持的消息传递协议使用 TCP,并需要客户端和 RabbitMQ 主机之间的 IP 路由功能正常。有几种工具和技术可用于验证两个主机之间的 IP 路由。traceroute 和ping 是大多数操作系统可用的两个常用选项。大多数路由表检查工具都是操作系统特定的。
请注意,traceroute 和 ping 都使用ICMP,而 RabbitMQ 客户端库和节点间连接使用 TCP。因此,仅成功运行 ping 并不保证客户端连接成功。
traceroute 和 ping 都有基于 Web 和 GUI 的工具。
捕获流量
可以使用流量捕获来检查、过滤和分析所有网络活动。
tcpdump 及其 GUI 版本 Wireshark 是捕获流量、过滤和分析的行业标准。两者都支持 RabbitMQ 支持的所有协议。有关概述,请参阅使用 Wireshark 处理 RabbitMQ 指南。
TLS 连接
对于使用 TLS 的连接,有一份单独的关于 TLS 故障排除的指南。
采用 TLS 时,重要的是要确保客户端使用正确的端口进行连接(请参阅上面的端口列表),并且它们被指示使用 TLS(执行 TLS 升级)。未配置使用 TLS 的客户端将成功连接到启用了 TLS 的服务器端口,但其连接随后将超时,因为它从未执行服务器预期的 TLS 升级。
连接到未启用 TLS 的端口的已启用 TLS 的客户端将成功连接并尝试执行 TLS 升级,而服务器不期望这样做,这将触发协议解析器异常。此类异常将由服务器记录。
检查连接
可以使用 netstat、ss、lsof 来检查节点的端口、TCP 和 UDP 连接。
以下示例使用 netstat 来列出所有 TCP 连接套接字,无论其状态和接口如何。 IP 地址将显示为数字,而不是解析为域名。程序名称将打印在数字端口值旁边(与协议名称相对)。
sudo netstat --all --numeric --tcp --programs
可以使用这种方式检查入站(客户端、对等节点、CLI 工具)和出站(对等节点、Federation 链接和 Shovels)连接。
rabbitmqctl list_connections、管理 UI 可用于检查更多连接属性,其中一些是 RabbitMQ 或消息传递协议特定的。
- 网络流量流,包括入站和出站
- 使用的消息传递(应用程序级别)协议
- 连接的虚拟主机
- 连接时间
- 用户名
- 通道数
- 客户端库详细信息(名称、版本、功能)
- 有效的 heartbeat 超时
- TLS 详细信息
将管理 UI 或 CLI 工具的连接信息与 netstat 或 ss 的信息结合使用,有助于对行为不当的应用程序、应用程序实例和客户端库进行故障排除。
可以使用 Prometheus 和 Grafana 来收集、聚合和监控大多数相关的连接指标。
检测高连接率
高连接率(在短暂时间内打开和关闭大量连接)可能导致资源耗尽。因此,能够识别这种情况很重要。netstat 和 ss 是检查 TCP 连接最流行的选项。大量处于 TIME_WAIT 状态的连接是高连接率的可能症状。处于非 ESTABLISHED 状态的大量连接也可能是值得调查的症状。
在 RabbitMQ 日志文件中可以找到短暂连接的证据。例如,这是一个持续时间仅为几毫秒的连接的示例:
2018-06-17 16:23:29.851 [info] <0.634.0> accepting AMQP connection <0.634.0> (127.0.0.1:58588 -> 127.0.0.1:5672)
2018-06-17 16:23:29.853 [info] <0.634.0> connection <0.634.0> (127.0.0.1:58588 -> 127.0.0.1:5672): user 'guest' authenticated and granted access to vhost '/'
2018-06-17 16:23:29.855 [info] <0.634.0> closing AMQP connection <0.634.0> (127.0.0.1:58588 -> 127.0.0.1:5672, vhost: '/', user: 'guest')