优步基于gRPC的下一代推送平台


Uber所有的应用程序都需要与实时信息同步,无论是通过屏幕上的接送时间、到达时间和路线,还是打开应用程序时附近的司机。Uber使用推送平台来传递这些消息,这篇博文将介绍Uber如何通讯将协议从服务器发送事件 (HTTP1.1) 更改为基于 gRPC 的双向流 (QUIC/HTTP3)、面临的挑战、最终结果以及一些关键的学习。 

转向gRPC原因
gRPC 是一种高性能、广泛采用的 RPC 框架,具有跨多种平台和语言的客户端和服务器的标准化实现。转向 gRPC 的主要原因如下:

1、双向流
gRPC 对双向流具有一流的支持,考虑到 RAMEN 的长期愿景,这是最吸引人的特性。确认可以立即通过同一流发送,而无需来自移动客户端的额外网络调用。这可以显着提高 RAMEN 的确认可靠性。
实时确认使我们能够测量 RAMEN 消息的 RTT 并了解网络状况。它们还帮助 RAMEN 后端减少消息队列的内存占用。

2、QUIC/HTTP3
与 HTTP2 相比,QUIC/HTTP3 从本质上消除了线头阻塞,持续显着改善了移动网络延迟。正如我们从之前的QUIC 实验中了解到的那样,QUIC 为我们带来了 HTTPS 流量的尾端延迟 10-30% 的改进,我们希望在这里也将它用于 RAMEN gRPC。 
gRPC 可以使用 Cronet 作为传输,这允许 RAMEN 从实时流量中重用 QUIC 会话,进一步减少了第一条 RAMEN 消息到移动端的延迟。 

数据建模 
我们使用proto3 protobuf 来定义服务器和客户端之间的合约。拥有明确定义的合约可以更容易地在各种 RAMEN 客户端中实施。从而减轻迁移并确保更少的错误。

RPC 合约RPC 被定义为一个双向端点,正如我们在前面部分中讨论的那样。服务器和客户端都会来回保持流数据。在高层次上,服务器将发送消息,客户端将回复确认。 

这就是我们在 protobuf 模式中定义请求和响应合约的方式:

请求数据模型

  1. SeqID 用于记账目的,我们存储每条消息的序列号,然后使用它来跟踪传递。 
  2. 消息确认用于确认消息,功能确认用于收听 RAMEN 消息的功能团队插件发送的确认。 
  3. 我们还有控制消息,客户端可以在其中指示对服务器的任何运行时更改,例如终止连接。我们还计划在未来将其用于流控制和流优先级等高级结构。 

响应数据模型 
我们以通用方式对响应进行了建模,其中消息可以属于任何类别,例如 RAMEN 消息、控制消息或心跳。 

  1. RAMEN 消息包含支持各种用例的所有实际消息。
  2. 控制消息用于向客户端指示断开连接等。
  3. 每 5 秒发送一次心跳以指示连接正常。 

后端实现
为了启用 gRPC,我们决定分离前端运行时以无缝地启用 gRPC 请求代理。gRPC 流量通过新的运行时流入,并被代理到集群中正确的请求代理实例

使用GRPCproxy实现了路由请求的前端层——StreamgateFE-gRPC(流式和非流式)。我们选择了这个实现,因为它为进入前端层的代理请求提供了一个简单的接口,并与我们的 Helix 层集成以确保粘性路由。

来自我们 gRPC 代理实现的上述代码片段展示了我们如何从调用中获取元数据(即方法名称、用于路由请求的用户 ID)以找出已经与 Streamgate 实例建立(如果已经)的正确 gRPC 通道,然后使用该通道路由请求。 

移动客户端
RAMEN SSE 建立在OkHttp和 iOS 网络库之上,由各种拦截器组成,以支持核心功能,例如故障转移和重定向、网络监控以及标头和 OAuth 令牌丰富。要将 RAMEN 迁移到 gRPC,我们必须重新设计移动网络堆栈,使其具有与 SSE 堆栈相同的功能。

结果
我们已经在 Android 和 iOS 上的全球所有移动应用程序(Rider、Driver 和 Eats)中完全推出了 RAMEN over gRPC。我们取得的一些关键成果:

  1. 由于上述所有更改,gRPC Connect Latency (p95) 至少提高了45% 。依赖 RAMEN 的功能可以提早启动,因为随着连接延迟的改善,它们将通过 RAMEN 提早接收数据。
  2. 所有应用程序的推送成功率至少提高了1-2%,并且 RAMEN gRPC 中每个会话发送的平均消息数有所提高。 
  3. 通过客户的实时确认,我们可以更好地了解 RTT,从而释放明智地使用网络带宽的机会。
  4. 我们在所有客户中都有一致的实施,从而减少了未来发生故障和中断的机会。 


详细点击标题