重新设计Uber Engineering的移动内容交付生态系统

重新设计Uber Engineering的移动内容交付生态系统

为使用优步的用户提供一个快速高效的应用内沟通渠道对我们的业务至关重要。如果我们无法在应用程序上有效地沟通信息,它可能会阻止司机接收重要信息。2015年,优步的司机体验团队推出了一个新的驱动程序改善用户体验,包括部署一个新的、更有效的内容交付生态系统。

在本文中,我们将讨论遇到的技术挑战- - - - - -以及我们开发的解决方案- - - - - -同时为应用程序构建新的内容提要和相应的后端生态系统。

吃还是不吃?

在设计一款新应用时,最直接的挑战是确定为用户构建内容的最佳方式。一般来说,Uber识别出三种用于对用户内容进行分组的交互模型:

  • 紧急的:需要用户立即执行操作的内容,例如关于文档过期的通知。
  • 重要的事:可以确认或拒绝的内容。这个模型的工作原理类似于电子邮件收件箱,在某种意义上,传入的消息可以在一段时间内访问,并可以等待用户在他们方便的时候阅读和处理它们。这些通知大多是关于支付,最近的评级和功能推广的确认。
  • 永久:有关用户简介的教育材料或持续统计数据,如总评分和每周收入。用户可以随时在应用程序用户界面(UI)的专用部分查看这些内容。

将这三个范例组合成一个单一的解决方案遵循正交的目标。在我们寻找解决方案的过程中,我们意识到从社交网络中获取一个feed概念,并添加一些修改将使我们能够实现我们的目标。在下一节中,我们将研究这些交互模型如何反映在新提要的行为中。

图1:Uber的司机应用程序提要显示三类内容:紧急、非紧急(如上所示)和永久。

交互模型的类别

紧急的内容

通过在主屏幕底部放置消息提要,并让这些消息以覆盖的形式向上滑动,新驱动程序应用程序上的所有传入更新都以弹出窗口的形式出现。虽然这可以很好地处理确认,但促销和行动请求(rfa)具有更复杂的生命周期。

一旦内容被确认,确认就会消失,因为它的唯一目的是通知用户他们可能想要采取行动。推广内容在屏幕上停留的时间比确认信息更长,以便用户有更多时间消化其内容,只有当用户点击确认后才会从feed中消失;它甚至可以链接到永久内容,用户可以在应用程序的一个单独的静态部分中获得。RFAs遵循更复杂的模式,通过出现、消失和重新出现,直到用户完成一个操作。

事内容

如果显示的内容不是紧急内容,则根据其“新鲜度”和与用户的相关性将其放置在提要中。这一策略对各种更新都是好兆头,比如他们所在城市即将发生的事件的信息或以前客户的反馈。

永久的内容

对于这款新应用来说,永久内容主要是一组指向其他内容的静态链接。在测试这个新接口时,我们发现可以将这些内容建模为应用程序的单独选项卡中显示的单独的、静态排名的提要。例如,与收入相关的信息,如奖励、推荐和财务统计数据,可以在一个由feed系统提供的单独选项卡中以静态项目列表的形式显示。

交互模型含义

在设计新的提要时,我们评估了这些交互模型对整个系统的需求以及它们产生的体系结构含义。通过为应用程序配备多种类型的提要,我们能够分别构建每个提要。这是通过为每个提要类型提供自己的可配置的排名策略,并为给定提要中的每个内容提供自己的生命周期策略来管理的。

使用这种方法,应用程序中包含静态内容的选项卡由一个惟一的、静态排序的提要提供服务。在这种情况下,排名很少随时间变化,但可能会受到驾驶员当前地区或经验水平等条件的影响。这些静态提要中的每个项都有几乎永久的生命周期,至少在有更改或删除它的请求之前是如此。

相反,动态提要具有可配置的复杂排名策略,能够根据紧急性、相关性和其他标准将项目推到提要的顶部。

现在,在回顾了提要驱动程序方面的产品需求之后,让我们看看内容交付系统的通信需求的更大范围。

更广泛的内容交付生态系统

像Uber这样的内容交付系统并不是孤立存在的,它在很大程度上受到内容创造和摄取机制的影响。为了提供流畅和功能性的用户体验,需要从头开始构建整个生态系统。在本节中,我们将讨论Uber是如何处理这一过程的。

乍一看,这条消息可能类似于社交网络,但有一个关键的区别:内容完全来自优步,而不是司机。作者并没有将他们的内容发送到数据中心的“荒野”中进行索引、独立排名和遗忘,而是积极地控制他们的内容的目标、定制和管理。从这个意义上说,Uber的内容发布系统与广告内容发布平台有更多的相似之处,而不是社交网络,因为互动是片面的,可能需要或促使用户做出回应。这种差异反过来又会影响饲料生态系统摄取和选择内容的方式。

针对

我们目前在Uber的司机应用程序上采用了三种主要的定位策略:基于事件的定位、实时匹配和批量消息。对于批量信息,我们根据优步的需求发明了一套全新的工具和服务。这个更广泛的系统中的每个后端服务都专门处理目标定位;然而,内容是通过一个连贯的前端体验提供给我们的用户的。

目标内容的生成有两种方式:第一种也是最简单的方式是使用内部UI工具手动定义一组规则或活动,第二种也是更复杂的方法是使用单独的服务生成内容。提供内容的服务通常监控系统中的指标或事件,并使用一些业务逻辑来执行额外的评估步骤。在这两种情况下,都使用了下图所示的基础设施:

图2:数据从优步现有的平台基础设施流向新的定位服务,这些服务可以通知司机应用程序的feed系统。
基于事件的目标

每当司机在移动应用程序上产生一个事件,比如越过地理围栏或完成一次旅行,就可能需要将实时消息推送到他们的信息流中。这在处理我们已经描述过的确认和通知用例时发挥了作用。为了推送该通知,我们设置了一个目标过滤器,等待特定事件发生;如果触发,此事件将导致一个消息发送到驱动程序提要。事件可以由任何动作触发,例如旅行请求、点击应用程序中的按钮、完成后台支付计算,甚至是司机越过特定的地理围栏。

在Uber,我们使用一个数据丰富的平台来处理事件。几乎所有发生在移动设备上的事情,包括地理坐标变化和用户交互,都会报告给网关服务并发送到我们的卡夫卡可供下游服务使用的流。目标定位基础设施主要利用Samza基于规则的引擎,可由UI工具配置,允许内容创建者根据特定规则(如地理围栏穿透)过滤事件,以生成消息并将其交付给用户。

大部分消息

BUlk消息传递非常适合有针对性的活动,例如针对特定群体的促销和公告。在此模型中,可以通过运行来批量发送消息蜂巢Hadoop,或火花作业脱机选择队列,然后将定制的消息推送到用户提要。

在Uber,几乎所有由移动设备产生的事件都被提取、转换并加载到一个Hadoop分布式文件系统(HDFS)并聚合。这允许通过Hive查询或Spark作业离线访问数据,以进行更复杂的队列选择。使用这项技术,内容创作者可以根据需要聚合事件的标准向用户发送消息,例如通过活动下降的阈值,来自骑手的投诉增加,或者只是根据驾驶员的驾驶历史向特定的驾驶员群体宣布一项新举措。在大多数情况下,使用基于hive的引擎查询HDFS表并将结果导出到队列系统,例如Cherami或卡夫卡。在结果排队之后,它们可以被feed系统使用并发送到移动设备。

实时匹配

在某些定向情况下,当司机打开应用程序并开始接受搭车服务时,必须评估某些标准。在这些情况下,内容将取决于动态参数,如位置和安装的应用程序版本。像这样的情况相当罕见,因为大多数用户的信息可以由应用主动发送,并被离线处理,供批量定位引擎进一步使用。然而,也有例外,在这种情况下,用户或应用程序状态的变化必须通过消息实时确认,例如,在新功能推出的情况下。

如今,许多软件公司都拥有某种实验平台(XP),该平台允许他们向可配置百分比的用户推出新功能,这些用户是根据某些标准(如国家、城市、地区和设备版本)选择的。这种特性的可用性以通过提要系统发送的消息的形式向用户宣布。在这些情况下,传递新特性信息的队列与接收该特性的队列完全一致是至关重要的。类似地,相同的XP应该能够对这两个问题产生一个答案:“该特性是否应该为用户启用?”以及“是否应该向用户显示关于这个新功能的消息?”在Uber,我们建立了自己的实时匹配器来解决这个用例。

饲料系统技术决策

扇出策略

在确定饲料中最有效的技术组成时,我们需要做出许多决定。

在标准内容交付生态系统中有两种存储内容的方法:为每个用户推送和预评估扇出- - - - - -写时)或根据请求索引、过滤和排序(读时扇出)。上面描述的目标选项直接影响提要系统处理内容的样式。定制的目标内容的推送会迫使feed系统设计遵循“扇出-写”模式。这主要有两个原因:

  • 实时交付:对于紧急消息,比如当司机必须被警告有关交通状况时,消息会在触发的同一时刻发送到他们的feed(例如,当用户撞到地理围栏边界或发生事件时)。
  • 效率:即使在不需要实时传递内容的情况下,扇出阅读也会导致轮询到目标引擎,因为它们包含目标逻辑。当队列规模较小时,大多数民意调查的结果都是空的,这将导致硬件的低效利用。

由于存在实时匹配目标,还必须支持读时扇出策略。因此,Uber的feed系统同时支持这两种策略,我们将在下一节中详细介绍。

实时推送vs.周期性轮询

由于优步的联合扇出策略,我们的提要以存储-通知或存储-推送模式运行,这取决于提要配置,同时还涉及为扇出-阅读配置的特定引擎和服务行为,如下所示:

图3:Uber的feed内容交付流程负责将内容交付给司机,以确保信息实时接收和注册。

饲料流

反馈端决定内容传递的流程。由于不能假定移动设备保持状态,后端服务必须能够在任何时候交付所有提要内容;每当设备需要获取最新状态时,移动应用程序就会调用提要内容。

一旦内部服务推送了一条新内容,反馈端就会将其存储在数据库中一段指定的时间,并通过推送机制通知移动设备。由推送触发,设备从后端请求一个新的反馈。此时,反馈端从数据库中检索存储的项,并调用其读时扇出服务以实时获取额外的项。步骤项经过聚合和排序后返回移动设备。

内容存储

在我们新的内容交付生态系统中,反馈后端将活动提要内容存储在数据库中。我们选择此模型是为了提高后续提要获取的性能,并在不应该再出现在提要中时删除内容。类似地,我们选择了卡珊德拉对于我们的存储需求超过其他技术,因为它能够处理数据中心复制和数据建模。

数据中心复制

来自乘客和司机合作伙伴的移动应用程序请求将根据地理位置接近度路由到全球的数据中心。然而,我们的一些内部内容生产服务只在这些数据中心中的一个活动(例如,Hive作业正在运行的地方),并且不知道驱动程序的位置。当生产者将内容推送到提要服务时,这些内容必须对跨数据中心托管的用户可用,以促进其可能的推出,而不管驱动程序位于何处。确保用户在任何时候都可以访问提要内容- - - - - -即使在网络故障切换期间- - - - - -用户流量可能被路由到备用数据中心。Cassandra的数据中心复制能力使我们在设计新的内容交付生态系统时可以轻松选择Cassandra。

数据建模

单个驱动程序的提要内容通常来自多个内部服务,这些服务可以在任何时间以任何速度推送内容。为了避免竞态条件,在将内容写入后端数据存储时,我们需要内容级粒度。当向移动客户端提供提要时,提要服务必须访问所有已保存的内容;为了实现这一点,我们需要读取数据的用户级粒度。

卡桑德拉的分区面向行数据模型完美地满足这些要求。选择用户ID作为分区键允许我们在单个请求中获取用户的所有可用项。这种类型的查询有一个常数时间复杂度项目类型的数量。通过选择用户ID、项目类型和项目ID作为复合主键,每个项本质上是数据存储中的一行。当跨组织的多个内容提供者同时为一个用户推送内容时,Cassandra将写入不同的行以避免任何竞争条件。

内容创作与设计

社交网络上的典型提要系统在表示层以不同的方式呈现内容,以实现自定义目的。为了减少表示代码的数量,公司通常尝试标准化他们的表示,只使用几种不同的设计。表示层(例如,前端代码或移动代码)然后将每种更新类型转换为一种UI设计。

在优步,我们在工作中学到了这一点。随着我们的产品中越来越多的提要内容类型,为每个新类别扩展和维护一个表示层成为整个提要系统的一个重大负担,原因有二:

  • 由于设计上的细微差异(如隐藏某些UI元素或添加额外按钮),开发新内容类型的代码必须添加到移动设备上,并针对每一种新内容类型推出。因此,鉴于我们服务的高速增长,设计的标准化和整合对我们来说是不现实的。
  • 即使相同的设计代码可以用于新类型的内容,它仍然需要编写新的表示代码来将新数据输入到该设计中。成品几乎不能重用,因此不能实时添加新类型的内容。这种策略对于我们的用例也是不可行的。

除了创建一系列可以根据内容类型进行插入和插入的内容设计之外,我们还推出了许多目标引擎,这些引擎能够在特定的设计中编写消息。我们考虑过让每个引擎提供自己的固定设计,但不出意外的是,有些设计不能在目标引擎之间重复使用,或者必须复制,这证明很耗时。

展示:Uber的内容交付生态系统

随着时间的推移,我们意识到我们需要构建一个新的工具来更好地创建和推出定制的内容设计,这样我们的提要系统的表示组件就可以使用单一的标准方法来呈现内容。

在这个模型的移动端,类似的设计可以被分割成可重用的组件,然后渲染引擎可以在运行时动态组合这些组件,允许内容创建者在内容创建过程中选择特定的视觉设计配置。

图4:优步的移动内容交付生态系统基础设施,使其更容易、更有效地结合司机应用程序feed消息的定制设计。

提要上的内容由UI工具编写,该工具允许内容创建者从可重用的块(如标题、图像、列表或按钮集等)中将其消息的特定设计拼接在一起,并填写每个块中内容的实际语言。这个过程使我们能够为来自目标引擎、用户配置文件和其他来源的数据注入模板占位符。

然后,我们最终设计模板的定义被序列化为对象表示法(JSON)格式,并由移动设备上的引擎呈现。该工具生成的设计模板存储在单独的数据库中,可以被目标引擎引用。使用这个系统,我们将目标引擎和其他服务提供的逻辑与现在由单一内容设计工具提供的表示逻辑分开。

通过允许相同的设计模板用于多个目标引擎,我们在整个平台上实现了丰富而一致的内容定制功能。此外,这一决定使我们无需修改大多数新设计的移动代码,并有助于推动应用程序的标准化观感通过定义一组固定的块。为用户提供更新的新服务不再需要处理表示方面的问题,例如将提要内容翻译成其他语言,并且可以专注于针对特定内容的正确驱动程序队列。通过这种基于块的设计方法,Uber的移动内容创建工具也可以在几分钟内制作新内容并翻译,而这个过程以前需要几个小时到几天。

这个全新的、易于使用的移动内容传递生态系统与优步广泛使用的许多服务和定位工具无缝集成,使工程师和客户支持能够迅速创建相关信息,并将其传递给司机,进而传递给我们的乘客。

如果你对这类工作感兴趣,可以考虑申请我们的职位驾驶员体验团队

Alex Forsythe, Denis Haenikel和Minjie Zha是Uber司机体验团队的软件工程师。何佳多(Jiaduo He)和罗宇佳(Yujia Luo)也是Driver Experience团队的软件工程师,他们对本文也有贡献。

评论