Uber无模式数据存储

设计无模式。Uber工程师使用MySQL定制数据库,允许我们从2014向后扩展。这是无模式三部分系列的第一部分。
在项目Mezzanine中,我们描述了如和从单一Postgres实例迁移Uber核心到无模式、容错以及高可用的数据库。这篇文章进一步描述其结构以及扩展已经存在Uber基础设施的无模式的作用,以及怎么走过来的。

新数据库竞赛

早在2014年,由于蓬勃发展的行程增长,我们用尽了数据库空间。每个新城市和行程里程碑将我们推向悬崖,那时,我们意识到Uber的基础设施将会年底无法工作:我们无法在Postgres上存储足够的行程数据。我们的任务是为Uber实现下一代数据库技术,这个任务花了多个月的时间,涉及到来自世界各地的工程师。
但是首先,为什么当丰富的商业和开源软件已经存在,还需要搭建一个可扩展的数据存储?对对新的形成数据存储我们有五个关键需求:

  • 我们新的结果通过增加更多服务需要能够线性增加的能力,Postgres的一个特性是缺乏设置。增加服务应能增加可用的磁盘存储,以及减少系统响应时间。
  • 我们需要写的可用性。我们之前实现了一个简单带有Redis的缓冲机制,因此如果些到Postgres失败,我们能够待会重试,因为在此期间行程被存储到Redis。但是在Redis,形成不能从Postgres中读取,我们失去了功能,例如计费。闹心的,是最后我们没有丢失行程。随着时间的推移,Uber增长,因此基于Redis的结果不能扩展。无模式提供了一个相似的机制作为Redis,但是在read-your-write语句上偏爱写的可用性。
  • 我们需要一种通知下游依赖的方式。在当前的系统,我们同时处理许多行程组件(如,billing,分析等等)。这是一个容易出错的处理:如果任何一步出错,我们不得不再重试一遍,尽管一些组件成功运行。这不可扩展,所以我们希望打破这些步骤为单独的步骤,由数据改变启动。我还有一个异步行程事件系统,但是他是基于Kafka 0.7的。我们不能无损的运行它,因此我们引进一个新的、类似的但是可以无损运行的系统。
  • 我们需要第二索引。正如我们从Postgres迁移时,新的存储系统必须支持Postgres索引,这意味着第二索引以相同方式搜索行程。
  • 我们需要系统操作的信任,因为他包括关键任务的行程数据。如果我们在凌晨3点时分页,数据存储没有响应查询,记录业务。我们能够有操作知识快速修复它?

鉴于上述情况,我们分析了一些替代常用系统,如Cassandra,Riak和MongoDB等等的优点和潜在限制。为了说明,下表显示了不用系统选项能力的不同组合:

虽然中三个系统都能够通过线上添加新节点线性扩展,只有一组系统能够在故障期间接受写入。这些方案都没有内置的方式通知下游依赖的改变,因此我们需要在应用水平实现这些。他们都有索引,但是如果你需要索引多个不同的值,查询非常缓慢,因为他们使用scatter-gather的模式查询所有节点。最后一些我们有单集群使用经验的系统,并没有提供面向用户的网络traffic,并且没有与我们服务链接的各种业务问题。
最后,我们面对使用系统操作信任的问题,因为他包含关键任务的行程数据。替代的解决方案或许能够在理论上可靠运行,但我们是否有操作经验能够直接执行他们最大能力,极大的影响了我们的决定,我最后决定在Uber使用的情况下开发适合我们的解决方案。这不仅依赖于我们使用的技术,而且依赖在团队中使用的经验。
我们应该注意,因为我们调查选项超过两年多,没有发现合适行程存储的使用情况,我们在我们基础设施的其他领域成功地采用了Cassandra和Riak,并且在生产用使用以服务数以百万规模的用户。

我们相信无模式

由于上述选项在我们给出的时间框架下没有满足我们的需求,我们决定构建我们自己的操作简便的系统,同时吸取别人的教训应用scaling。设计是Friendfeed启发的,和重点业务方面由Pinterest启发。
我们最终建立一个key-value存储,在无模式的方式下(因此得名),允许你保存任何JSON数据不需要严格的模式验证。具有由MySQL共享的append-only模式,并带有缓冲写入以支持MySQL主节点出错,和一个当数据改变时通知发布订阅的功能。最后,无模式支持数据全局索引。下面我们讨论数据模型和一些关键特征的概述,包括Uber行程的分解,为了后续文章保留更深的例子。

无模式数据模型

无模式是一个只追加的稀疏的三维持久的hash map,和google的Bigtable非常相似。无模式中,最小的数据实体被称为一个cell,并且是不可变的;一旦写入,不能覆盖写和删除。cell是一个JSON由row key,column name,和一个名为ref key的引用key组成的blob,其中colum name是一个字符串,引用key是一个整数。
你可以认为row key是关系型数据库中的主键,column name是一个column。然而,在无模式中,没有预定义或强制模式,并且row不需要共享column name;实时上,column name完全由应用程序定义的。ref key用于确定给定row key 和列的cell版本。因此如果一个cell需要更新,你可以编写一个更大的ref key写入一个新的cell(最新的cell是有最高ref key的那个)。ref key也用于列表条目,但是通常用于版本。应用决定使用那个schema。
应用程序通常对相关数据中相同的列分组,然后没列种所有cell有大致相同的应用侧的schema。这种分组是一中捆绑改变数据的好方法,而且在数据库侧它允许应用迅速改变schema不需要停机时间。下面的例子讲更多的阐述这个问题。

例:无模式行程数据存储

在我们深入讨论我们如果在无模式中模型化一个行程之前,让我们看看Uber行程的分解。行程数据是不同时间点产生的,从搭乘,离去到付费,而这些不同部分的信息,由于人们反馈行程或者后台程序执行,是异步到达的。下图是一个简化的Uber行程:

一个行程是由合作伙伴,用户搭载,以及一个从开始到结束的时间戳。这些信息构成几本的行程,由此我们可以计算行程的花费(票价),这是用户的收到的账单。在行程结束之后,我们可能需要调整票价,要么信用卡或扣款。我们或许对这段行程添加评价,从用户或者车主(上图型号所示)得到反馈。或者,如果第一张过期或者拒绝的情况,我们可能需要尝试多张信用卡支付。Uber的行程流程是一个数据驱动的过程。随着数据变的可用或者被添加,那么确定一系列行程执行流程。这方面的信息,例如用户或车主的评分(上面注释的部分),在行程结束后几天收到。
那么,如何映射上述行程模型为无模式?

行程数据模型

使用斜体表示UUID,大写表示column name,下表显示一个行程存储的一个简化版本的数据模型。我们有两个行程{ trip_uuid1 ,trip_uuid2 }和四个列(BASE, STATUS, NOTES, and FARE ADJUSTMENT)。一个cell代表一个带有数字和一个JSON blob的格子(缩写为{…})。格子的叠加表示版本(即,不同的ref key)。

trip_uuid1有三个cell:一个在BASE列,两个在STATUS列,FARE ADJUSTMENT列为空。trip_uuid2有两个cell在BASE列,一个在NOTES列,同样的FARE ADJUSTMENT列为空。对于无模式,列是不同的,因此列的语法有应用定义的,在这种情况下是Mezzanine服务的。
在Mezzanine中,BASE列的cell包括基本行程信息,例如车主的UUID以及行程的时间。STATUS列包含行程当前的支付状态,我们为行程的每一次支付插入一个cell。(如果信用卡没有足够资金或者透支了,尝试可能失败)。如果有任何由车主或者Uber DOps (Driver Operations employee)离开关联的评价,NOTES列包含一个cell。最后如果票价被调整了,FARE ADJUSTMENT列包含cell。
使用切分后的列以避免数据竞争,并且最小化需要写入更新的数据数量。BASE列当一个行程完成是写入,因此通常只写入一次。STATUS列在BASE列的数据已经写入后,当尝试支付行程的行为发生,若支付失败可能发生多次时写入。NOTES列在BASE写入后的某个时间点可能被写入多次,但是它和STATUS列写入是完全分开的。相似的,如果行程费用改变,例如由于低效的路线,FARE ADJUSTMENTS只写入一次。

无模式触发器

无模式一个关键的特征是触发器,具有注意到改变转换为无模式实例的能力。因为cell是不可变的,并且新版本是追加的,每个cell也代表一个变化或者一个版本,允许实例中的值被视为更改日志。对一个给定的实例,监听这些变化,并基于它们触发功能是可能的,和事件bus系统如Kafka非常相似。
无模式触发器使得无模式完善了实测数据存储,因为除了数据随机存储,下游依赖可以使用触发功能监控,并触发任何特定应用的代码(相似的系统是Linkedin的DataBus),进行去耦数据的创建和处理。
对于其他使用案例,当BASE列写入到MEzzanin实例,Uber使用无模式触发为行程生成账单。鉴于上面的例子,当trip_uuid1 BASE列写入,在BASE列触发支付服务选取这个cell并尝试通过控制信用卡支付这次行程。控制信用卡的结果,不论成功或失败,写回到Mezzanine的STATUS列。这种方式的支付服务减弱行程的创建,无模式作为一个异步事件Bus。

索引便于访问

最后,无模式支持在JSON blob中字段定义的索引。索引是一个通过这些预定义字段的查询,以发现匹配查询参数的cell。查询这些索引是效率的,因为索引查询只需要到单一碎片发现cell集合并返回。事实上,查询可以进一步优化,因为无模式允许cell数据使用非规范化到索引。具有非规范化数据的索引意味着一个对于查询和检索信息,索引查询只需要去顾及一个碎片。实际中,我们通常推荐无模式用户规范化数据,用户可能认为除了直接通过row key直接检索cell情况外,查询任何信息需要索引。某种意义上来讲,因此为快速查询查找换取储存。
对于一个Mezaamine的例子,我们有一个定义为运行我们发现给定车主行程的辅助索引。我们已经非规范化行程创建时间和行程开始的城市。这使得在给定时间范围内查询某个城市车主的所有行程称为可能。下面我们给出以YAML形式的driver_partner_index定义,这是行程存储和定义在BASE列(本例标注#的注释)的一部分。
使用这个索引,对于由city_uuid 和/或trip_created_at过滤发现给定driver_partner_uuid所有行程。在这个例子中,我们只使用BASE列的字段,但是无模式支持多列的规范化数据,等同于上面的column_def列表中的多实例。
正如前面提到的无模式具有高效的索引,基于分片字段由分片索引实现。因此对索引的唯一要求是索引的字段之一是被指定为分片字段(上例中,为driver_partner_uuid,因为它最先给定)。分片字段决定那个分片实例应该被写入或检索。原因是当我们查询索引时需要提供分片字段。这意味着在查下你期间,我们需要顾及检索索引实例的一个分区。关于分区字段有一点要注意的他应该有一个良好的分布。UUID是最好的,city ids是次优的,并且状态字段(枚举)不利于存储。
除了分片字段,无模式支持相等,不等和过滤范围查询,并且支持在索引中指选择字段子集以及对索引实例指向的row key检索特定或所有列。目前,分片字段必须是不可变的,因此无模式总是需要访问一个碎片。但是我们正探索如何使其可变并且不没有大量性能开销。
索引是最终一致的,每当我们写入cell同样也要更新索引实例,但是不会在同一事务发生。cell和索引实例通常不属于同样的分区。因此如果我们能够提供一致的索引,在写入时需要引入2PC,否则会产生显著开销。随着最终一致索引避免了开销,但无模式用户可能在索引中发现过期数据。大多数cell变化和响应索引改变之间的滞后远远低于20ms

总结

给出了数据模型,触发器和索引的概览,所有这些是定义无模式的关键特征,行程存储引擎的主要部件。在以后的文章中,我们将看看无模式的其他一些功能来说明它如何成为一个受欢迎的Uber基础设施的服务:更多的架构,使用MySQL作为存储节点,以及我们如果触发客户端侧的容错。

Uber无模式数据存储相关推荐

  1. VMware vSphere 5.1 群集深入解析(二十六)- 数据存储维护模式汇总

    VMware vSphere 5.1 Clustering Deepdive HA.DRS.Storage DRS.Stretched Clusters Duncan Epping &Fran ...

  2. 虚拟化磁盘模式、数据存储详解

    虚拟化磁盘模式.数据存储详解 1. 配置模式 1.1. 普通 1.2. 普通延迟置零 1.3. 精简 2. 磁盘模式 2.1. 从属 2.2. 独立-持久 2.3. 独立-非持久 3. 数据存储 3. ...

  3. mysql 存储模式_FriendFeed 如何使用 MySQL 来存储无模式的数据

    背景 我们使用MySQL存储了FriendFeed的所有数据.数据库随着用户基数的增长而增长了很多.现在已经存储了超过2.5亿条记录与一堆涵盖了从评论和"喜欢"到好友列表的其他数据 ...

  4. 被捞起的“海底数据中心”,故障率仅为陆地1/8,微软新型数据存储模式又有新进展...

    微软让数据存储更加环保. " 作者 | 贝爽 "水下数据中心"可以提高能源效率,至少微软是这样认为的. 近日,微软将已经沉入海底两年的数据中心打捞出了水面,经研究人员评估 ...

  5. 重新加一个window_Activity、View、Window关系,进程间通信,责任链模式,Https,数据存储...

    码仔,今天就给大家带来了<每日一道面试题>的第九期: 01 理解Activity View window的关系 Activity像一个工匠(控制单元),Window像窗户(承载模型),Vi ...

  6. c51语言的数据存储模式,第5章项目三单片机存储结构及C51语言.ppt

    第5章项目三单片机存储结构及C51语言 项目三 基本功 任务一 MCS-51单片机基础 任务二 单片机C51语言程序设计基础 二.MCS-51单片机存储器及存储空间 1.存储器的概念 什么是存储器呢? ...

  7. SaaS模式、技术与案例详解——第12章 数据存储

    [本章导读语] 不积跬步,无以至千里. ________<荀子.劝学篇> 信任,或是缺乏充分信任,都是妨碍SaaS推广的首要问题.我们可以说,关于产品.客户.雇员.供应商等的数据是商业运营 ...

  8. 租户隔离怎么做MYSQL_基于JPA实现SaaS多租户模式的数据存储——共享数据库,隔离数据架构...

    SaaS是Software-as-a-Service(软件即服务)的简称,这边具体的解释不介绍.多租户的系统可以应用这种模式的思想,将思想融入到系统的设计之中. 现在SaaS Multi-Tenant ...

  9. NAS:以数据为中心的数据存储模式[zt]

    NAS:以数据为中心的数据存储模式 (澳柯玛天地数码科技有限公司 2001年05月30日 17:20) 计算机给世界的发展带来了巨大的动力.科技的进步,使人们急需从各种地方获得有效的资源.网络时代的发 ...

最新文章

  1. 【转】Vue.js 2.0 快速上手精华梳理
  2. SharpWebMail介绍和安装(转)
  3. 必须认识的http请求包
  4. (六) Docker 容器命令
  5. Kotlin 学习笔记01
  6. High Logic MainType 10中文版
  7. golang语言编译的二进制可执行文件为什么比 C 语言大(转载)
  8. linux下oracle开机自启动,Linux下开机自动启动Oracle的设置
  9. python爬取知乎标题_python爬虫 爬取知乎文章标题及评论
  10. HDU2564 词组缩写【文本】
  11. bluem2.com引擎mysql,蓝色bluem2引擎登录器配置教程详细,bluem2列表格式
  12. div+css实现盖章
  13. 【翻译】图解Janusgraph系列-事务详解(Janusgraph Transactions)
  14. 百度图片爬虫【图片编码处理】
  15. 一名优秀的数据分析,需要满足哪些基本条件?
  16. 临床试验中lm是什么职位_除了CRX职位,临床试验中还有这些岗位
  17. KDD Cup 2020多模态召回比赛季军方案与广告业务应用
  18. 计算机各个接口PCB-Layout 规则要求
  19. 图片怎样修改分辨率?用什么修改图片分辨率?
  20. 鸿蒙内核为linux,现在linux改叫内核(非OS),安卓/iOS/鸿蒙才能被称为“操作系统 - 水木快照 JinghuaSoft...

热门文章

  1. 新一年级家长快查收,小学入学必备物品超强清单!
  2. 英语口语275之每日十句口语
  3. 【备忘录】西北工业大学 深澜校园网登录页面
  4. android手机使用otg usb手柄
  5. 小米官宣:手表Color 2来了,6色多彩表带,你喜欢哪个?
  6. powerquery分组_Power Query中的Table.Group函数详细分析
  7. [语义分割]SPP、空洞卷积与ASPP总结
  8. office打不开文件,显示需要修复文件,点击修复也没用的解决办法
  9. 金融机构业务连续性管理
  10. UG编程-适合新手的详细讲解