相信很多客户都经历过从 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)
本篇作者