[译]Uber是如何使用MySQL设计可扩展性数据存储的?(一)

  原文:DESIGNING SCHEMALESS, UBER ENGINEERING’S SCALABLE DATASTORE USING MYSQL

  译文由杰微刊兼职译者缪晨翻译,杰微刊审校及发布

  Schemaless的形成:根据Uber工程师的习惯使用MySQL设计的数据存储,使我们可以 从2014 扩容到更高。这是Schemaless三部曲中的第一部。

  在Mezzanine项目中我们描述了我们是如何将Uber的核心行程数据从单个的Postgres节点迁移到Schemaless,这是我们开发的一个容错性很高、可用的数据存储。本文将进一步讲述它的架构、它在Uber基础结构中的角色以及他是如何成为该角色的。

  我们对新数据库的迫切需求

  2014年初,由于出行业务的迅猛增长,数据库空间即将耗尽。每次入住新的城市以及行程的里程碑都会把我们推向危险的境地,直到我们发现到年末时Uber的基础架构将无法继续发挥效用:Postgre并不能存储如此多的行程数据。我们的任务是实现Uber的下一代数据库技术,一个耗时数月甚至几乎整年的任务,大量的来自于我们世界各地研究所的工程师参与进来。

  但是首先,在商业与开源选择如此之多的当下,为什么要自己构建一个可扩展的数据库。我们对我们新的行程数据存储有5点关键的需求:

  1、 我们新的解决方案需要可以通过增加服务器线性扩容,这是原有的Postgre所缺乏的。添加服务器应该能在增加硬盘存储的同时减少系统的响应时间。

  2、我们需要写入的能力。我们之前通过Redis实现了一套简单的缓冲机制,因此如果Postgre写入失败,我们可以稍后重试,因为行程已经在中间层存入了Redis当中。但是当行程数据在Redis当中时,是不能从Postgre中读取的,然后一些功能就挂了,比如计费。很烦,不过至少我们没有丢失行程数据。

  随着时间流逝,Uber逐渐成长,我们基于Redis的解决方案不能扩容。Schemaless需要支持一种类似Redis的机制,但最好还是写完即时可读。

  3、我们需要一种机制通知下游依赖。在现有系统中,我们同时处理多个行程组件(比如计费,分析等)。这种处理方式很容易出错:如果任何一步失败了,我们就比如从头重试,即使一些组件处理已经成功了。这就不能扩容了,因此我们想把这些步骤打碎成独立的步骤,由数据变更发起。我们曾经确实有一个异步事件系统,但是它是基于 Kafka 0.7的。我们没法让它无损运行,因此我们希望新系统有一些类似的机制,但是可以无损运行。

  4、 我们需要副索引。由于我们是从Postgre迁移的,那新的存储系统需要支持Postgre的索引,会按照习惯用副索引搜索行程数据。

  5、我们需要运维够信赖的可靠系统,因为其中包含了行程数据的关键任务。如果凌晨3点我们接到叫车请求,但是这时数据存储无法响应查询,导致业务宕机,我们是否有相关操作知识可以快速解决这个问题。

  鉴于以上种种,我们分析了几种常用的选择的优势和潜在的限制,比如Cassandra、Riak、MongoDB等。出于说明的目的,我们提供了如下图表,展示了不同系统选择下的不同功能组合:

  所有的三个系统都可以通过在线增加节点线性扩容,只有一对系统可以在宕机时收到写操作。所有的解决方案中都没有内置的方式将变化通知下游依赖,因此可能需要在应用层实现该功能。它们都索引功能,但是如果你想索引多个不同的值,查询会变慢,因为他们使用分散查询并聚合结果的方式查询了所有节点。最后对于其中的一些系统有过单集群的使用经验,但不提供面向用户的在线流量,而且在我们的服务连接的时候有各种各样的运维问题。

  最终我们的确定运维信赖为主要因素,因为它包含了行程数据的关键任务。 可供选择的解决方案理论上可能都是可靠的,但是我们是否有运维的知识来立即发挥其最大功效,基于此我们决定基于Uber的使用情况开发自己的解决方案。这不仅基于我们使用的技术,而且根据成员的经验。

  需要注意的是我们对这些系统的研究持续了两年,没有发现适合行程数据存储的,但是我们已经在其它领域成功接受了Cassandra与Riak作为我们的基础服务,而且在生产环境使用这些为数百万级的用户提供服务。

  在Schemaless中我们相信

  由于以上的所有选择在规定的时间内都不能完全满足自己的需求,我们决定构建我们自己的系统使运维尽量简单,也参考了其它厂扩容的经验。这个设计的灵感来自于Friendfeed,运维的方面则参考了Pinterest。