数据测试 一次 MTU 问题导致的 RDS 访问故障

京东云开发者 · 2022年11月28日 · 2314 次阅读

导语

VPN 是一种通过公网连接两个或多个私网站点的专用网络,使得这些站点仿佛是通过专线连接在一起。IPSec 是一套协议框架,用于保证数据传输的私密性,完整性,真实性。但是 VPN 网络经常会带来一些连通性上的问题,通常与 MTU 设置的不合理有关。本文通过一个实际案例,来具体分析解决这个问题。

作者:陆信宇

一、环境拓扑

  1. 链路中,各个设备接口的 MTU 为 1450

    MTU 是数据链路层的概念,限制的是数据链路层 payload 的大小,即上层协议大小 (包括上层协议头),例如设置主机接口 mtu 为 1450。则在一个 TCP 报文中,1450 = 20 字节 IP 头 + 20 字节 TCP 头 + 1410TCP 数据。

  2. RDS 为京东智联云云数据库实例,实例中创建有 400 个数据库。

  3. SH_MariaDB_VM 是一台上海地域的云主机,部署了 mariadb 服务,数据和 RDS 实例相同。

  4. BJ_VPNGW 和 SH_VPNGW 分别是北京 VPC 和上海 VPC 的 vpn 网关

  5. bj_client 所在子网和 RDS 所在子网通信时,下一跳为各自所在地域的 vpn 网关

二、现象描述

  1. bj_client 通过 BJ_VPNGW 连接 RDS。执行 show databases 时,一直卡住无返回。

  2. bj_client 通过 BJ_VPNGW 连接 SH_MariaDB_VM。执行 show databases 正常,没有卡住的现象。

三、排查过程

  1. bj_client 可以 ping 通 RDS,telnet RDS 3306 端口正常,使用 mysql 客户端也可以正常连接。

  2. 在 BJ_VPNGW 和 SH_VPNGW 上抓包分析。发现 RDS 回包正常到达 SH_VPNGW,但是没有到达 BJ_VPNGW。数据包在 SH_VPNGW 被丢弃。怀疑是 MTU 问题,导致丢包。

  3. 继续抓包分析 RDS 和 SH_MariaDB_VM 回包的区别。发现 SH_VPNGW 都给 RDS 和 SH_MariaDB_VM 回了一个 IMCP Error 报文,报文中指定了MTU next hop: 1374。但是 RDS 的重传报文中,ip 层的 Total Length 一直是 1450。SH_MariaDB_VM 在首次被丢包后,重传报文的 Total Length 为 1374。判断 ICMP Error 报文没有被正常转发给 RDS 服务端。后核实 RDS 前面还有一层 LB,该 LB 没有转发 ICMP Error。

  4. 调整 bj_client 接口 mtu 为 1374 之后,问题解决。

四、问题原因

由于 bj_client、RDS、SH_MariaDB_VM 的 mtu 都是 1450,所以 bj_client 与 RDS、SH_MariaDB_VM 进行 TCP 三次握手时,协商的 MSS 大小为 1410(MTU - 20B ip 头 - 20B tcp 头)。即后续发送的 TCP 报文的数据部分,最大不能超过 1410 字节,且 IP 头中 DF 置位,不允许报文分片。

bj_client 连接 RDS 执行 show databases 命令。由于请求包较小,所以请求报文可以正常通过 vpn 网关到达 RDS。RDS 收到报文后开始响应。由于 RDS 中数据库很多,所以响应报文会拆分成多个进行发送,每个报文的 TCP 数据部分是 1410 字节。报文到达 VPN 网关后,VPN 网关在原数据包基础上再次封装 ESP、UDP、IP,封装之后的报文大小超过了 VPN 网关出接口的 mtu 值,又因为数据包不允许分片,导致 VPN 网关丢弃报文。VPN 网关丢弃报文之后,会向 RDS 发送一个 ICMP Error,指明 mtu of next hop: 1374 ,告知 RDS 以 1374 为最大 mtu 发包。但是因为 RDS 实例前面还有一层 LB,且这个 LB 不会转发 ICMP Error 报文,导致 ICMP Error 报文并没有到达真正的 RDS 服务端,最终导致 RDS 没有调整数据包大小就直接重传,数据包再次被 vpn 网关丢弃,进入死循环。

五、解决方案

根据以上分析,有三种解决方法。

  1. 调小服务端或者客户端 mtu,让两端在建立三次握手协商 mss 时,以更小的 mss 收发数据。可以设置为 ping 探测的路径 MTU 值。

  2. 在 VPN 网关配置iptables -t mangle -A FORWARD -o eth0 -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu。两端建立三次握手的报文到达 vpn 网关时,修改 MSS 值,使 MSS 自适应 PMTU(Path MTU)

  3. 保证 icmp error 报文可达

六、其他

  1. 什么是 MTU

    MTU 是数据链路层的概念,限制的是数据链路层 payload 的大小,即上层协议大小 (包括上层协议头)

    例如设置主机接口 mtu 为 1450。则在一个 TCP 报文中,1450 = 20 字节 IP 头 + 20 字节 TCP 头 + 1410TCP 数据。

  2. 什么是 MSS

    MSS 最大报文段,是 TCP 中一个选项,用于在 TCP 连接建立时,收发双方协商通信时每一个报文段所能承载的最大数据长度 (注意不包含 TCP 头部大小)

  3. 如何探测路径 MTU 值

    Linux 主机中: 执行ping x.x.x.x -s 1422 -M do,x.x.x.x 是目标地址,-s 指明 icmp 报文的数据部分大小 (不包含 icmp 8 字节头部)。-M do表示不允许分片。多试几次,找到临界点。以 mtu 为 1450 为例,1450 = 20 字节 IP 头 + 8 字节 icmp 头 + 1422 数据,则-s 指定为 1422 可以正常通过

    Windows 主机中: 执行ping x.x.x.x -l 1472 -f,x.x.x.x 是目标地址,-l 指明 icmp 报文的数据部分大小 (不包含 icmp 8 字节头部)。-f 表示不允许分片。

  4. 如何查看 MTU

    Linux: ifconfig

    windows: netsh interface ipv4 show  subinterfaces

  5. 如何设置 MTU

    Linux: ifconfig eth0 mtu xxx

    windows: netsh interface ipv4 set subinterface "WLAN" mtu=1450 store=persistent

暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册