亚马逊AWS官方博客

AWS VPC Peering 和 TGW 互相转换过程中出现的丢包问题分析

­­相信很多客户都经历过从 VPC Peering 到 TGW 的转换过程,因为在发展过程中,需要更多的扩展性,支持更多的 VPC 连接,包括传递路由、防火墙控制;同时也有很多客户具有关于核心路由的低延时、高效访问和流量的成本控制需要,从而有从 TGW 到 VPC Peering 的转换需求。但是无论哪种方法,都会在变更配置中,出现在一定时间内存在非对称路由的状态。

变更前: 对称状态下的两种路由方式

变更过程中:两种临时状态

先说结论,只有最后一个场景下(Request 侧为 TGW,Response 侧为 VPC Peering)的非对称路由状态下,会发生超过 MTU 8500 的包丢包。下面是详细解释:

故障现象:只有 MTU 超过 8500 的包会丢,通常是数据库的数据提交,或者应用的大包传递。而类似 ping 和 ssh 访问都完全不会有问题。而 scp 可以用于模拟这个故障现象。如果我们全程用 ping 来观察,是完全不会丢包的。可以用 Ping -s 9000 Target-IP 来进行探测故障现象。

根本原因:VPC Peering Connection 支持的 MTU 是 9001, TGW 接受的 MTU 是 8500,在建立连接协商 MSS 的过程中,TGW 采用的 Clamping 的机制,本身不支持 PMTUD,从而在非对称路由情况下,产生 2 种不同的结果。

非对称路由下从 172.16.8.100 到 172.17.8.100 的访问

基本信息:

  • MSS 协商过程在 TCP 建立连接的 SYN 和 SYN,ACK 阶段。
  • Amazon Linux 默认是 9001 MTU。
  • AWS Transit Gateway 支持最大 8500 MTU; VPC Peering 支持最大 9001 MTU。

我们可以分析一下整个流程:

1:172.16.8.100 上发起访问 TCP 访问到 172.17.8.100,都是 Amazon linux 2023 的系统网卡的 MTU 都是 9001,所以去掉 IP 头部 20 字节,TCP 20 字节,所以就是 9001-40=8961。

2:在通过 TGW 网关后,由于 AWS TGW 的 Clamping 的机制,所以在流经 TGW 的时候,就被直接降低为 8500-40=8460。

3:172.17.8.100 收到 SYN,8460 后,发出了 SYN,ACK MSS=8961,这里不容易理解的是,为什么在已经收到 MSS 为 8460 后,仍然发出 8961 的 MSS 的值,实际上这就是 MSS 的协商机制,代表我能处理的最大的包,不管之前收到的多少。如果是对称情况下,SYN,ACK 过程中,会被 TGW 再次修改为 8460。

4:流经 VPC Peering,由于能处理同等级别的 MTU,所以不会改变任何 MSS 的值。

接下来才是真正问题所在,实例 172.16.8.100 就会认为链路上可以接受 8961 的 MSS,所以再发包的时候,就会以 MSS=8961 的进行发包,当再次流经 TGW 后,就会被 TGW Drop 掉所有超过 8500 的包。

下面佐证上述的抓包信息。

在 172.16.8.100 发起 SCP 传输到 172.17.8.100

在 172.16.8.100 处抓包:

在 172.17.8.100 处抓包:

非对称路由下从 172.16.8.100 到 172.17.8.100 的访问:

在这种场景下,MSS 最后流经 TGW,最后协商 MSS 就会是 8460,再建立连接后,MSS 就会满足所有中间传输过程所有的网关,也就不会有问题了。

如上,在知道了故障原因后,就知道我们如何来避免这个问题,即尽量来减少对称路由持续的时间。

我们迭代了 2 个版本的方式,下面会给大家做一个简单的介绍。最终测试可以做到时间在 2s 以内,而通常这种情况下,不会触发任何警报。

解决方案

方案 1. 采用 AWS CLI,同时对称执行每条命令

这个方案的每个路由表操作清晰,可以很好地保留单条的回滚操作,但是执行时间稍长,取决于实际您的路由表条数。

我们首先确认需要的变更信息表:

Name Route table id Destination VPC CDIR Target Gateway ID Original Gateway
172.16->172.17 A-sin-private-ap-southeast-1a rtb-xxxxxxxa01 172.17.0.0/16 tgw-xxxxxxxxxxxxxxxxx pcx-xxxxxxxxxxxxxxxxx
A-sin-private-ap-southeast-1b rtb-xxxxxxxa02 172.17.0.0/16 tgw-xxxxxxxxxxxxxxxxx pcx-xxxxxxxxxxxxxxxxx
A-sin-private-ap-southeast-1c rtb-xxxxxxxa03 172.17.0.0/16 tgw-xxxxxxxxxxxxxxxxxx pcx-xxxxxxxxxxxxxxxxx
172.17->172.16 B-sin-private-ap-southeast-1a rtb-xxxxxxxb01 172.16.0.0/16 tgw-xxxxxxxxxxxxxxxxx pcx-xxxxxxxxxxxxxxxxx
B-sin-private-ap-southeast-1b rtb-xxxxxxxb02 172.16.0.0/16 tgw-xxxxxxxxxxxxxxxxx pcx-xxxxxxxxxxxxxxxxx
B-sin-private-ap-southeast-1c rtb-xxxxxxxb03 172.16.0.0/16 tgw-xxxxxxxxxxxxxxxxx pcx-xxxxxxxxxxxxxxxxx
172.16:
aws ec2 replace-route --route-table-id rtb-xxxxxxxa01 --destination-cidr-block 172.17.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa02 --destination-cidr-block 172.17.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa03 --destination-cidr-block 172.17.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-A-name


172.17:
aws ec2 replace-route --route-table-id rtb-xxxxxxxb01  --destination-cidr-block 172.16.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-B-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb02  --destination-cidr-block 172.16.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-B-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb03  --destination-cidr-block 172.16.0.0/16 --gateway-id tgw-xxxxxxxxxxxxxx  --profile account-B-name

所以对应的回滚命令:

172.16:
aws ec2 replace-route --route-table-id rtb-xxxxxxxa01 --destination-cidr-block 172.17.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa02 --destination-cidr-block 172.17.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxa03 --destination-cidr-block 172.17.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name

172.17:
aws ec2 replace-route --route-table-id rtb-xxxxxxxb01  --destination-cidr-block 172.16.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb02  --destination-cidr-block 172.16.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name
aws ec2 replace-route --route-table-id rtb-xxxxxxxb03  --destination-cidr-block 172.16.0.0/16 --vpc-peering-connection-id pcx-xxxxxxxxxxxxx  --profile account-A-name

反之亦然。

方案 2. 从指定对称账号下抓取指定 VPC 下所有的路由表,针对目标路由修改网关

迭代为并发调用,可以在 1-2 秒级别完成整个对称操作,从而做到应用无感知的更新。

整体方案仍然是:

A:采集目标信息,Python 脚本,依据目标地址,获取所有匹配的 VPC 下的路由表,输出为 CSV,对比变更内容。

$ python3 getAllRouteTableInfo.py
CSV file 'route_info.csv' has been created with the route information.

$ cat route_info.csv
vpc,route table id,dest vpc cidr,gateway
vpc-0b66cf51703b7d189,rtb-004257d2fe5ab16ab,172.17.0.0/16,tgw-015dbf530ac9fb88c
vpc-0b66cf51703b7d189,rtb-03e8ac66f8c002544,172.17.0.0/16,tgw-015dbf530ac9fb88c
vpc-0b66cf51703b7d189,rtb-0ed6c9acc69963302,172.17.0.0/16,tgw-015dbf530ac9fb88c
vpc-0d1be21c181045b64,rtb-05f7948acdf9149e1,172.16.0.0/16,tgw-015dbf530ac9fb88c
vpc-0d1be21c181045b64,rtb-0c8090b390f805219,172.16.0.0/16,tgw-015dbf530ac9fb88c
vpc-0d1be21c181045b64,rtb-04fd7e3c5c609634b,172.16.0.0/16,tgw-015dbf530ac9fb88c

B:变更脚本,依据目标地址,获取每条记录,并发改匹配的所有路由表网关。程序本身是幂等的,每次可以通过脚步 A 保留执行结果。

$ python3 changRouteTable.py
No matching route found in route table rtb-0d39482f555cd3818 for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a588923eb2883c15 for CIDR 172.17.0.0/16
No matching route found in route table rtb-000b98350ab58a79d for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a16367cfbbb7e4de for CIDR 172.16.0.0/16
Route replaced successfully in route table rtb-04fd7e3c5c619d34b for CIDR 172.16.0.0/16
No matching route found in route table rtb-0aa7e8ec3768dbdb5 for CIDR 172.16.0.0/16
Task completed for route table rtb-04fd7e3c5c609d33b
No matching route found in route table rtb-0bd2d895b5e7a7d1c for CIDR 172.16.0.0/16
Route replaced successfully in route table rtb-05f7948acdf9199e1 for CIDR 172.16.0.0/16
Task completed for route table rtb-05f7948acdf9199e1
Route replaced successfully in route table rtb-0c8090b390f807219 for CIDR 172.16.0.0/16
Task completed for route table rtb-0c8090b390f807219
Route replaced successfully in route table rtb-004257d2fe5ab96ab for CIDR 172.17.0.0/16
Route replaced successfully in route table rtb-0ed6c9acc6996a302 for CIDR 172.17.0.0/16
Task completed for route table rtb-004257d2fe5ab96ab
Task completed for route table rtb-0ed6c9acc6996a302
Route replaced successfully in route table rtb-03e8ac66f8c005544 for CIDR 172.17.0.0/16
Task completed for route table rtb-03e8ac66f8c005544
All tasks completed.

C:回滚脚本, 依据目标地址,获取每条记录,并发改匹配的所有路由表网关。

$ python3 restoreRouteTable.py
No matching route found in route table rtb-0d39482f555cd3818 for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a588923eb2883c15 for CIDR 172.17.0.0/16
No matching route found in route table rtb-000b98350ab58a79d for CIDR 172.17.0.0/16
No matching route found in route table rtb-0a16367cfbbb7e4de for CIDR 172.16.0.0/16
Route replaced successfully in route table rtb-0ed6c9acc6996a312 for CIDR 172.17.0.0/16
No matching route found in route table rtb-0aa7e8ec3768dbdb5 for CIDR 172.16.0.0/16
No matching route found in route table rtb-0bd2d895b5e7a7d1c for CIDR 172.16.0.0/16
Task completed for route table rtb-0ed6c9acc6996a312
Route replaced successfully in route table rtb-04fd7e3c5c609d31b for CIDR 172.16.0.0/16
Task completed for route table rtb-04fd7e3c5c609d31b
Route replaced successfully in route table rtb-004257d2fe5ab96ab for CIDR 172.17.0.0/16
Task completed for route table rtb-004257d2fe5ab96ab
Route replaced successfully in route table rtb-05f7948acdf9199e1 for CIDR 172.16.0.0/16
Task completed for route table rtb-05f7948acdf9199e1
Route replaced successfully in route table rtb-03e8ac66f8c005544 for CIDR 172.17.0.0/16
Task completed for route table rtb-03e8ac66f8c005544
Route replaced successfully in route table rtb-0c8090b390f807219 for CIDR 172.16.0.0/16
Task completed for route table rtb-0c8090b390f807219
All tasks completed.

代码在 Github 的位置如下:

https://github.com/JasonB9527/Route-Table-Changes-Between-TGW-and-VPC-Peering

就在文章发布之际,公司发布了新的特性,目前 TGW 已经支持 PMTUD,以后不会再出现这个异步路由情况下丢包的场景了。

https://aws.amazon.com/about-aws/whats-new/2024/11/aws-transit-gateway-cloud-wan-visibility-metrics-path-mtu/

相关文档

https://docs.aws.amazon.com/vpc/latest/peering/vpc-peering-basics.html (关键字: MTU/MSS)

https://docs.aws.amazon.com/vpc/latest/tgw/transit-gateway-quotas.html (关键字: MSS/Clamping)

https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-mtu.html (关键字: MTU/MSS)

本篇作者

刘佳

亚马逊云科技解决方案架构师,负责基于 AWS 云计算客户方案咨询和架构设计,在金融领域有着多年的数据中心虚拟化解决方案经验。

张乾

亚马逊云科技解决方案架构师,负责基于 AWS 的解决方案咨询和设计,在系统架构设计、应用研发、容器服务、SRE 领域有丰富的实践经验。