QUIC 协议的实际应用:Uber 如何实施该协议来优化性能

QUIC 协议非常有趣,这就是我们喜欢撰写有关它的原因。 但是,如果之前有关 QUIC 的出版物更多的是历史(本地历史,如果你愿意的话)性质和硬件,那么今天我们很高兴发布不同类型的翻译 - 我们将在 2019 年讨论该协议的实际应用。 此外,我们谈论的不是所谓车库中的小型基础设施,而是几乎在世界各地运营的 Uber。 该公司的工程师如何决定在生产中使用 QUIC、他们如何进行测试以及他们在生产中推出 QUIC 后看到的结果 - 低于标准。

图片是可以点击的。 享受阅读!

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能

Uber 的业务遍及全球,即 600 个城市,其应用程序完全依赖于 4500 多家移动运营商的无线互联网。 用户期望应用程序不仅要快,而且要实时——为了实现这一点,Uber 应用程序需要低延迟和非常可靠的连接。 唉,但是堆栈 HTTP / 2的 在动态和容易丢失的无线网络中表现不佳。 我们意识到,在这种情况下,低性能与操作系统内核中的 TCP 实现直接相关。

为了解决这个问题,我们应用了 QUIC,一种现代通道复用协议,使我们能够更好地控制传输协议的性能。 目前工作组 IETF 将 QUIC 标准化为 HTTP / 3的.

经过大量测试后,我们得出的结论是,与 TCP 相比,在我们的应用程序中实施 QUIC 会带来更低的尾部延迟。 我们观察到驾驶员和乘客应用程序中的 HTTPS 流量减少了 10-30%。 QUIC 还为我们提供了对用户包的端到端控制。

在本文中,我们分享了使用支持 QUIC 的堆栈为 Uber 应用程序优化 TCP 的经验。

最新技术:TCP

如今,TCP 是在 Internet 上传输 HTTPS 流量时最常用的传输协议。 TCP 提供可靠的字节流,从而应对网络拥塞和链路层丢失。 TCP 在 HTTPS 流量中的广泛使用是由于前者的普遍存在(几乎每个操作系统都包含 TCP)、大多数基础设施上的可用性(例如负载均衡器、HTTPS 代理和 CDN)以及可用的开箱即用功能在几乎大多数平台和网络上。

大多数用户在旅途中使用我们的应用程序,TCP 尾部延迟远不能满足我们实时 HTTPS 流量的需求。 简而言之,世界各地的用户都经历过这种情况 - 图 1 显示了主要城市的延误情况:

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 1:Uber 主要城市的尾部延迟各不相同。

尽管印度和巴西网络的延迟高于美国和英国,但尾部延迟明显高于平均延迟。 即使对于美国和英国也是如此。

TCP 空中传输性能

TCP 的创建目的是 有线 网络,即强调高度可预测的链接。 然而, 无线的 网络有其自身的特点和难点。 首先,无线网络容易因干扰和信号衰减而遭受损失。 例如,Wi-Fi 网络对微波、蓝牙和其他无线电波敏感。 蜂窝网络遭受信号丢失(迷路)由于物体和建筑物以及来自的信号的反射/吸收 干扰 来自邻近的 手机信号塔。 这会导致更显着(4-10 倍)和更多样化 往返时间 (RTT) 与有线连接相比,数据包丢失。

为了应对带宽波动和损失,蜂窝网络通常使用大缓冲区来应对流量突发。 这可能会导致过度排队,这意味着更长的延迟。 TCP 通常将这种排队视为由于超时延长而造成的浪费,因此 TCP 倾向于中继并从而填充缓冲区。 这个问题被称为 缓冲膨胀 (网络缓冲过多、缓冲区膨胀),这非常 严重的问题 现代互联网。

最后,蜂窝网络性能因运营商、地区和时间而异。 在图 2 中,我们收集了 2 公里范围内跨小区的 HTTPS 流量的中值延迟。 为印度德里的两家主要移动运营商收集的数据。 正如您所看到的,不同单元的性能有所不同。 此外,一名操作员的生产率与另一名操作员的生产率不同。 这受到考虑时间和位置的网络进入模式、用户移动性以及考虑塔密度和网络类型(LTE、3G 等)比例的网络基础设施等因素的影响。

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 2. 以 2 公里半径为例的延迟。 印度德里。

此外,蜂窝网络的性能随时间而变化。 图 3 显示了一周中各天的平均延迟时间。 我们还在一天和一小时内观察到较小规模的差异。

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 3. 对于同一操作员,不同天的尾部延迟可能会有很大差异。

所有这些都会导致 TCP 性能在无线网络中无效。 然而,在寻找 TCP 的替代方案之前,我们希望对以下几点有一个准确的理解:

  • TCP 是我们应用程序中尾部延迟的罪魁祸首吗?
  • 现代网络是否存在显着且变化的往返延迟 (RTT)?
  • RTT和丢包对T​​CP性能有什么影响?

TCP性能分析

为了了解我们如何分析 TCP 性能,让我们快速了解一下 TCP 如何将数据从发送方传输到接收方。 首先,发送方建立TCP连接,执行三向 握手:发送方发送 SYN 数据包,等待接收方发送 SYN-ACK 数据包,然后发送 ACK 数据包。 额外的第二遍和第三遍用于建立 TCP 连接。 接收方确认收到每个数据包 (ACK) 以确保可靠的传送。

如果数据包或 ACK 丢失,发送方会在超时(RTO、 重传超时)。 RTO 是根据各种因素动态计算的,例如发送方和接收方之间的预期 RTT 延迟。

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 4. TCP/TLS 上的数据包交换包括重传机制。

为了确定 TCP 在我们的应用程序中的执行情况,我们使用以下命令监控 TCP 数据包 转储 来自印度边缘服务器的战斗流量一周。 然后我们使用以下方法分析 TCP 连接 跟踪。 此外,我们创建了一个 Android 应用程序,将模拟流量发送到测试服务器,尽可能模仿真实流量。 装有此应用程序的智能手机被分发给几名员工,他们在几天内收集了日志。

两个实验的结果是一致的。 我们发现 RTT 延迟很高; 尾部值几乎比中值高6倍; 算术平均延迟超过1秒。 许多连接丢失,导致 TCP 重新传输了所有数据包的 3,5%。 在机场和火车站等拥堵区域,我们看到了 7% 的损失。 这些结果对蜂窝网络中使用的传统观点提出了质疑 先进的重传电路 显着减少运输层面的损失。 以下是“模拟器”应用程序的测试结果:

网络指标

RTT,毫秒 [50%,75%, 95%,99%]
[350,425,725,2300]

RTT 发散,秒
平均~1,2秒

连接不稳定时丢包
平均约 3.5%(超载地区为 7%)

几乎一半的连接至少有一个数据包丢失,其中大多数是 SYN 和 SYN-ACK 数据包。 大多数 TCP 实现对 SYN 数据包使用 1 秒的 RTO 值,该值对于后续丢失呈指数增长。 由于 TCP 需要更长的时间来建立连接,因此应用程序加载时间可能会增加。

就数据包而言,在无线网络中存在瞬态丢失的情况下,高 RTO 值会大大降低网络的有用利用率。 我们发现平均重传时间约为 1 秒,尾部延迟近 30 秒。 TCP 级别的高延迟导致 HTTPS 超时和重新请求,进一步增加网络延迟和效率低下。

测量的 RTT 的第 75 个百分位数约为 425 毫秒,而 TCP 的第 75 个百分位数几乎为 3 秒。 这暗示丢失导致 TCP 需要 7-10 遍才能成功传输数据。 这可能是RTO计算效率低下、TCP无法快速响应丢失的结果 最新套餐 窗口中的问题以及拥塞控制算法的低效率,该算法不区分无线丢失和网络拥塞造成的丢失。 以下是 TCP 丢失测试的结果:

TCP丢包统计

至少有 1 个数据包丢失的连接百分比
45%

连接建立期间丢失的连接百分比
30%

数据交换期间丢失的连接百分比
76%

重传延迟分布,秒 [50%, 75%, 95%,99%] [1, 2.8, 15, 28]

一个数据包或TCP段的重传次数分布
[1,3,6,7]

QUIC的应用

QUIC 最初由 Google 开发,是一种运行在 UDP 之上的多线程现代传输协议。 目前 QUIC 处于 标准化流程 (我们已经写过,QUIC 有两个版本,好奇 可以点击链接 – 大约。 译者)。 如图5所示,QUIC置于HTTP/3之下(事实上,QUIC之上的HTTP/2是HTTP/3,目前正在大力标准化)。 它通过使用 UDP 形成数据包来部分替代 HTTPS 和 TCP 层。 QUIC 仅支持安全数据传输,因为 TLS 完全内置于 QUIC 中。

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 5:QUIC 在 HTTP/3 下运行,取代了之前在 HTTP/2 下运行的 TLS。

以下是说服我们使用 QUIC 进行 TCP 放大的原因:

  • 0-RTT 连接建立。 QUIC 允许重用先前连接的授权,从而减少安全握手的次数。 在未来 TLS1.3 将支持 0-RTT,但仍然需要三向 TCP 握手。
  • 克服HoL阻塞。 HTTP/2 对每个客户端使用一个 TCP 连接来提高性能,但这可能会导致 HoL(队头)阻塞。 QUIC 简化了复用并独立地将请求传递给应用程序。
  • 拥塞控制。 QUIC 驻留在应用层,可以更轻松地更新基于网络参数(丢失数或 RTT)控制发送的主要传输算法。 大多数 TCP 实现都使用该算法 CUBIC,这对于延迟敏感的流量来说并不是最佳选择。 最近开发的算法如 BBR,更准确地对网络进行建模并优化延迟。 QUIC 允许您使用 BBR 并在使用时更新该算法。 完美.
  • 弥补损失。 QUIC 调用两个 TLP(尾部丢失探针)在 RTO 触发之前 - 即使损失非常明显。 这与 TCP 实现不同。 TLP主要重传最后一个数据包(或者新的数据包,如果有的话)来触发快速补充。 处理尾部延迟对于 Uber 运营其网络的方式特别有用,即短时、零星和延迟敏感的数据传输。
  • 优化的ACK。 由于每个数据包都有唯一的序列号,所以没有问题 区别 重传数据包时。 ACK 数据包还包含处理数据包并在客户端生成 ACK 的时间。 这些功能确保 QUIC 更准确地计算 RTT。 QUIC 中的 ACK 支持多达 256 个频段 纳克,帮助发送方对数据包改组更有弹性,并在此过程中使用更少的字节。 选择性确认(SACKTCP 中的 ) 并不能在所有情况下解决这个问题。
  • 连接迁移。 QUIC 连接由 64 位 ID 标识,因此如果客户端更改 IP 地址,旧的连接 ID 可以继续在新 IP 地址上使用,而不会中断。 对于用户在 Wi-Fi 和蜂窝连接之间切换的移动应用程序来说,这是一种非常常见的做法。

QUIC 的替代方案

在选择 QUIC 之前,我们考虑了解决问题的替代方法。

我们尝试的第一件事是部署 TPC PoP(存在点)来终止更靠近用户的 TCP 连接。 本质上,PoP 终止与更靠近蜂窝网络的移动设备的 TCP 连接,并将流量代理回原始基础设施。 通过更接近地终止 TCP,我们可以潜在地减少 RTT 并确保 TCP 对动态无线环境的响应更加灵敏。 然而,我们的实验表明,大部分 RTT 和损耗来自蜂窝网络,并且 PoP 的使用并不能提供显着的性能改进。

我们还研究了调整 TCP 参数。 在我们的异构边缘服务器上设置 TCP 堆栈很困难,因为 TCP 在不同的操作系统版本上有不同的实现。 实现这一点并测试不同的网络配置很困难。 由于缺乏权限,无法直接在移动设备上配置 TCP。 更重要的是,0-RTT 连接和改进的 RTT 预测等功能对于协议的架构至关重要,因此仅通过调整 TCP 不可能获得显着的收益。

最后,我们评估了几种基于 UDP 的协议来解决视频流问题 - 我们想看看这些协议是否对我们的案例有帮助。 不幸的是,它们严重缺乏许多安全设置,并且还需要额外的 TCP 连接来存储元数据和控制信息。

我们的研究表明,QUIC 可能是唯一可以帮助解决互联网流量问题,同时兼顾安全性和性能的协议。

将 QUIC 集成到平台中

为了在连接不良的环境中成功嵌入 QUIC 并提高应用程序性能,我们用 QUIC 协议替换了旧堆栈(基于 TLS/TCP 的 HTTP/2)。 我们使用了网络图书馆 克罗内特 из 铬项目,其中包含原始的 Google 版本协议 - gQUIC。 该实现也在不断改进,以遵循最新的 IETF 规范。

我们首先将 Cronet 集成到我们的 Android 应用程序中以添加对 QUIC 的支持。 整合的方式是尽可能降低迁移成本。 而不是完全替换使用该库的旧网络堆栈 好的http,我们在 OkHttp API 框架下集成了 Cronet。 通过这种方式进行集成,我们避免了对网络调用的更改(这些调用由 改造)在 API 级别。

与 Android 设备的方法类似,我们在 iOS 上的 Uber 应用程序中实现了 Cronet,拦截来自网络的 HTTP 流量 API运用 NSURL协议。 这种抽象由 iOS 基金会提供,可处理特定于协议的 URL 数据,并确保我们可以将 Cronet 集成到我们的 iOS 应用程序中,而无需大量迁移成本。

在 Google Cloud Balancer 上完成 QUIC

在后端,QUIC 补全由 Google Cloud 负载均衡基础设施提供,该基础设施使用 替代SVC 响应中的标头以支持 QUIC。 一般来说,平衡器会向每个 HTTP 请求添加一个 alt-svc 标头,这已经验证了该域的 QUIC 支持。 当 Cronet 客户端收到带有此标头的 HTTP 响应时,它会使用 QUIC 来发送对该域的后续 HTTP 请求。 一旦平衡器完成 QUIC,我们的基础设施就会通过 HTTP2/TCP 显式将此操作发送到我们的数据中心。

表现:结果

输出性能是我们寻找更好协议的主要原因。 首先,我们创建了一个展位 网络仿真了解 QUIC 在不同网络配置文件下的表现。 为了测试 QUIC 在现实网络上的性能,我们在新德里开车时使用与乘客应用程序中的 HTTP 调用非常相似的模拟网络流量进行了实验。

实验1

实验设备:

  • 使用 OkHttp 和 Cronet 堆栈测试 Android 设备,以确保我们分别允许 TCP 和 QUIC 上的 HTTPS 流量;
  • 基于 Java 的模拟服务器,在响应中发送相同类型的 HTTPS 标头并加载客户端设备以接收来自它们的请求;
  • 物理位置靠近印度的云代理,用于终止 TCP 和 QUIC 连接。 对于 TCP 终止,我们使用了反向代理 NGINX,很难找到 QUIC 的开源反向代理。 我们使用 Chromium 的基本 QUIC 堆栈自行构建了 QUIC 的反向代理, 发表 它作为开源的铬。

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 6. TCP 与 QUIC 道路测试套件由具有 OkHttp 和 Cronet 的 Android 设备、用于终止连接的云代理以及模拟服务器组成。

实验2

当 Google 推出 QUIC 时 Google Cloud负载平衡中,我们使用了相同的清单,但进行了一项修改:我们使用 Google 负载均衡器代替 NGINX 来终止来自设备的 TCP 和 QUIC 连接,并将 HTTPS 流量路由到模拟服务器。 平衡器分布在世界各地,但使用距离设备最近的 PoP 服务器(得益于地理位置)。

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 7。在第二个实验中,我们想要比较 TCP 和 QUIC 的完成延迟:使用 Google Cloud 和使用我们的云代理。

结果,有几个启示等待着我们:

  • 通过 PoP 终止提高了 TCP 性能。 由于平衡器终止靠近用户的 TCP 连接并且经过高度优化,因此可以降低 RTT,从而提高 TCP 性能。 尽管 QUIC 受到的影响较小,但在减少尾部延迟方面,它仍然优于 TCP(减少 10-30%)。
  • 尾巴受到影响 网络跳数. 尽管我们的 QUIC 代理比 Google 的负载均衡器距离设备更远(延迟大约高 50 毫秒),但它提供了相似的性能 - 延迟减少了 15%,而 TCP 的第 20 个百分位数减少了 99%。 这表明最后一英里过渡是网络中的瓶颈。

QUIC 协议的实际应用:Uber 如何实施该协议来优化性能QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 8:两个实验的结果表明 QUIC 显着优于 TCP。

打击交通

受到实验的启发,我们在 Android 和 iOS 应用程序中实现了 QUIC 支持。 我们进行了 A/B 测试,以确定 QUIC 对 Uber 运营城市的影响。 总体而言,我们发现两个地区、电信运营商和网络类型的尾部延迟均显着减少。

下图显示了按宏观区域和不同网络类型(LTE、95G、99G)划分的尾部(3 和 2 百分位数)的百分比改进。
QUIC 协议的实际应用:Uber 如何实施该协议来优化性能QUIC 协议的实际应用:Uber 如何实施该协议来优化性能
图 9. 在战斗测试中,QUIC 在延迟方面优于 TCP。

仅转发

也许这只是一个开始 - QUIC 投入生产为提高稳定和不稳定网络中的应用程序性能提供了绝佳的机会,即:

增加覆盖范围

分析了协议在实际流量上的性能后,我们发现大约 80% 的会话成功使用 QUIC 所有 请求,而 15% 的会话使用 QUIC 和 TCP 的组合。 我们假设这种组合是由于 Cronet 库超时返回 TCP,因为它无法区分真正的 UDP 故障和较差的网络条件。 我们目前正在寻找解决这个问题的方法,并致力于 QUIC 的后续实施。

QUIC优化

来自移动应用程序的流量对延迟敏感,但对带宽不敏感。 此外,我们的应用程序主要用于蜂窝网络。 根据实验,即使使用代理终止靠近用户的 TCP 和 QUIC,尾部延迟仍然很高。 我们正在积极寻找改进拥塞管理并提高 QUIC 丢失恢复算法效率的方法。

通过这些和其他几项改进,我们计划改善用户体验,无论网络和地区如何,使世界各地更方便、无缝的数据包传输。

来源: habr.com

添加评论