从驾驶员和骑手的位置和目的地到餐厅订单和付款交易,Uber运输平台上的每一次互动都由数据驱动。数据为Uber的全球市场提供了动力,为全球骑手,驾驶员和食客提供了在我们的产品中更可靠和无缝的用户体验,并赋予我们自己的员工能够更有效地完成工作。
Uber随着其系统的复杂性和数据广度,将数据驱动到一个新的水平,每天处理数万亿个Kafka消息,将数百次数据存储在HDFS跨多个数据中心,并支持数百万个每周的分析查询。
但是,大数据本身不足以利用见解。要高效地使用,Uber量表的数据需要上下文来做出业务决策并获得见解。为了提供进一步的见解,我们构建了Databook,这是Uber的内部平台,该平台表面和管理有关某些DAT的内部位置和所有者的元数据ASET,使我们能够将数据转化为知识。
指数业务(和数据)增长
自2016年以来,Uber在其平台上添加了几条新业务,包括优步吃,,,,优步货运, 和跳自行车。现在,我们每天完成超过1500万次旅行,每月有超过7500万的活跃骑手。在过去的八年中,该公司从一家小型初创公司增长到全球18,000名员工。
随着这种增长,数据系统和工程架构的复杂性越来越复杂。例如,我们使用的多个分析引擎中存在数以万计的表蜂巢,,,,普雷斯托, 和Vertica。这种分散使得必须完全了解可用的信息,尤其是当我们继续添加新的企业数据和员工时。2015年,Uber开始使用手动维护的一组静态HTML文件来对其表进行分类。
随着公司的发展,我们需要更新的表和相关元数据的数量也是如此。为了确保我们的数据分析能够跟上公司的增长速度,我们需要一种更简单,更快的方法来进行这些更新。在这种规模和增长的范围内,发现所有数据集及其相关的元数据的强大系统不仅仅是很好:这对于使数据在Uber中有用绝对是不可或缺的。
为了使数据集发现和探索更加容易,我们创建了数据库。数据库平台管理和表面丰富的元数据有关Uber的数据集,使整个Uber的员工能够在Uber探索,发现和有效地利用数据。数据库确保有关数据的背景(其含义,质量等等)并没有在数千个试图分析数据的人中丢失。简而言之,Databook的元数据赋予了Uber的工程师,数据科学家和运营团队的能力,从查看原始数据转变为具有可行的知识。
借助Databook,我们从进行手动更新到利用高级,自动化的元数据商店来收集各种经常刷新的元数据。数据库包含以下功能:
- 可扩展性:新的元数据,存储和实体很容易添加。
- 可访问性:服务可以通过编程方式访问所有元数据。
- 可伸缩性:支持高通量阅读。
- 力量:跨数据中心读写。
Databook提供了来自Hive,Vertica的各种元数据,mysql,,,,Postgres,,,,卡桑德拉,以及其他几个内部存储系统,包括:
- 表模式
- 表/列描述
- 样本数据
- 统计数据
- 血统
- 餐桌新鲜度,SLA和所有者
- 个人数据分类
通过中央UI和A中的可视化均可访问所有元数据RESTFUL API。Databook UI使用户可以轻松访问元数据,而API允许数据库元数据为Uber上的其他服务和用例供电。
虽然像LinkedIn这样的开源解决方案哪里已经存在,游戏框架和gradle在Databook开发期间,Uber不支持。在其中也缺乏跨数据中心的读写支持,这对我们的性能需求至关重要。因此,我们着手构建自己的内部解决方案,用Java编写,以利用其内置功能和成熟的生态系统。
接下来,我们将为您介绍如何创建数据库以及在此过程中遇到的挑战。
数据库架构
Databook的架构可以分为三个部分:如何收集元数据,如何存储元数据以及元数据浮出水面。图2,下面描绘了该工具的整体体系结构:
数据库将多个源作为输入摄入,存储相关的元数据,并通过Restful API输出此信息,该信息为数据库UI提供动力。
当第一次设计数据库时,我们必须做出的一个重大决定是我们是否会根据要求存储我们收集或获取它的元数据。我们的服务需要支持高通量和低延迟阅读,如果我们将这项责任委托给元数据来源,它将需要所有来源来支持高通量和低延迟阅读,这将引入复杂性和风险。例如,获取表格架构的Vertica查询通常需要几秒钟的时间来处理,从而使其不适合可视化。同样,我们的Hive Metastore管理了Hive的所有元数据,因此需要支持高通量读取请求的风险。由于Databook支持了许多不同的元数据源,因此我们决定将元数据存储在Databook架构本身中。此外,尽管大多数用例都需要新鲜的元数据,但它们不需要实时看到元数据的变化,从而使周期性爬行成为可能。
我们还将请求服务层与数据收集层分开,因此每个过程都在单独的过程中运行,如图3所示,如下所示:
这将两层隔离,从而减少了附带影响。例如,数据收集爬行作业可能会使用重要的系统资源,这可能会影响请求层上的API SLA。此外,与Databook的请求服务层相比,数据收集层对中断的敏感程度较小,以确保如果数据收集层降低,则将仍然提供过时的元数据,从而最大程度地减少对用户的影响。
e基于通风口的收藏与预定收藏
我们的下一个挑战是确定我们如何从几个不同的,不同的数据源中最有效和性能地收集元数据。我们考虑了多个选项,包括:以分布式方式创建耐故障框架,并利用基于事件的流以实时检测和调试问题。
我们首先创建了爬行者,以定期从我们的各种数据源和微服务中收集信息,以生成有关数据集的元数据信息,例如我们强大的开源工具得出的表统计信息,用于解析和分析SQL,Queryparser。(有趣的事实:QueryParser也由我们的数据知识平台团队构建)。
我们需要以可扩展的方式经常收集元数据信息,而不会阻止其他爬网任务;为了做到这一点,我们将爬行者部署到不同的机器上,需要以分布式方式在爬行者之间有效协调。我们考虑了配置石英在分布式调度的聚类模式下(由MySQL支持)。但是,我们面对两个阻止者,使我们无法实现此解决方案:首先,在多个计算机上以聚类模式运行石英,需要石英时钟为同步定期添加外部依赖性,其次,我们在调度程序启动后经历了恒定的MySQL连接不稳定。结果,我们排除了以聚类模式运行石英。
但是,我们仍然决定使用石英进行强大的内存计划功能,以使发布任务更加容易,更有效地进入我们的任务队列。对于Databook的任务队列,我们利用Uber的开源任务执行框架,切拉米。这个开源工具允许我们在分布式系统中解脱消费者应用程序,使它们能够以异步的方式在多个消费者组中进行交流。使用Cherami,我们将Docker容器中的爬行者部署到了不同的主机和多个数据中心中。使用Cherami使得可以从许多不同的来源收集各种元数据,而不会阻止任何任务,同时将CPU和内存消耗保持在理想的水平和单个主机中。
尽管我们的爬行者适用于大多数元数据类型,但需要实时捕获一些元数据,这就是为什么我们决定使用KAFKA过渡到基于事件的架构的原因。因此,我们能够立即检测和调试数据中断。我们的系统还可以捕获关键的元数据变化,例如数据集谱系和新鲜度,如下图4所示:
该体系结构使我们的系统能够以编程方式触发其他微服务,并近乎实时向数据用户发送通信。但是,我们仍然使用爬行者来进行诸如收集(或刷新)示例数据,针对目标资源的节流请求以及当发生自动触发其他系统的事件时需要收集的元数据(例如,数据集用法)统计数据)。
除了接近实时进行轮询和收集元数据外,数据库UI还从数据集消费者和生产者(例如表和列的描述)中收集有关数据集的手册,语义信息。
我们如何存储元数据
在Uber,我们的大多数管道都以多个簇运行,以实现故障转移目的。结果,某些类型的元数据的值(例如,延迟和用法)在同一表之间在不同的群集上可能有所不同,这些簇定义为群集特异性。相反,从用户收集的手册元数据是群集 - 不可思议的:描述和所有权信息在整个集群之间适用于同一表。为了正确链接这两种类型的元数据,例如将列描述与所有簇中的表列关联在一起,可以采用两种潜在方法:在读取过程中写或链接期间链接。
写入期间的链接
当将特定于集群的元数据与群集 - 敏锐的元数据相关联时,最直接的策略是在写入过程中将元数据链接在一起。例如,当用户将列描述添加到给定的表列时,我们将信息坚持到所有群集中,如下图5所示:
这种方法可确保持续的数据处于干净状态。例如,在图5中,如果“第1列”不存在,它将拒绝该请求。但是,存在一个主要问题:要在写入时间内将群集 - 敏锐的元数据链接到特定于集群的元数据,所有特定于集群的元数据都必须存在,并且时间上只有一个机会。例如,当图4中触发描述时,只有群集1具有此“第1列”,因此写入群集2失败。后来,集群2中同一张表格的模式被更新了,但是机会已经消失了,除非我们定期重试,否则该描述将永远无法使用,从而使系统复杂化。图6,下面描绘了这种情况:
阅读过程中的链接
实现目标的另一种方法是在阅读过程中链接群集 - 不稳定和特定于集群的元数据。这种方法解决了在写入过程中链接中缺少元数据的问题,因为每当存在特定于群集的元数据时,这两种类型的元数据在阅读过程中链接。当架构更新后“第1列”显示时,将在用户阅读的时间合并其描述,如图7所示,如下所示:
存储选择
MySQL最初用于为Databook的后端供电,因为它可以快速开发,并且可以通过Uber的基础架构门户自动提供。但是,当涉及到多数据中心的支持时,共享的MySQL群集并不理想,原因有三个:
- 一个主人:首先,在Uber支持只有单个主人,从而从其他数据中心获得了缓慢的写入时间(在我们的情况下为每个写作添加约70ms)。
- 手动促销:第二,当时不支持自动促销。结果,如果主节点下降,则花了几个小时才能宣传新的主节点。
- 数据量:我们从MySQL切换的另一个原因是Uber生成的大量数据。我们打算保持所有历史的变化,并希望我们的系统支持将来的扩展,而无需花费太多时间进行集群维护。
由于这些原因,我们选择Cassandra替换MySQL,因为它具有强大的XDC复制支持,从而使我们能够从多个数据中心编写数据而不会遭受延迟增加。而且,由于卡桑德拉(Cassandra)是线性可扩展的,因此我们不再需要担心适应Uber不断增加的数据量。
我们如何表面数据
Databook提供了访问元数据的两种主要手段:一个RESTful API和Visual UI。Databook的Rentful API由Dropwizard这是用于高性能恢复Web服务的Java框架,并部署在多台机器中,并由Uber内部请求转发服务平衡。
在Uber,数据库主要由其他服务以程序化方式访问数据。例如,我们的内部查询解析/重写服务依赖于Databook中的表模式信息。API可以支持高通量读取,并且可以水平扩展,并且当前的峰值查询约为1,500。可视化UI用React.js和Redux以及D3.J编写,主要由工程师,数据科学家,数据分析师和整个公司的运营团队使用,以分类数据质量问题并识别和探索相关数据集。
搜索
搜索是数据库UI的关键功能,使用户能够轻松访问和导航表格元数据。我们使用Elasticsearch作为我们的全索引搜索引擎,这反过来又同步了来自Cassandra的数据。使用Databook,用户可以跨多个维度搜索,例如名称,所有者,列和嵌套列,如下图8所示,启用新鲜和更准确的数据分析:
数据库的下一章
借助Databook,Uber的Metadata现在比以往任何时候都更加可行和有用,但是我们仍在通过建立新的,更强大的功能来扩大影响。我们希望为数据库开发的一些功能包括使用机器学习模型生成数据见解的能力,并创建高级问题检测,预防和缓解机制。
如果构建可扩展的,智能服务和开发创新的复杂技术,以及内部和开源解决方案都吸引您,请与佐伊·艾布拉姆斯(Zoe Abrams)联系(za@uber.com)或申请角色在我们的团队中!






