OceanBase——海量结构化数据的分布式存储解决方案
OceanBase是为满足海量结构化数据存储需求而设计的。她具有良好的可扩展性,同时提供结构化数据的支持,较好地支持了业务相对复杂的系统对海量数据存储的需求。
1 介绍
随着互联网的进一步普及,互联网应用的用户进一步增长,对现有的很多架构提出了挑战。这在存储系统方面尤为突出。
首先,互联网应用需要存储的数据直接由用户生成,而不再是由应用提供者提供。随着用户量的增长,用户生成的数据量也随之增长,对系统能支撑的数据量提出了更高的要求,进而对底层的存储系统的可扩展性要求也越来越高。
随着移动互联网用户的增多,用户在线时间大大增长,这对服务的可用性提出了更高的要求,任何时刻服务不可用影响的用户数可能都很大。
用户对服务的用户体验要求也越来越高,用户体验的一个重要因素便是响应时间,底层存储系统的响应时间非常关键。
很多应用开始阶段为了开发效率,往往不会太多的考虑系统的可扩展性,尤其是底层的存储系统,比如数据存储大多使用类似MySQL的关系型数据库。这在开始阶段工作的很好,随着用户数的增长,扩展性的问题越来越突出。由于使用传统的关系型数据库,现有的数据模型通常较为复杂,使得其向很多NoSQL产品(比如key/value系统)迁移比较困难。
OceanBase在设计的时候便考虑了以上的问题,她兼顾了NoSQL存储系统的可扩展性和传统关系型数据库在数据结构表达上的便利性,为解决以上问题提供了一种新的思路。
本文介绍了OceanBase的设计与实现,并简单介绍了其在淘宝收藏夹应用中的使用。第二部分介绍OceanBase的数据模型。第三部分介绍客户端的接口。第四部分介绍了其具体的实现。第五部分展示OceanBase的性能数据。最后一部分我们介绍OceanBase在收藏夹中的应用。
2 数据模型
OceanBase支持应用的概念(这类似与数据库中的schema),一个应用可以创建多张table,table中包含一系列的列。table之间支持基于列的关联(join)关系。应用在使用前需要先创建数据模型,并支持在运行过程中动态修改数据模型。
2.1 Rowkey
每张表都需要指定一个rowkey,rowkey的最大长度可以在创建时指定,其内容为二进制字符串(Binary String)。Rowkey在一张表内需要确保唯一(这和关系型数据库中的主键类似),OceanBase在内部存储时,数据按照rowkey排序。一张表的数据会根据rowkey动态的切分,切分后的单位为tablet,tablet由startKey和endKey指定其负责的数据的范围。
OceanBase的rowkey还支持split属性。该属性指定了rowkey内容的一个前缀,当数据在被动态切分时,系统会确保split后前缀内容相同的rowkey所对应的数据不会被切分至多个tablet中。
比如在淘宝的收藏夹应用中,用户可以收藏某个店铺,也可以收藏某件商品。用户的一条收藏记录可以由{userId,  object type , object id}唯一确定,所以将其作为rowkey,分别表示收藏者的用户Id,被收藏对象的类型(店铺或者商品)和被收藏对象的Id,其中userId为一个8字节的整型。我们为了确保同一个用户的收藏在动态切分时分布在同一个tablet中,则可以指定rowkey在8字节的位置split。
2.2 Column
一张表可以创建多个列,OceanBase中列支持的数据类型包括:
类型
说明
Int
整数,范围为[-2^63, 2^63]
Varchar
字节流,可以指定其最大长度,比如varchar(1024)
Datetime
表示自1970-1-1 00:00:00到现在的秒数
Precise_datetime
表示自1970-1-1 00:00:00到现在的微秒数
Create_time
和Precise_datetime类似,该列的值由数据新增时系统自动生成,不支持修改。
Modify_time
和Precise_datetime类似,该列的值由数据更新时系统自动生成,不支持修改。
2.3 关联
为了简化对有关联的数据的查询操作,OceanBase支持在创建表时指定表之间的关联关系。当客户端查询时,服务器端根据表之间的关联关系定义,自动将相应的数据合并,然后将合并后的数据结果返回给客户端。
比如下面的关联关系定义:
Join=rowkey[8,16]%collect_item_info:item_name$item_name,item_price$new_price
该关联关系定义了当前表和collect_item_info表之间的关联关系,关联关系由该表rowkey的8-16字节与collect_item_info的rowkey指定。当查询该表时,将使用collect_item_info中的item_name和new_price分别和当前表的item_name和item_price合并,合并后的结果返回给用户。合并操作不修改OceanBase中存储的数据,只影响返回给用户的结果。
3 API
OceanBase的API提供了查询单条数据,查询范围,新增,修改,删除数据的功能。
3.1 查询
客户端可以获取rowkey指定的单条数据,也可以获取由startKey和endKey指定范围的数据集合。获取数据时可以指定需要获取的列。如果是获取数据集合,还可以指定这些数据的排序规则,数据的起始位置(类似MySQL中offset)和单次查询返回的数据量(类似MySQL中的limit),排序的字段需要包含在指定获取的字段列表中。
下面的代码便是使用Java客户端获取一个范围数据的例子:
QueryInfo qinfo = new QueryInfo();
qinfo.setStartKey(startKey);
qinfo.setEndKey(endKey);
qinfo.addColumn("title").addColumn("price");
qinfo.addOrderBy("price", true).addOrderBy("title", false);
results = client.query(table, qinfo);
for (RowData row : Result())
{
    System.out.("title") + ", ");
    System.out.("price"));
}
3.2 更新
OceanBase的更新接口支持新增,修改和删除操作。一次可以提交对多张表的多个rowkey操作,这些操作都是在同一个事务中,即要么全部失败,要么全部成功。
ObMutator mutator;
// 在table1中更新rowkey1对应的column1和column2
mutator.addCell(new ObCell(table1, rowkey1, column1, value1), OB_UPDATE);
mutator.addCell(new ObCell(table1, rowkey1, column2, value2), OB_UPDATE);
// 在table1中更新rowkey2对应的column1
mutator.addCell(new ObCell(table1, rowkey2, column1, value1), OB_UPDATE);
// 在table2中新增rowkey3, 包含column1和column2两列
mutator.addCell(new ObCell(table2, rowkey3, column1, value1), OB_INSERT);
mutator.addCell(new ObCell(table2, rowkey3, column2, value2), OB_INSERT);
// 删除table3中的rowkey1对应的整行数据
mutator.addCell(new ObCell(table3, rowkey1), OB_DEL_ROW);
// 执行以上操作
client.apply(mutator);
OceanBase的更新操作和传统关系型数据库的语义稍有不同。如果在新增时,对应的数据已经存在,系统不会返回失败,而是使用新的内容更新老的内容。同理,如果更新的时候rowkey指定的数据不存在,则update的语义类似insert。
4 实现
OceanBase系统主要包括5个组件:维护系统元数据的rootserver,服务更新操作的updateserver,存储静态数据的chunkserver,服务查询请求的mergeserver和为应用提供服务接口的客户端。
4.1 整体架构
OceanBase将表的数据动态切分为tablet,tablet的数据分为动态和静态两部分。静态的数据存放在chunkserver上,所有对数据的修改都存储在updateserver中。updateserver的修改定期同步到chunkserver,chunkserver将updateserver的更新和本地的静态数据合并,生成合并后的新数据。
tablet的信息由rootserver维护,客户端在初始化时会请求rootserver,获取updateserver的地
址信息。客户端的更新请求(包括新增,修改和删除)都直接访问updateserver。查询请求时客户端根据相应的rowkey向rootserver查询其对应的tablet信息,rootserver返回相应的mergeserver地址,客户端根据返回的信息请求相应的mergeserver获取数据。
Mergeserver收到请求时,根据rowkey从rootserver获取相应的tablet信息,该信息中包括负责该tablet的chunkserver列表,mergeserver请求相应的chunkserver,获取静态数据(如果有的话),然后根据返回的数据,请求updateserver获取相应的更新数据,将更新数据和静态的数据合并,将合并后的结果返回给客户端。OceanBase的整体架构如图1。
图表 1 OceanBase整体架构
4.2 tablet怎样创建tablet
tablet主要包括元信息和地址信息,都由rootserver维护。
元信息主要包括该tablet负责的数据的范围(由startKey和endKey指定),tablet的数据条数、大小以及tablet的checksum等。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。