Uber 实时推送平台实践:gRPC 推动基础设施的发展

原标题:Uber实时推送平台实践:gRPC推动基础设施的发展
作者|Uber工程博客
译者|Sambodhi
策划|赵钰莹
本文最初发表于Uber官方博客 , InfoQ经对方授权对全文进行了如下翻译 。
Uber的业务遍布全球 , 每天需要处理全球数百万人次的出行 , 实时性对Uber而言非常重要 。 在一次行程中 , 多个参与者可以修改和查看正在进行中的行程状态 , 这需要实时更新 。 无论是取车时间、到达时间、路线还是在打开应用时附近的司机数量 , 所有参与者和应用都必须保持实时信息同步 。 本文介绍了Uber如何通过轮询保持信息实时更新以及基于gRPC双向流协议构建应用 。
轮询更新
在Uber的应用场景下 , 司机侧需要每隔几秒钟对服务器进行轮询 , 以查看是否有新的订单 。 乘客侧可以每隔几秒钟轮询一次服务器 , 以检查是否分配了司机 。
这些应用程序的轮询频率取决于所轮询的数据变化率 。 在Uber这样的大型应用中 , 变化率的取值范围非常大 , 从几秒钟到几小时不等 。
移动应用轮询的问题
在某些时候 , 发送到后端API网关的请求中80%都是轮询调用 。
主动轮询可以保持应用响应 , 但是会占用大量服务器资源 。 轮询频率上的任何错误都会导致后端负载和性能下降 。 当需要更多实时动态数据时 , 这种方法是行不通的 , 因为它将在后端增加大量负载 。
轮询会导致电池消耗加快、应用迟钝以及网络级拥堵 。 这一点在2G/3G网络或整个城市网络不稳定的地方尤为明显 , 应用在每次轮询时都会多次尝试 。
随着功能数量的增加 , 开发者试图让现有的轮询API过载 , 或创建一个新的API 。 在高峰时期 , 该应用会轮询几十个API 。 每一个API都有多个功能过载 。 这些轮询API最终只会变成一组负载分片的API , 供应用轮询其功能 。 保持API级别的一致性和逻辑分离 , 仍然是一个日益增长的挑战 。
应用的冷启动是轮询策略中最具挑战的场景 。 每当用户打开应用 , 所有功能都需要从后端提取出最新的状态来渲染用户界面 。 这样就会产生多个竞争的并发API调用 , 应用只有从服务器获取关键组件后才能渲染 。 由于所有API都包含一些关键信息的片段 , 没有优先级 , 因此应用的加载时间会持续增加 。 恶劣的网络条件会使冷启动问题更加恶化 。
显然 , 我们需要对市场上各个参与者的状态同步方式进行彻底改革 。 在创建推送消息平台的过程中 , 我们允许服务器根据需要向应用发送数据 。
在采用该体系结构时 , 我们发现效率有了显著提高 , 同时也解决了很多问题和挑战 。 接下来的部分 , 我们将介绍整个该平台是如何演变的 。
取消轮询 , 引入RAMEN
虽然使用推送消息是取消轮询的必然选择 , 但是如何进行架构设计却有许多考虑 。 主要的设计原则有以下四点 。
从轮询迁移到推送更容易
现有的很多轮询端点都可以为企业提供动力 。 在不重写的情况下 , 新系统必须利用现有轮询API中的负载来构建业务逻辑 。
易于开发
与开发轮询API相比 , 开发人员不应采取完全不同的方式来推送数据 。
可靠性
在网络上 , 所有消息都应该可靠地发送 , 如果发送失败 , 则应重试
线路效率
由于Uber的快速发展 , 对用户来说传输数据的成本是一个挑战 , 特别是那些每天与平台连接数小时的司机 。 这个协议必须在服务器和移动应用之间传输最少的数据 。
我们将新系统命名为
RAMEN(RealtimeAsynchronousMEssagingNetwork , 意即实时异步消息网络) 。

Uber 实时推送平台实践:gRPC 推动基础设施的发展
文章图片
图1:整个系统的高级架构
确定生成消息
实时信息随时都在数百名乘客、司机、餐厅和行程中发生变化 。 信息的生命周期从确定“何时”为用户生成信息负载开始 。
Fireball是一个微服务 , 负责解决“何时推送消息”的问题 。 决策的很大一部分被捕获为配置 。 它监听系统中发生的各种类型事件 , 并确定是否需要推送所涉及的用户 。
举个例子 , 当司机“接受”订单时 , 司机和行程实体的状态会发生变化 。 这种变化会触发Fireball服务 。 Fireball根据配置来确定应该将哪种推送消息发送给相关的参与者 。 许多情况下 , 一次触发需要多个用户的多个消息负载 。
触发器可以是任何类型的重要事件 , 并且应该为其生成推送负载 。 例如 , 像请求乘车这样的用户操作、应用程序的打开、固定时间间隔的计时器滴答声、消息总线上的后端业务事件 , 或者地理上的出入口事件 。