想象一下如果你必须在几个星期内迁移数以亿计的数据和100多个服务项目,同时还要保持UBER被几百万的乘客正常使用,这是多么艰巨的任务啊!而以下这个故事就是关于数十名工程师是如何帮助UBER在2014年迁移到Mezzanine的故事。
在2014年年初,我们面临了一个严峻的现实问题,关于我们的路径的增长(一个月约增长了20%),所以在年底之前用于存储路径的存储容量将会不够用。我们因此推出Mezzanine项目这一盛举来解决这个特别的问题。数据大迁移的日期定为万圣节(10月31日),而这恰是交通量会非常高的一天。
背景
就像大多数基于网络服务的公司那样,UBER后端系统一开始是采用“单一化”的软件架构,其中包括一群应用服务器和一个单独的数据库。该系统主要是写在Python编程语言之下,以及使用的SQLAlchemy(开源软件)作为ORM -layer(对象关系映射层面)到数据库。原来的架构在少数城市运行较少的车次路径是够用的。到2014年年初,该架构已演变成接近100个服务项目的真正以服务为导向的体系结构了。该系统的高层次的图像如下:
实时服务负责执行规划路径,后端服务负责计算乘客的付账、给司机的费用,以及侦查欺骗、做分析、和管理城市等职能。上面图中的大问题是:我们仍然依赖于单一的PostgreSQL (数据库管理系统)来存储大部分的数据。下面的饼图显示了数据是如何在数据库中分配的:
Trips(路径)数据占用比例最大,是(现在仍然是)增长最快的数据,也形成了最多的IOPS(每秒钟输入输出)。我们使用路径数据是为了为了提高服务,比如像uberPOOL,给乘客和司机提供支持,防止欺诈行为,以及开发和测试新的功能,比如在旧金山的搭乘建议。因此,我们开展了Mezzanine项目来重新构建系统,它看起来是这样的:
新的路径存储
第一个设计决定是对路径存储的数据库选择。我们简短的需求列表如下:
列表的最后一个项目是在解决一个非常直接的痛点。PostgreSQL(数据库管理系统)中的路径表增加过快,以至于任何操作比如增加一个新的列或添加新的索引会引起的死机。这使得开发新的功能变得越来越烦琐。
我们决定,用一个导向柱,无模式的方法,其中数据(JSON blobs)被路径-UUID(通用唯一识别码)、列名、以及任选的时间戳一起形成一个格状索引,它可以像一个整体的数据模型那样很好地工作。该模型通过划分多个行来横向扩展分片,并通过无模式来支持我们快速发展的文化。新的列可以添加,和新的字段也可以被添加而不需要重建模块。
我们评估了各种NoSQL(不同于传统的关系数据库的数据库管理系统的统称)的具有上述特点风格的数据库。但是由于我们的操作经验或者是产品本身的不成熟,所以我们并不认为这些数据库适合用来存储我们的路径数据。
由于博客文章的启发,比如这个启发来自FriendFeed的,我们决定建立我们自己的简单,可以分片数据存储的MySQL(开放源代码的关系数据管理系统)。我们建立的系统的主要特点是:
整个系统,我们简单地称它为无模式来表示对它的敬意,整个系统是用Python编写的。最初的版本花了约5个月从创意到生产部署,我们将描述它具体的实施细则在未来的博文中。
从SQLAlchemy(开源软件)到Schemaless(无模式)
编写一个新的可扩展的数据存储一个从无到有的创举。使用PostgreSQL数据库来重建一个实时系统的关键部分因而撬动了一个面向列的数据库是一个完全不同的游戏。显然,路径数据是UBER后端系统代码的一个组成部分,所以这个任务会触及大多数的工程团队。
在这部分的项目中的主要里程碑是:
在真正可以开始大迁移之前,第一个任务是从用户身份到用户唯一识别码的迁移,因为原代码依赖于自动递增的PostgreSQL 数据库标识符。几百条SQL查询需要被重写。这些SQL查询都是在SQLAlchemy的Python代码的形式,并且包括通过模型关系显式或间接的查询。这些都需要被重写,以便在新的无模式中连接应用程序的接口,这是一个受限制的应用程序接口,它不支持联接针对PostgreSQL中其他表格。
我们最初的目标是直接删除的路径表中的SQLAlchemy的路径模型和查询的用户。从本质上讲,我们希望得到以下结构:
路径存储的API(应用程序接口),这是一个基于无模式的实现兼容的API。路径存储就像一个开关,一个查询要么可以通过PostgreSQL或通过Schemaless(无模式)。因此,我们在PostgreSQL的数据模型之上模拟了无模式API作为代码的重新构建。
当所有写入被镜像到无模式,我们可以在无模式里重播所有查询并验证在后台的结果。因此,我们几乎立即开始评估,在Schemaless(无模式)数据与PostgreSQL中的数据是一致的。因为验证将负载到数据库(这是已经重负载),我们使用了概率方法来控制我们把对PostgreSQL数据库的额外负载。这里有一个意外收获,数据建模,回填,重构和无模式发展可以并行,以及这些可以有所不断进步和加大。
执行
Mezzanine迁移过程中我们旧金山总部的会议室。
Mezzanine项目的最终危机持续了6周。我们都聚在一个“作战室”(除了少数较远的人),把剩余SQLAlchemy的代码转换到新的路径存储库里面去,完成回填,设计和重建索引的工作,就像一个“强迫症患者”那样不断地去做改进和验证的工作。
在2014年万圣节前一天,我们已经准备把路径存储从PostgreSQL搬到Schemaless(无模式)数据库去。所有工程组队员们当天早上6点就出现在了旧金山的办公室里。如果出现了问题,所有队员可以马上进行排查以及我们有一整个工作时间来进行修复。我们保持着谨慎乐观的态度,但同时也非常紧张。出乎大家意料的是,那天没有出任何问题!对于UBER平台,它一切如常。这一起就像万圣节,可能看起来吓人,但其实只是娱乐一下!
教训总结
自从我们迁移了大数据以来,我们已经增加了一倍的路径存储了,且实现了零死机,并实施了许多性能和运营改进。在此之上,无模式数据库现在也被其它很多服务项目使用。
这篇文章是向整个Mezzanine团队致敬,感谢他们做了这样惊人的努力!