Ambient 模式是 2022 年在 Istio 中引入的新型无 sidecar 数据平面。当今年 5 月 Ambient 模式 达到 Beta 阶段时,我观察到用户开始试用并运行负载测试,以理解将应用添加到网格后的性能影响。
受到 Quentin Joly 的博客 关于 Istio 在 Ambient 模式下的惊人性能的启发,以及来自社区其他用户有时应用在 Ambient 模式 下稍快的反馈,我决定自己验证这些结果。
我使用了一个拥有 256GB RAM 和每个节点 32 核 CPU 的三节点 Kubernetes 集群。
Istio 使用了一些工具来简化一致性的基准测试。首先,我们使用一个叫做 Fortio 的负载测试工具,它以指定的每秒请求数 (RPS) 运行,记录执行时间的直方图并计算百分位数,例如 P99,即 99% 的请求在此时间内完成。
我们还提供了一个叫做 Bookinfo 的示例应用,其中包括用 Python、Java、Node.js 和 Ruby 编写的微服务。
每个 Bookinfo 部署都有两个副本,这些副本均匀分布在三个工作节点上。使用 pod anti-affinity rule,我确保 Fortio 被放置在与 details 服务不同的节点上。
我从 Istio v1.22.3 版本安装了 Bookinfo 应用。使用 Fortio 工具对单个 Bookinfo 服务(例如 details)或完整的 Bookinfo 应用进行负载驱动,我注意到在将所有服务添加到 ambient 网格后,延迟影响 接近零。大多数时间它们的增加范围在 0-5% 之间,用于平均值或 P90。我一致注意到 Istio 的 details 服务在 ambient 模式下稍微快一点,就像 Quentin 在他的博客中报告的那样。
我进行了与 Quentin 相同的测试,通过 10 个连接发送 100 RPS 到 details 服务,并收集了无网格和 ambient 的结果。
就像 Quentin 一样,我不得不进行多次测试以验证 ambient 模式比无网格模式略有性能提升——这很难让人相信!对于 Bookinfo 的 details 服务来说,加入 ambient 模式平均降低了 6-11% 的延迟——以及添加了 mTLS 和 L4 观测!
Fortio 对 details | 平均 | P50 | P75 | P90 | P99 | 差异 |
---|---|---|---|---|---|---|
无网格运行 1 | 0.89ms | 0.64ms | 0.74ms | 0.85ms | 2.67ms | 平均慢 11%,P90 慢 5% |
Ambient 运行 1 | 0.80ms | 0.6ms | 0.71ms | 0.81ms | 1.4ms | |
无网格运行 2 | 0.86ms | 0.65ms | 0.75ms | 0.86ms | 1.71ms | 平均慢 6%,P90 慢 4% |
Ambient 运行 2 | 0.81ms | 0.61ms | 0.72ms | 0.83ms | 1.56ms | |
无网格运行 3 | 0.90ms | 0.65ms | 0.76ms | 0.88ms | 1.92ms | 平均慢 10%,P90 慢 5% |
Ambient 运行 3 | 0.82ms | 0.63ms | 0.72ms | 0.84ms | 1.5ms |
表 1: Fortio 对 details 服务 100 RPS 10 连接。
我们被教导说服务网格会增加延迟。Quentin 的结果,这里复制的结果,展示了一个工作负载在通过服务网格运行时更快的案例。这是怎么回事?
当您的应用位于 ambient 模式 中时,负载请求首先通过一个轻量级的本地节点代理叫做 ztunnel,然后传送到目的地 ztunnel,再向服务传送。details 服务使用带有 Webrick 库的 HTTP/1.1,我们已经看到旧的或配置不良的 HTTP 库中存在连接管理和保持活动状态的行为不佳。我的第一个假设是,当客户端和服务器位于不同节点时,通过客户端和服务器 ztunnels 代理实际上可能更快,如果应用没有使用高效的 HTTP/2 连接的话。Ztunnel 使用连接池和 HTTP Connect 建立节点之间的安全通道,以在负载下利用并行性和 HTTP/2 流多路复用。
然而,这个理论有一些挑战。为什么我只在 details 服务上一致观察到这个,而不是任何其他 Bookinfo 服务?
进一步研究,我发现我们的 Fortio 负载工具默认启用了连接保持活动。使用 10 个来自 Fortio 的连接到 details 服务和 details 服务(使用 WEBrick Ruby 库)尊重连接保持活动设置,连接可以有效地被重用,无需 ambient。
接下来,我探索了使用设置 Connection: close
标头的同样负载测试。这强制禁用任何 HTTP 连接池,这是测试这个假设的好方法。
curl -v -d '{"metadata": {"url":"http://details:9080/details/0", "c":"10", "qps": "100", "n": "2000", "async":"on", "save":"on"}}' "localhost:8081/fortio/rest/run?jsonPath=.metadata" -H "Connection: close"
Fortio 对 details | 平均 | P50 | P75 | P90 | P99 | 差异 |
---|---|---|---|---|---|---|
无网格 | 1.90ms | 1.72ms | 2.28ms | 2.77ms | 3.98ms | |
Ambient | 2.06ms | 2.15ms | 2.65ms | 2.94ms | 4ms | 平均慢 8%,P90 慢 6% |
表 2: Fortio 对 details 服务 100 RPS 10 连接带有 connection close。
与表 1 的结果相比,表 2 的响应时间明显更高,这是预期的,因为每个连接在 details 服务响应后立即关闭。考虑到 P50、P75、P90 和 P99 都从带有 connection close 的 ambient 运行中变慢,似乎可以安全排除第一理论中的 ztunnel 连接池可能使请求更快。
我注意到在我们新的 Istio v1.23 版本中的 details 和 productpage 服务中有一个与性能相关的 PR。对于 details 服务,PR 为 details WEBrick 服务器启用了 TCP_NODELAY 标志,这将减少来自 details 服务响应时间的不必要延迟(高达 40ms)。对于 productpage 服务,PR 在传入请求上启用了保持活动状态,这将重用现有的传入连接,从而提高性能。
包含修复的新更新的 details 部署中,我重复了通过 10 个连接发送 100 RPS 到 details 服务的相同测试。无网格和 ambient 的结果非常接近,所以我进行了三次测试以确保结果的一致性。下面是每个场景的第一次运行的截图:
我为每个场景的三次运行建立了一个表格:
表 3: Fortio 对新 details 服务 100 RPS 10 连接。
与表 1 的先前结果相比,表 3 的无网格数字有了相当大的改进(在更高百分比下更显著地超过 ambient 数字),现在接近于 ambient 数字。Ztunnel 默认启用了 TCP_NODELAY,这有助于 ambient 性能在表 1 中超过无网格,当旧的 details 服务没有启用 TCP_NODELAY 时。当新的 details 服务启用了 TCP_NODELAY 时,它也稍微提高了 ambient 的响应时间。
表 3 还显示,在此类型的负载测试中,无网格和 ambient 运行之间的平均、P50、P75 和 P90 几乎没有差异。这些运行之间的差异可能只是噪音,除了 P99,无网格始终比 ambient 慢 8% 或更多。
继续审查表 3 的测试结果,为什么在有额外跳转到 ztunnel pod 和 ambient 提供的如 mTLS 和 L4 观测等显著优势时,无网格和 ambient 之间的延迟相似?对于 P99 情况,为什么 details 服务在 ambient 模式下始终更快?
Ztunnel 提供了出色的读写缓冲管理,并通过 HTTP/2 多路复用,可以有效地最小化或有时甚至消除通过客户端和服务器 ztunnel pod 的额外跳转所增加的开销。我决定通过在两个 Fortio 和 details 服务的 Kubernetes 工作节点上进入并附加 strace 来测量这一点,同时过滤掉无关的跟踪:
strace -fp {pid} -e trace=write,writev,read,recvfrom,sendto,readv
无网格和 ambient 情况下的 details 服务的 strace 输出是相似的:
…read(9, "GET /details/0 HTTP/1.1\r\nHost: d"..., 8192) = 118write(9, "HTTP/1.1 200 OK\r\nContent-Type: a"..., 180) = 180write(9, "{"id":0,"author":"William Shakes"..., 178) = 178write(2, "192.168.239.19 - - [13/Aug/2024:"..., 80) = 80…
输出 1: 无网格或 ambient —— 附加 strace 到 details 服务的 PID。
无网格和 ambient 情况下的 Fortio 服务的 strace 输出不同。在无网格情况下,我们看到 Fortio 执行了两次读取,一次用于 HTTP 头部,另一次用于正文。
…read(13, "HTTP/1.1 200 OK\r\nContent-Type: a"..., 4096) = 180read(13, "{"id":0,"author":"William Shakes"..., 4096) = 178…write(19, "GET /details/0 HTTP/1.1\r\nHost: d"..., 118) = 118 …
输出 2: 无网格 —— 附加 strace 到 Fortio 的 PID。
在 ambient 情况下,我们始终只看到一个读取,用于同时获取头部和正文。
…read(19, "HTTP/1.1 200 OK\r\nContent-Type: a"..., 4096) = 358…write(19, "GET /details/0 HTTP/1.1\r\nHost: d"..., 118) = 118…
输出 3: Ambient 模式 —— 附加 strace 到 Fortio 的 PID。
为什么会这样?这是有道理的,因为 write 调用完全基于应用行为,而这在这种情况下没有变化。Ambient 将这些多个应用写入合并为单个网络写入,并隐含地在对等端进行单个读取。
在上述测试场景中,我观察到 Fortio 服务在启用 ambient 时系统调用总数减少了 60%。这非常重要,并解释了在 peak 时 Fortio pod 的延迟和 CPU 使用量减少约 25% 的大部分原因。系统调用的减少超过了 mTLS 和 ztunnel 的其他功能的成本。我预计这种模式在企业中会相当常见,因为一些 HTTP 库和应用在缓冲和刷新方面做得更好,而一些则不太好。这通常与应用的年龄和它们构建时使用的 SDK 相关。
在更新了 details 和 productpage 部署之后,我开始通过 100 个连接发送 1000 RPS 到 Bookinfo 应用,并观察到无网格和 ambient 的优异结果。
Fortio 对 Bookinfo | 平均 | P50 | P75 | P90 | P99 | 平均差异 |
---|---|---|---|---|---|---|
无网格 | 1.39ms | 1.32ms | 1.42ms | 1.67ms | 2.19ms | |
Ambient | 1.40ms | 1.34ms | 1.48ms | 1.68ms | 2.94ms | 平均和 P90 均慢不到 1% |
表 4: Fortio 对新 Bookinfo 应用 1000 RPS 100 连接。
作为对比,我还针对 v1.22.3 版本中附带的旧 Bookinfo 示例进行了同样的测试,你可以看到新 Bookinfo 在响应时间上取得了 5-10 倍 的提升,无论是无网格还是 ambient!
Fortio 对 Bookinfo | 平均 | P50 | P75 | P90 | P99 | 平均差异 |
---|---|---|---|---|---|---|
无网格 | 6.35ms | 4.68ms | 7.44ms | 11.4ms | 36.63ms | |
Ambient | 6.74ms | 4.9ms | 7.79ms | 12.12ms | 41.14ms | 慢 6% |
表 5: Fortio 对旧 Bookinfo 应用 1000 RPS 100 连接。
将负载增加到 4000 RPS 和 400 连接,并使用新 Bookinfo 部署:
响应时间依然很好,远远优于只有 1000 RPS 和 100 连接的旧 Bookinfo 应用(表 5):
Fortio 对 Bookinfo | 平均 | P50 | P75 | P90 | P99 | 平均差异 |
---|---|---|---|---|---|---|
无网格 | 1.54ms | 1.33ms | 1.54ms | 2.25ms | 3.98ms | |
Ambient | 1.58ms | 1.37ms | 1.57ms | 2.33ms | 4.9ms | 平均慢 3%,P90 慢 4% |
表 6: Fortio 对新 Bookinfo 应用 4000 RPS 400 连接。
很高兴看到 Bookinfo 能够在 4000 RPS 下无错误地运行,而且 ambient 模式比无网格慢 3-4%,但带来了传输中加密的 mTLS 和 L4 观测的所有好处。我记得我之前只能在旧 Bookinfo 应用中达到最高 1200 RPS,这已经导致了少量的错误。现在我可以增加到 4000 或更高 RPS 而不出现错误。
在 L4 上,Ambient 模式只引入了非常微小的影响——偶尔甚至可以自动改善!— 用户应用的延迟。结合简单的用户体验,通过标记命名空间以将您的应用注册到 ambient 而无需重启任何工作负载,它为用户提供了我们初衷中预期的愉快体验。
我想感谢所有 Istio 维护者,他们构建了这样一个令人愉快的项目,以及为 Istio 项目提供测试基础设施的 CNCF。我还要感谢 Quentin Joly 和许多提供了“ambient 有时比无网格稍快”的反馈的用户,这促使我进行了上述基准测试,亲身体验了在负载下的改善或微小的延迟影响。
最后更新于 2024/11/27