利用ELK实时设计优步预测gydF4y2Ba

0gydF4y2Ba
利用ELK实时设计优步预测gydF4y2Ba

优步的服务依赖于我们的准确性gydF4y2Ba事件的预测gydF4y2Ba一个gydF4y2BangydF4y2BadgydF4y2BafgydF4y2BaogydF4y2BargydF4y2BaegydF4y2BacgydF4y2Ba一个gydF4y2Ba年代gydF4y2BatgydF4y2Ba我gydF4y2BangydF4y2BaggydF4y2BatgydF4y2BaogydF4y2BaogydF4y2BalgydF4y2Ba年代gydF4y2Ba。从估算给定日期的骑手需求到预测gydF4y2BaUbereats.gydF4y2Ba订单将到达,优步使用预测算法来增强我们的产品组合的用户体验(UX)。gydF4y2Ba

为了建立精确且易于解释的工程和操作的预测经验,我们通过利用分布式开源建立了自定义预测系统gydF4y2Ba宁静的搜索引擎gydF4y2Ba由查询引擎组成gydF4y2BaElasticsearch.gydF4y2Ba,数据索引管道gydF4y2Balogstash.gydF4y2Ba,以及可视化工具gydF4y2BakibanagydF4y2Ba(麋鹿)。简单但功能强大,我们的结果体系结构易于伸缩并实时工作。gydF4y2Ba

在本文中,我们将讨论我们为什么以及如何构建这个系统,并分享使用Elasticsearch的最佳实践和经验教训。gydF4y2Ba

设计一个定制的预测系统gydF4y2Ba

我们的预测质量通过与uberpool匹配率,匹配质量等的竞争功能相匹配的最终结果来衡量。gydF4y2Ba

我们需要设计一个高度可定制的架构,以便我们的预测系统可以与我们现有的产品同步,因为:gydF4y2Ba

  • 某些行程功能仅适用于Uberpool,例如匹配速率和匹配质量。gydF4y2Ba
  • 我们产品的具体特性gydF4y2Ba- - - - - -gydF4y2BaUberpool,Uberx,Uberblack等。gydF4y2Ba- - - - - -gydF4y2Ba经常影响行程特点。例如,uberPOOL有一个功能,但uberX和UberBLACK没有,可能会影响整体平衡。gydF4y2Ba
  • 乘客和司机的行为,比如选择不同于优步建议的路线,会影响预测。gydF4y2Ba

为满足上述要求,我们将新预测系统的产品要求定义为:gydF4y2Ba

  1. product-aware。gydF4y2Ba准确区分骑手使用的是哪个产品,并在必要时改变我们的预测,这对于无缝的用户体验至关重要。gydF4y2Ba
  2. 每种产品确保低平均误差。gydF4y2Ba每个产品的平均预测误差需要尽可能接近零,以保持我们预测的整体准确性。gydF4y2Ba
  3. 保持一个较低的gydF4y2Ba平均绝对错误gydF4y2Ba每种产品gydF4y2Ba。此外,每个产品的平均绝对预测误差需要尽可能接近零,以确保各个时间或位置精度。gydF4y2Ba

除了满足产品要求外,还需要遵守特定的工程标准。高可用性,低延迟,可扩展性和运营友好性对我们预测系统的成功至关重要,因为该模型将在数百万个城市和数十个国家提供数百万用户。在设置这些指南后,我们为可以满足这些基准测试的算法提供了算法的蓝图,可评估在线和离线设计。gydF4y2Ba

构建一个在线算法gydF4y2Ba

在Uber,我们经常结合使用历史和实时出行数据来训练我们的出行预测算法。虽然我们可以根据地点、日期、时间和其他变量预测一些模式,如行程密度和匹配率,但这些模式会随着我们系统的进步和业务向新市场的扩展而调整。因此,实时或近实时捕捉系统动力学对预测精度至关重要。gydF4y2Ba

为了使精度最大化,我们决定使用不需要太多训练和模型维护工作的在线算法。我们选择gydF4y2Bak-inceltebors算法gydF4y2Ba(然而)发现gydF4y2BakgydF4y2Ba最近的邻居(指一段时间内类似的历史旅行),然后对它们进行回归以创建预测。这两步算法的工作原理是:gydF4y2Ba

  1. 选择gydF4y2BakgydF4y2Ba候选人基于我们的自定义gydF4y2Ba相似函数gydF4y2Ba源自:Geolocations,Time等的功能gydF4y2Ba
  2. 根据相似度函数计算每个候选项的权重,并将每个响应变量的加权平均值作为输出。gydF4y2Ba

该算法的第二部分主要是局部计算,工程挑战小,而算法的第一部分更具挑战性。基本上是一个大规模的gydF4y2Ba搜索问题gydF4y2Ba,这一步需要一个相对复杂的相似性函数来对候选项进行排序并选择排名靠前的gydF4y2BaKgydF4y2Ba作为算法的第二部分的输入。我们这里的目标是将最相似的历史旅行分组出大量的旅行。非常困难使用所有的旅行gydF4y2Ba相似函数gydF4y2Ba在搜索引擎中,因为数据的多样性和数量。相反,我们通过两个步骤实现这一点:gydF4y2Ba

  • 通过应用高级过滤逻辑来减少搜索空间,例如,通过城市或产品ID过滤数据。gydF4y2Ba
  • 在减少的数据集上执行基于相似的排名,然后选择“排名”gydF4y2BaKgydF4y2Ba出来。gydF4y2Ba

KNN虽然功能强大,但在处理大规模数据时是一个具有挑战性的算法。为了有效地使用它,我们需要一个能够每秒处理数千个查询(QPS)和同时处理数亿条记录的健壮的存储和搜索引擎。我们还需要地理空间查询支持来帮助过滤gydF4y2BakgydF4y2Ba候选人。gydF4y2Ba

使用ELK作为数据存储和搜索引擎gydF4y2Ba

我们简要介绍了其他支持地理空间查询的数据库,比如gydF4y2BaMySQLgydF4y2Ba,我们的模式灵活性需求和搜索需求使我们很容易决定使用开源ELK解决方案来增强我们的数据存储和搜索引擎。gydF4y2Ba

用Elasticsearch,Logstash和Kibana建造的麋鹿是一个用于实时搜索和分析数据的集成解决方案。Elasticsearch是解决方案的核心,是一个内置于顶部的搜索引擎gydF4y2BaApache Lucene.gydF4y2Ba。它提供分布式全文搜索,具有RESTful接口和无模式gydF4y2BaJSONgydF4y2Ba文件。LogStash是数据集合和日志解析引擎,Kibana是Elasticsearch的数据可视化和分析插件。gydF4y2Ba

Elk对我们来说是一个简单的选择,因为它提供了全文搜索,地理空间查询,架构灵活性和易于组装的数据管道。(ELK可以通过摄取Kafka主题在近实时加载数据。)ELK提供了满足我们的工程准则所需的灵活性,并为我们的车手提供准确的快速预测系统。gydF4y2Ba

系统架构gydF4y2Ba

在基本级别,我们的预测架构是使用的gydF4y2BaKafka.gydF4y2Ba数据流,gydF4y2Ba蜂巢gydF4y2Ba作为管理查询和分析的数据仓库,以及使用ELK堆栈创建健壮的预测系统的四个独立内部服务。下面,我们将概述这四种服务并描述其整体架构:gydF4y2Ba

  • 预测服务:gydF4y2Ba实时为用户提供预测服务gydF4y2Ba
  • 培训服务:gydF4y2Ba离线训练参数和数据管道gydF4y2Ba
  • 旅行服务:gydF4y2Ba管理从请求到完成的整个行程生命周期的状态gydF4y2Ba
  • 配置服务:gydF4y2Ba存储和为其他服务提供训练有素的参数gydF4y2Ba
实时预测系统的整体架构由数据管道、培训和服务逻辑组成。gydF4y2Ba

数据管道gydF4y2Ba

我们的数据存储由完整的行程数据、行程时间、距离和成本等指标组成。为了快速高效地工作,我们的管道必须能够接近实时地摄取和提供这些行程数据。我们的解决方案是在旅行结束时发布数据到Kafka主题。从那里,Logstash吸收Kafka主题,转换和索引数据到Elasticsearch。设置数据管道是为了立即进行数据查询,通过使用最近的行程确保最佳性能。我们还需要一个用于存储和分析的主存储;我们利用Hive作为一个提取、转换和加载(ETL)工具来管理Kafka处理的数据。在这两个数据管道中,我们使用ELK进行实时查询,使用Hive进行训练和分析。gydF4y2Ba

培训参数gydF4y2Ba

KNN回归是一种在线算法,这意味着我们不需要为它训练模型。但值gydF4y2BakgydF4y2Ba并需要相应地培训并选择回归参数。我们建立了一个培训服务,以选择值gydF4y2BaKgydF4y2Ba和回归参数。该服务可以以不同的粒度训练这些参数,还可以输出全局默认值、每个国家的值、每个城市的值和每个产品的值。一旦这些参数被训练,训练服务就会将这些值推送到动态配置服务中。gydF4y2Ba

从那里,配置服务为我们的预测服务提供可操作的参数。然后,旅行服务从我们的预测服务中致电即将到来的旅行中的预测指标。在此步骤中,我们的预测服务查询候选者的Elasticsearch和参数的配置服务,将它们馈送到算法中以生成预测。预测结果将返回我们的旅行服务并作为跳闸数据存储,后来将发布到Elasticsearch和Hive,因此我们可以跟踪我们预测的性能,以培训未来参数并提高准确性。gydF4y2Ba

生长在优步规模gydF4y2Ba

我们的预测系统被优化为gydF4y2Ba水平可扩展性gydF4y2Ba跨市场和产品,因此首先实施和维护相对容易。但是,随着我们扩展我们的规模,在更多城市中纳入更多产品,我们必须考虑由A引起的高延迟gydF4y2Ba垃圾收集gydF4y2BaCPU过度令诱导的暂停和级联故障。这两个问题都是通过过载弹性科节点引起的,因此我们将我们的努力提高了搜索性能并设计了更可扩展的架构。gydF4y2Ba

减少查询大小以提高搜索性能gydF4y2Ba

Elasticsearch中的数据大小;大指标意味着太多的数据,缓存搅拌,响应时间不佳。当查询卷很大时,ELK节点变得过载,导致长垃圾收集暂停甚至系统中断。gydF4y2Ba

为了解决这个问题,我们切换到六边形查询,将映射划分为六边形的单元格。每个六边形单元格都有一个由六边形分辨率级别确定的字符串ID。地理距离查询可以大致转换为一个六边形id环;虽然六边形环不是一个圆形表面,但对于我们的用例来说它已经足够接近了。由于这个调整,我们的系统的查询容量增加了三倍以上。gydF4y2Ba

使用虚拟群集水平缩放gydF4y2Ba

随着系统扩展到新市场,我们需要将更多节点添加到群集中。缩放弹性研究的常见方法是水平添加更多节点。为此,我们将跳闸数据组织成日常索引,每个索引都具有单个碎片,复制到群集中的所有数据节点。一种gydF4y2BaHAProxygydF4y2Ba部署以将搜索流量平衡到群集中的所有数据节点。在该模型中,该系统相对于群集节点的数量是线性可伸缩的。gydF4y2Ba

但是,随着节点的增加,集群变得不稳定。虽然单个集群体系结构每秒可以处理大约3000个查询,但我们的系统总共有40个节点(还在计算中),每个节点的大小为500GB。在这个范围内,集群间节点通信的成本开始超过使用大型集群的好处。gydF4y2Ba

为了克服这个限制,我们开发了一个虚拟集群。这是一种不常见的架构选择,虚拟集群由共享相同集群别名的多个物理集群组成。通过指定集群别名,应用程序可以通过HAProxy访问虚拟集群,并且请求可以路由到使用集群别名的任何集群。通过这种架构,我们可以通过添加更多的集群实现几乎无限的可伸缩性。gydF4y2Ba

经验教训:Elasticsearch作为NoSQL数据库gydF4y2Ba

我们使用Elasticsearch作为二级存储——将数据异步推送给它——因为它不是为一致性而设计的。为了有效地利用其有价值的搜索功能,我们需要小心地操作Elasticsearch。下面,我们将概述使用这个强大而复杂的数据库所获得的一些经验教训:gydF4y2Ba

  • 提供足够的资源。gydF4y2BaElasticsearch在有充足资源支持的情况下工作起来很有魅力。它是为速度和强大的功能而设计的,假定硬件和人员是丰富的。然而,当资源受限时,它就会停滞不前。为了充分利用Elasticsearch,您需要了解所处理的规模并提供足够的资源。gydF4y2Ba
  • 根据业务逻辑组织数据。gydF4y2Ba当数据的大小太大,无法容纳一个节点时,您需要智能地组织数据。gydF4y2Ba
  • 订购Elasticsearch查询以提高效率。gydF4y2BaElasticsearch在其查询中支持许多过滤器,它们的顺序对性能有很大影响。更具体的过滤器应该优先排序,并放在不那么具体的过滤器之前,以便它们可以在查询过程中尽可能早地过滤掉尽可能多的数据。在实现资源密集型过滤器之前,应该先实现资源密集型过滤器,这样它们可以过滤更少的数据。类似地,可缓存的过滤器应该放在不可缓存的过滤器之前,这样它可以更好地利用缓存。gydF4y2Ba

Uber新的实时预测系统现已在全球400个城市推出。有很多待办事项,因此如果在Uber-Scale的系统的架构预测算法,请考虑gydF4y2Ba加入我们不断壮大的群体gydF4y2Ba共享乘车或基础设施团队。gydF4y2Ba

我们与预测和麋鹿的旅程只刚刚开始 - 你是游戏吗?gydF4y2Ba

谢国成(音)是优步拼车团队的软件工程师。黄艳君(Yanjun Huang)是优步基础设施团队的工程师。gydF4y2Ba

更新:由于优步首先开始使用麋鹿,因此ELK堆栈扩展到包括其他技术,现在被称为gydF4y2Ba弹性堆栈gydF4y2Ba。gydF4y2Ba

注释gydF4y2Ba