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

  最后我们决定构建一个键值存储,允许存储任何JSON数据而不需要严格的格式验证,一个非结构化的模式(命名的由来)。这是一个只扩展分片的MySQL, master节点都带有写缓冲在应对MySQL宕机,数据变更通知是一个订阅-发布的功能,我们称之为trigger。最后,Schemaless支持全局数据索引。下面我们将讨论一下数据模型概览以及一些关键特性,包括剖析Uber的一份行程数据,更深入的例子保留在接下来的文章中。

  Schemaless的数据模型

  Schemaless是一个只扩展的稀疏三维持久化哈希表,非常类似Google的 Bigtable。Schemaless中的最小数据被称作cell,不可更改;一次写入后不可被覆写或删除。Cell是一个JSON blob通过一个rowkey和一个columnname引用,还有一个referencekey叫做ref key。rowkey是一个UUID,column name是一个字符串,reference key是一个整型。

  你可以将row key看作是关系型数据库的主键,column name看作是关系型数据库的列。无论如何,在Schemaless中没有预定义或强制模式而且每行不需要共享column name;事实上,columnname完全由应用层定义。ref key用于给一个指定row key和列加版本。因此如果一个cell需要更新,你只需写一个新的cell附带一个更大的ref key (最新的cell是那个有最大的ref key的)。ref key也可以用作标记一个列表中的实体,但主要用作标记版本。具体哪种形式由应用本身决定。

  应用通常把相关的数据组织进同一列,然后每列的所有cell在应用侧的结构都大致相同。这种分组方式很好的把一起修改的数据很好的组织到了一起,这样应用程序就可以在数据库不停机的情况下迅速修改结构。下面的例子进行了更详细的叙述。

  实例:Schemaless中的行程数据存储

  在深入了解我们如何在Schemaless中对行程数据建模之前,让我们先剖析一下一个Uber的行程。行程数据在不同的时间点产生,从上车下车到付费,这许多信息伴随着用户在行程中的反馈以及后台进程处理异步到达。下图简要说明了一个Uber行程的不同阶段是何时发生的:

  这个图表展示了一个我们行程流的简化版。*标志的部分是可选的且可能发生多次。

  一个行程是由乘客发起,由司机结束,包含开始与结束的时间戳。这些信息构成了行程的基础,我们据此计算出该次行程的费用,由司机来收费。行程结束后,我们可能要调整跟收取或发放的费用。我们也可能给行程数据添加备注,从乘客或司机出发出反馈(上图中星号部分标出)。在第一张信用卡超期或禁用的情况下,我们不得不尝试用多张信用卡付款。Uber行程流是一个数据驱动的过程。随着数据变得有效或添加,特定的一组处理会在该行程上执行。这些信息中的一部分,比如乘客或司机的评级(上图中note部分),可能在行程结束后几天处理。

  好了,那我们如何把上述的行程模型映射到Schemaless?

  行程数据模型

  使用 斜体字 标注UUID,大写字母表示column name,下表展示了我们行程数据存储的简化版的数据模型。我们有两个行程(UUIDstrip_uuid1 和 trip_uuid2) 以及四列(BASE, STATUS, NOTES, and FARE ADJUSTMENT)。一个格子表示一个cell,带有一个数字以及一个JSON的 (以{…}缩写)。格子的覆盖代表不同版本 (也就是不同的ref keys)。

  trip_uuid1 有三个cell:一个在BASE列,两个在STATUS列,FARE ADJUSTMENT列没有内容。trip_uuid2的BASE列有两个格子,NOTES列有一个,同样的FARE ADJUSTMENTS列也没有内容。在Schemaless中,列没什么不同;每列的语义都由应用层定义,本例中是 Mezzanine。

  在Mezzanine中,BASE列的cell包含了行程的基础信息,比如司机的UUID和行程的时间。STATUS列包含行程现在的支付状态,每次我们尝试对行程支付的时候都会插入一个cell (由于信用卡额度不足或者逾期等问题尝试可能失败)。如果司机或者Uber的DOps(司机调度员)有行程相关的备注,会在NOTES列添加一个cell。最后的FARE ADJUSTMENT列的cell记录了行程价格的调整。

  我们如此划分列是为了避免数据冲突 而且最小化更新时需要写的数据量。BASE列在行程结束时写入,基本只会写一次。当行程开始尝试支付的时候开始尝试写STATUS列,此时BASE已经写好了,如果支付失败可能会写多次。相似的NOTES列在BASE列写过后的一些节点可能会写多次,但是与STATUS列的写操作完全独立。类似的FARE ADJUSTMENTS列只在行程费用变更时会写,例如路况不好等原因。