InfoQ Uber为什么放弃Postgres选择迁移到MySQL?

作者|EvanKlitzke
译者|无明
策划|小智
Uber的早期架构包含了一个用Python开发的单体后端应用程序 , 这个应用程序使用Postgres作为数据存储 。 从那个时候开始 , Uber的架构已经发生了巨大变化 , 变成了微服务 , 并采用新的数据平台模型 。 具体地说 , 之前使用Postgres的地方 , 现在改用Schemaless , 一种构建在MySQL之上的新型数据库分片层 。 在本文中 , 我们将探讨Postgres的一些缺点 , 并解释为什么我们要在MySQL之上构建Schemaless和其他后端服务 。
1
Postgres架构
我们遭遇了Postgres的诸多限制:
低效的写入操作
低效的数据复制
数据损坏问题
糟糕的副本MVCC支持
难以升级到新版本
我们将通过分析Postgres的表和索引在磁盘上的表示方式来探究以上这些限制 , 并将其与MySQL的InnoDB存储引擎进行比较 。 请注意 , 我们的分析主要是基于我们对较旧的Postgres9.2版本系列的经验 。 据我们所知 , 在本文中讨论的内部架构在较新的Postgres发行版中并未发生显著变化 , 并且至少自Postgres8.3发行版(现在已近10岁)以来 , 9.2版本的基本设计都没有发生显著变化 。
磁盘表示
一个关系型数据库必须能够执行一些关键任务:
提供插入、更新和删除能力
提供修改模式的能力
支持MVCC , 让不同的数据库连接具有各自的事务视图
这些功能如何协同工作是设计数据库磁盘数据表示的重要部分 。
Postgres的一个核心设计是不可变数据行 。 这些不可变数据行在Postgres中被称为“元组” 。 这些元组通过ctid来唯一标识 。 从概念上看 , ctid表示元组在磁盘上的位置(即物理磁盘偏移) 。 可能会有多个ctid描述单个行(例如 , 为了支持MVCC , 可能存在一个数据行的多个版本 , 或者一个数据行的旧版本还没有被autovacuum进程回收掉) 。 元组集合构成一张表 。 表本身是有索引的 , 这些索引被组织成某种数据结构(通常是B树) , 将索引字段映射到ctid 。
通常 , 这些ctid对用户是透明的 , 但了解它们的工作原理有助于了解Postgres表的磁盘结构 。 要查看当前行的ctid , 可以在语句中将“ctid”添加到列列表中:
我们通过一个简单的用户表来解释这个 。 对于每个用户 , 我们都有一个自动递增的用户ID主键、用户的名字和姓氏以及用户的出生年份 。 我们还针对用户全名(名字和姓氏)定义了复合二级索引 , 并针对用户的出生年份定义了另一个二级索引 。 创建表的DDL可能是这样的:
这里定义了三个索引:一个主键索引和两个二级索引 。
我们往表中插入以下这些数据 , 包括一些有影响力的历史数学家:
InfoQ Uber为什么放弃Postgres选择迁移到MySQL?
文章图片
如前所述 , 这里的每一行都有一个隐式、唯一的ctid 。 因此 , 我们可以这样考虑表的内部表示形式:
InfoQ Uber为什么放弃Postgres选择迁移到MySQL?
文章图片
主键索引(将id映射到ctid)的定义如下:
InfoQ Uber为什么放弃Postgres选择迁移到MySQL?
文章图片
B树索引是在id字段上定义的 , 并且B树中的每个节点都存有ctid的值 。 请注意 , 在这种情况下 , 由于使用了自动递增的ID , B树中字段的顺序恰好与表中的顺序相同 , 但并不是一直都这样 。
二级索引看起来差不多 , 主要区别在于字段的存储顺序不同 , 因为B树必须按字典顺序来组织 。 (first,last)索引从名字的字母表顺序开始:
InfoQ Uber为什么放弃Postgres选择迁移到MySQL?
文章图片
类似的 , birth_year索引按照升序排列 , 如下所示:
InfoQ Uber为什么放弃Postgres选择迁移到MySQL?
文章图片


推荐阅读