本文所有内容均来自于阿里云官网

简介

TableStore是阿里云自研的多模型结构化数据存储,提供海量结构化数据存储和快速查询和分析服务,其分布式存储和索引引擎能够支持PB级存储,千万TPS以及毫秒级延迟的服务能力。

存储引擎与索引引擎

在OTS的服务端有两个引擎,存储引擎和索引引擎,他们的数据结构和底层原理都是不同的,即表引擎(Table)和多元索引引擎(Searchindex)

全托管

表格存储是一种全托管的结构化数据存储。使用表格存储您只需专注于业务研发,无需担心软硬件预置、配置、故障、集群扩展、安全等问题,在保证高服务可用性的同时,极大地减少了管理及运维成本。

多模型

  • Wide column模型:一款经典模型,目前绝大部分半结构化、结构化数据都存储在Wide column模型系统中。
  • Timeline模型:表格存储自研模型,主要用于消息数据,适用于IM、Feed和物联网设备消息下推等消息系统中消息的存储和同步,目前已被广泛使用。(syncserver的推送位点)
  • Timestream模型:适用于时序数据、时空数据等核心数据场景。
  • Grid模型:适用于科学大数据的存储和查询场景。

无缝扩展

数据分片&负载均衡实现无缝扩展,通过调整数据分区配置更多存储,单表不少于1PB或一万亿条记录

查询能力强

除了支持主键查询,表格存储还支持二级索引、多元索引。

  • 二级索引:相当于给数据表提供了另外一种排序方式,即对查询条件预 先设计了一种数据分布,可加快数据查询的效率。
  • 多元索引:基于倒排索引和列式存储,支持多字段自由组合查询、模糊查询、地理位置查询、全文检索等,可解决大数据的复杂查询难题。
  • SQL查询:兼容MySQL的查询语法

数据强一致(三副本)

高并发(千万级)

Wide Column模型术语

主键与分区键

主键(Primary Key):表中的每一行由主键(PK)唯一确定,主键可包含1~4个主键列,建表时必须指定主键列,且后面无法再更改

分区键(Partition Key):数据分区的划分粒度为主键的第一列,该列即为数据分区键。拥有相同数据分区键的行必然在同一个数据分区中。OTS会根据分区键列值的范围来进行分区的操作,通过分区来达到数据访问负载均衡的目的。

分区:

  • 当表的大小逐渐增大后,表会分裂,由原来的一个分区自动分裂成多个分区。
  • 触发分裂的因素会有很多,其中一个很关键的因素就是数据量。
  • 分裂后,每个分区会负责某个独立的分片键范围,每个分区管理的分片键范围都是无重合的,且范围是连续的。
  • 后端会根据写入数据行的分片键的范围,来定位到是哪个分片。

如何设定一个好的分区键?

建表时,分区键的选择是很重要的,会影响当表数据量很大时访问的性能。应用程序在选择分区键时,应该遵循以下基本原则:

  • 不要使用拥有固定值或取值范围较小的属性,如客户性别(Male/Female)。
  • 尽量避免使用按自然序排序后会有明显访问热点的属性,如在查询最新数据场景中使用时间戳(TimeStamp)作为分区键。
  • 尽量使用按自然序排序后访问热点比较分散的属性,如UserID。

如果无法预估访问热点,该怎么做?

建议在写入分区键之前,根据应用程序的特点进行一次哈希(Hash)。如在写入一行数据时,将UserID通过简单的哈希算法生成一个哈希值,然后在哈希值后拼接UserID作为分区键的值存入表格存储的表。通过这种轻量级的操作可以有效地解决部分访问热点问题。但是需要特别注意的是,由于分区键的值是由哈希值和实际值拼接的,应用程序将无法使用分区键进行范围读取的操作(getRange)。

稀疏的属性列

OTS的表是稀疏的,每一行可以有不同的列,可以动态增加或者减少属性列,创建表时无需为表的属性列定义严格的SCHEMA。

多版本、生命周期、有效版本偏差

多版本(multi-version):每条记录的不同列可以有不同版本,使用timestamp(ms)作为版本号(version),timestamp可以是写入服务器的时间,也可以由用户自己指定

使用timestamp作为version,两全其美:

  1. 是递增的
  2. 表明更新时间,

最大版本数(max-version):每个属性列最多保存的版本个数,符合FIFO

生命周期(TTL):某个属性的version,经过TTL时间后,由系统后台自动销毁

两个特殊场景,进一步理解生命周期:

  1. 写入TTL过期的version时,经过计算,OTS会直接拒绝写入请求
  2. 将表的TTL设小,再恢复原来的TTL值,最久远的若干条记录有可能就被系统回收了

宽行模型与关系模型的区别

  • Wide column模型:三维结构(行、列和时间)、schema-free、宽行、多版本数据以及生命周期管理。
  • 关系模型:二维(行、列)以及固定的Schema。

Wide Column存储引擎

OTS的存储可以用一个巨大的SortedMap来表示:

1
SortedMap<PrimaryKey, List<Column>>

查询操作

从本质上来说,OTS只提供两种查询:

  • 单行查询:GetRow
  • 范围查询:GetRange

主键的比较

按照主键列的定义顺序,依次比较,相同则比较下一列,所有主键列都相同才代表主键相等

类型 比较规则
整型(Integer) 有符号长整型比较
布尔型(Boolean) 布尔型比较
字符串型(String) 字典序比较
字节型(Binary) 字典序比较

举个简单的例子,假设一个表有3列主键列,分别是:整型、字符串型和整型:

  • (10, ‘abc’, 10) == (10, ‘abc’, 10) 所有主键列均相等
  • (10, ‘abc’, 10) < (11, ‘abc’, 10) 第一列主键列比较出大小
  • (10, ‘bbc’, 0) > (10, ‘abc’, 10) 第一列主键列相等,第二列主键列比较出大小,即使第三列主键列也不同。

单行查询

单行查询必须指定行的主键,根据上一章描述的比较规则,在表格存储内部查找到相同主键的行,并根据指定的查询条件,返回整行或者部分列。

范围查询

范围查询必须指定两个主键,一个作为范围的起始(包含),一个作为范围的终止(不包含)。在表格存储内部,会根据上面章节提到的主键的比较规则,返回大于等于起始主键且小于终止主键的所有的行。

误区:范围查询等于条件查询

1
2
3
4
5
6
7
8
9
10
11
12
举例:
假设表有三个主键: [PK1(INTEGER), PK2(STRING), PK3(INTEGER)]

给定的查询范围为:
起始主键:[PK1 = 10, PK2 = 'h', PK3 = 5]
终止主键:[PK1 = 15, PK2 = 'z', PK3 = 9]

很多用户会将这个查询条件误解为:
10 <= PK1 < 15 and 'h' <= PK2 < 'z' and 5 <= PK3 < 9

而正确的理解应该是:
起始主键 <= 行主键 < 终止主键

如果按照条件查询,下表所有行都不符合范围,但是实际上,2、3、4、5行是符合范围的

行号 PK1 PK2 PK3
1 10 ‘a’ 0
起始主键 10 ‘h’ 5
2 11 ‘a’ 0
3 11 ‘b’ 0
4 12 ‘a’ 0
5 12 ‘c’ 0
终止主键 15 ‘z’ 9
6 15 ‘z’ 10
7 16 ‘a’ 0
8 16 ‘a’ 1

全局二级索引(GlobalIndex)

术语

  • 索引表:对主表某些列数据的索引,只能读不能写。
  • 预定义列:表格存储为Schema-free模型,原则上一行数据可以写入任意列,无需在schema中指定。但是也可以在建表时预先定义一些列,以及其类型。
  • 单列索引:只为某一个列建立索引。
  • 组合索引:多个列组合排序,组合索引中包含组合索引列1,列2。
  • 索引表属性列:被映射到索引表非PK列中的主表预定义列。
  • 索引列补齐:自动将没有出现在索列中的主表PK列补充到索引表PK中。

使用

  • GlobalIndex使用的是额外的一张TableStore表来实现的,所以索引表的数据模型与TableStore的表完全一致。用户可以指定任意列(原表的主键列或属性列)作为索引表的主键。
  • 举例:
    假设原表有以下几列:
    • 一列主键X
    • 三列属性列Q、W、E
      我们创建GlobalIndex的主键为Q、X(索引列补齐:原表的主键列会加在属性列后面,为了防止重复),通过索引表可实现如下查询组合:
    • Q范围查询,X范围查询
    • 指定Q的值,X范围查询
    • 指定Q和X的值

理解

  • 为何叫二级索引?当用户创建一张表时,其所有PK列构成了该表的“一级索引”
  • 全局二级索引支持在指定列上建立索引,生成的索引表中数据按用户指定的索引列进行排序,主表的每一笔写入都将自动异步更新到索引表(延迟一般是毫秒级别)。
  • 在许多场景下,将极大的提高查询的效率。

多元索引(SearchIndex)

GlobalIndex虽然查询能力上有所增强,但是在某些查询功能上还是无法满足需求,比如分词查询、多字段自由组合查询、模糊查询、地理位置查询等。为了支持更多的查询能力,OTS增加了多元索引能力

  • 极强的索引能力:需要支持多字段组合查询,模糊查询,时空等多维查询等,这些需求只能通过倒排索引和其他类似索引解决。
  • 轻量级分析能力:需要支持排序、统计、聚合等轻量级分析能力,这些能力在众多场景下都有大量的需求,目前很多产品的这部分能力诉求都没能得到很好地满足。

索引能力

  1. 倒排索引:是搜索系统中多种查询能力的基础结构,可以极大优化查询功能。基于此,TableStore提供了倒排索引能力,用户为某些属性列建立了倒排索引后,可以基于这些倒排索引实现多字段自由组合的ad-hoc查询,同时也不用担心性别,年龄,枚举等选择性较差的字段的问题了。
  2. 多维空间索引:是一种用于地理位置等多维空间查询的数据结构,一般都用于时空数据场景,可以极大提高空间查询的性能。TableStore也提供了多维空间索引,目前基于多维空间索引提供了地理位置的查询能力,包括“附近的人”、“矩形、多边形等范围内的点”等常见的地理查询,为大数据筛选、车联网和移动应用提供更丰富的一站式数据查询能力。

理解

  • 写入延迟:与GlobalIndex类似,数据同步到SearchIndex也是异步的。由于SearchIndex内部实现的原因,数据写入到SearchIndex有一个索引构建的过程。所以除了同步链路的延迟,还需要加上索引构建的延迟,整个延迟在秒级别。
  • 模糊查询:模糊查询时关系型数据库的一个强大功能,基于like语法可以实现很多易用性极高的功能,但是在分布式数据库中的时候,比如HBase,这个能力没法提供。现在TableStore提供了模糊查询能力,只要为该属性列创建倒排索引,该字段就可以被模糊查询。
  • 前缀查询:有了模糊查询能力后,TableStore也提供了前缀查询功能。

全局二级索引与多元索引的对比

GlobalIndex(全局二级索引) SearchIndex(多元索引)
查询灵活性 只可以使用创建索引时的给出的索引组合进行查询,如果需要其他组合则需要再创建新的索引表 可以对索引字段做任意组合查询
大范围扫描 支持,性能与原生TableStore一致 支持,但性能不及全局二级索引
数据可见延迟 毫秒级 秒级
分词查询 不支持 支持
GEO地理位置查询 不支持 支持
数据一致性 最终一致 最终一致

OTS和HBase的异同

OTS与HBase一样,都从谷歌的BigTable汲取了灵感,而HBase是目前开源届比较知名的实现,注意这里比较的是OTS的WideColumn模型,其他模型如Timeline与Hbase是不一样的,不用考虑异同。

BigTable和Hbase是什么?

  • Bigtable 是一个分布式, 多维, 映射表. 表中的数据通过一个行关键字(Row Key)、一个列关键字(Column Key)以及一个时间戳(Time Stamp)进行索引. 在Bigtable中一共有三级索引. 行关键字为第一级索引,列关键字为第二级索引,时间戳为第三级索引。

    Bigtable的存储逻辑可以表示为:

      
    1
    (row:string, column:string, time:int64)→string
  • HBase 是一个开源的、分布式的、版本化的 NoSQL 数据库(也即非关系型数据库),它利用 Hadoop 分布式文件系统(Hadoop Distributed File System,HDFS)提供分布式数据存储。主要适用于海量明细数据(十亿、百亿)的随机实时查询。HBase表中的每个列都归属于某个列族,列族必须作为表模式(schema)定义的一部分预先给出,列名以列族作为前缀,每个“列族”都可以有多个列成员(column);如course:math, course:english, 新的列族成员(列)可以随后按需、动态加入;

关于主键的异同

  • HBase只支持一个值,也就是HBase的RowKey,通常对应比如业务唯一值(如商品ID),如果需要使用多个列作为联合主键的时候,需要手动拼接多个列,将拼接后的字符串作为一个RowKey。
  • OTS支持最多4个列作为联合主键,但是第一个列会作为OTS划分数据存储的分区键,同一个分区下可以使用OTS提供的一些特性,比如分区内事务。多个列作为主键时,在底层会按照主键有序存储,因此支持按照主键(列)的范围查询。
  • 小结:OTS的多列主键不仅避免了业务层去做主键的拆与合,还能提供比较灵活的查询场景的支持。但是这种查询也是有局限性的,由于OTS的联合主键底层采用的是类似于SortedMap的存储结构,因此只能支持精确的单行查询,以及基于主键的顺序和逆序扫描,既然OTS支持了主键的这些查询,这就意味着我们在设计主键的时候,需要花更多的精力去琢磨主键的设计。

关于数据类型的异同

  • HBase的主键(RowKey)的数据类型为字符串(String),所有列的底层类型都是BinaryBytes。
  • OTS支持多种基本数据类型,主键支持String,Integer,Binary,属性列支持String,Integer,Double,Boolean,Binary。
  • 小结:从存储的高效性上来看肯定是统一的BinaryByte更直接更高效,但是支持多样的数据类型让OTS的存储数据可以直观可视化,也为OTS通过属性列来建立多元索引提供了前提。

关于数据版本和生命周期

  • HBase支持系统自生成时间戳作为版本号来标识数据版本,也支持自定义时间戳来作为版本号。同时支持在列族(ColumnFamily)粒度和单元格(Cell)粒度设置TTL(Time To Live),过期后自动清理。
  • OTS对数据版本的支持和HBase并无二异(同样也有多版本、生命周期等概念),OTS支持在表粒度上设置TTL,过期后所有的属性列都会过期,这是和HBase不太相同的一点,因为OTS没有列族的概念,而HBase一个Row可以配置多个列族。因此HBase可以对不同的列族设置不同的TTL生命周期。
  • 小结:在这一点上,二者基本没太大差别,生命周期很好理解,数据版本在很多场景下可以做幂等性校验,同时因为数据版本永远是后插入的值一定要大于等于之前已插入的值。因此也可以用来保证数据的一致性。

其他比较

  • OTS是使用HTTP协议的,底层的分布式文件系统使用的是盘古。为了尽可能在用户使用保证傻瓜化,OTS对于很多运维相关的功能都不支持,比如Region管理,Table管理等。
  • HBase使用的是TCP协议,底层的分布式文件系统使用的是HDFS。

实战

OTS提供了两种方式来写入数据,一是同步批量写入,返回值中即可直接获取写入状态,如果一次写入200行,但是有1条数据写入失败,你可以直接在返回值中获取并进行后续处理.二是异步写入+CallBack的方式,后者适合数量量很大的场景,

读接口

  • 主键精确读:GetRow
  • 主键批量读:BatchGetRow
  • 主键范围读:GetRange
  • 索引查询:search

假设主键列为A,B,属性列为C,D,E,F 全局二级索引列为C,A,B 多元索引列为D,E,F

基于主键

  • 主键点查(精确查询):通过已知主键,精确读取一行,效率最高,SQL类比where A=a and B =1
    • where A = a and B= b
  • 主键范围查:从开始主键到结束主键,支持正序和逆序(这种查询需要满足最左前缀原则)
    ○ where A = a
    ○ where A between a and c
    ○ where A = a and B > 1
    ○ 查询范围在A=a and B=1(最小值)和 A=D and B=5(最大值)之间的数据

基于全局二级索引

全局二级索引结构等同于主表结构,区别在于只包含索引列,通过全局二级索引定位到主键,在通过主键从主键表中定位到具体的数据行.

全局二级索引的意义就在于希望通过主键外的某个列来查询数据.二级索引列需要包含主键列,一般是普通列A+主键列

  • 主键点查
    • where C = c and A =a and B=b
  • 主键范围查
    • where C=c
    • where C=c and A=a
    • where C=c and A > a
    • where C=c and A>a and B < b
    • where C>c
    • …..

基于多元索引

多元索引使用倒排索引,BKD树等结构,具备丰富的查询能力,支持按任意多个多元索引列做组合查询,聚合统计,排序分页等,在使用上,理论上来说,只需要建立一个多元索引,将所有可能查询的列加入到这个多元索引中即可,加入的顺序也没有要求,但要注意,索引列最多只能有20个

  • where D=d order by E DESC limit 1,10
  • where D= d order by C ASC
  • select sum(d) from 表名 where E>e
  • ……

附录

存储量对查询速度有影响吗?

对于单行查询和范围查询,查询的速度不在于数据量有多少。

表格存储作为NoSQL数据库,其数据量可以随集群的规模线性扩展,并且对单行和范围查询的速度不会有任何影响。即使数据规模达到亿级或者百亿级,查询速度都不会变。

参考资料

表格存储数据模型和查询操作:https://developer.aliyun.com/article/38621

深入对比 HBase 与阿里云的表格存储服务:https://developer.aliyun.com/article/69547?spm=ata.21736010.0.0.41546874SbHkAA

TableStore索引功能详解:https://developer.aliyun.com/article/692837?spm=ata.21736010.0.0.41546874SbHk

本文落笔于 2021-08-05