背景
Ztunnel 是节点级别的 L4 代理,进出 Pod 的所有流量都会由对应 Node 的Ztunnel 处理,执行 mTLS 加解密以及身份认证后再转发到实际的 Pod 中。如果目标服务存在 Waypoint 代理的话,Ztunnel 也会将流量转发给对应的 Waypoint,由 Waypoint 进行更进一步的处理。典型的 Ambient 流量路径如下图所示:
图片来自ASM官网文档:如何选择适合您的数据面模式_服务网格-阿里云帮助中心[1]
原理解释
Ztunnel 的最高要求就是最小化流量中断。
然而,4 层是一个很特殊的位置:
- TCP 是有状态的,因此不能简单的将状态传递给其他进程。
- Ztunnel 不会执行 7 层操作,所以无法通知应用:请连接到新的 Ztunnel。
在这样的限制下,目前 Ztunnel 可以做到以下两点,尽可能的保证流量无损:
- 确保在任何时间,任何新建的连接都会成功。从来不会丢弃一个新建的连接。
- 给老的 Ztunnel 留一段可以继续处理已有连接的时间。
Ztunnel滚动流程
利用 Linux 的底层 API,我们可以实现两个进程在同一个端口开启监听,Ztunnel 的滚动过程正是利用了这一点。具体的滚动流程如下:
- 新的 Ztunnel 启动。
- ASM CNI 组件将当前 node 上所有 pod 的状态发送给新的 Ztunnel。Ztunnel为每个运行在当前 node 上的 pod 创建监听,然后将自己标记为“ready”。
- 此时有两个 Ztunnel 在运行,新建的连接将会被分配到其中之一。
- 短暂等待之后,Kubernetes 开始停止老的 Ztunnel。这个是通过发送一个SIGTERM 信号实现的。Ztunnel 会捕获这个信号,然后开始排水。
- 开始排水后,老的 Ztunnel 就会关闭自己所有的监听。此时只有新的 Ztunnel 在监听。请注意,这样做确保了任何时候至少有一个 Ztunnel 在监听。
- 此时老的 Ztunnel 不再接受新的连接,它还是会继续处理已有连接。
- 在排水超时后,老的 Ztunnel 会强制终止所有未停止的连接。
此时下线过程结束。
一定程度的优雅下线
由于 Ztunnel 工作在 4 层,无法像 HTTP/gRPC 一样实现高级的优雅下线。但是只要配置合适的优雅下线时间,依然可以很大程度减少重启对业务的影响。
如果客户端确实无限长时间的使用一个 TCP 连接,那这种中断是不可避免的。
但是幸运的是,大部分协议都支持配置最大连接时间,并且不会过度依赖 TCP 连接不中断。
下面我们将通过实际的压测来展示 Ztunnel 优雅下线的效果。
模拟测试
这里我们演示了一个典型场景:客户端访问 ASM 网关,ASM 网关访问 httpbin服务。httpbin 服务已经开启了 Ambient,所有进入 httpbin 服务的流量都会经过 Ztunnel。
测试 Client 在集群内,且未开启 Ambient。Client 使用 ClusterIP 访问 ASM网关,减少其他网络因素影响。
1.未开启优雅下线
fortio load -qps 0 -c 1000 -t 60s -timeout 10s istio-ingressgateway.istio-system/status/418 Code 418 : 289965 (100.0 %) Code 503 : 5 (0.0 %) All done 289970 calls (plus 1000 warmup) 208.285 ms avg, 4700.8 qps
fortio load -qps 0 -c 100 -t 60s -timeout 10s istio-ingressgateway.istio-system/status/418 Code 418 : 297514 (100.0 %) Code 503 : 4 (0.0 %) All done 297518 calls (plus 100 warmup) 20.180 ms avg, 4946.8 qps
2.设置优雅下线时长 120s
为了确保测试时长覆盖 Ztunnel 的启动范围,此处延长了测试间隔。
fortio load -qps 0 -c 1000 -t 200s -timeout 10s istio-ingressgateway.istio-system/status/418 Code 418 : 961124 (100.0 %) Code 503 : 2 (0.0 %) All done 961126 calls (plus 1000 warmup) 208.484 ms avg, 4766.9 qps
fortio load -qps 0 -c 100 -t 200s -timeout 10s istio-ingressgateway.istio-system/status/418 Code 418 : 960527 (100.0 %) Code 503 : 1 (0.0 %) All done 960528 calls (plus 100 warmup) 20.825 ms avg, 4799.2 qps
结果分析
说明:本文中由于 503 的数量实在太少,都是个位数。所以上面的对比均进行了多次。
开启优雅下线之前,失败的请求数都集中在 4~6 个。
开启优雅下线之后,失败请求数只有 1~2 个。
本文的测试比较简单,但是仍然可以配置优雅下线之后 503 有明显减少。从以上结果可以看出:
- 长 TCP 连接的中断不可避免。但是由于 Ztunnel 启动的特殊设计,任何时候都可以建连成功,所以受影响的请求很少。在我们高并发测试的情况下,只有个位数的请求受到了影响。
- 对于有限长的 TCP 连接,通过合理的配置优雅下线时间,可以显著减少流量中断影响。我们为 Ztunnel 配置 120s 优雅下线时间后,失败的请求数有显著下降。
最佳实践
如果您的业务对于 TCP 中断十分敏感,我们建议您遵从以下最佳实践:
- 业务主动配置类似 maxConnectionAge、maxConnectionDuration 之类的参数。因为即使不加入网格,越长时间的 TCP 连接中断的风险也越高。配置之后您可以很好的和 Ztunnel 配合做到无损升级。
- 启用 ASM Ambient 模式之后,Ztunnel 有开箱即用的可观测能力,您可以通过对 Ztunnel 日志进行分析,获取到您所有 TCP 连接的 Duration,然后将其配置为 Ztunnel 优雅下线时间即可。本文测试时选取的优雅下线时间就是根据Ztunnel 日志中的连接 Duration 得出。
本次测试的场景中,您可以在网关上通过 DestinationRule 为 httpbin 服务配置 maxConnectionDuration,理论上可完全规避流量中断。
总结
在 ASM 1.25 版本中,Ambient 模式的核心能力已经稳定,并且良好的适配了阿里云容器服务环境,期待您的使用与反馈。
ASM 官方文档:如何选择适合您的数据面模式_服务网格-阿里云帮助中心[1]
参考文档: