数据模型
表模式
SDS 数据模型概念包括表、记录和属性。
在SDS中表是记录的集合,记录是属性的集合。
在SDS中表具有预定义的架构,属于强schema模型,即用户可设定表名,表的实体组键,主键,其余属性的名称和数据类型
表名(必选) 在每个用户下表名唯一
实体组键(Entity Group Key)(可选) 实体组键可以是一个或多个属性,实体组键用于支持局部二级索引与及哈希分布
- 局部二级索引组(可选,需要先设置实体组键)用以提升对某些属性的读性能。二级索引和实体组键不能是相同属性
主键(Primary Key)(必选) 主键也可以包含一个或多个属性,实体主键+主键唯一确定一条记录
其余属性(可选) 记录中每个属性都是一个名称/值对,一个属性可以只有一个值,也可以是具有多个值的集合
表示例:
city | province | pm25 | score | timestamp |
---|---|---|---|---|
Lianyungang | Jiangsu | 357 | 26.0 | 1537264064 |
对于这张示例表,可以有以下三种定义方式:
例1:city可以单独作为主键,而province、pm25、score、timestamp作为其余属性
例2:city+province作为主键,pm25、score、timestamp作为其余属性
例3:city作为主键,score作为实体组键,timestamp作为局部二级索引
属性支持如下数据类型:
数据类型 | Java SDK | PHP SDK | Python SDK | Go SDK | c++ SDK | node.js SDK | 备注 |
---|---|---|---|---|---|---|---|
BOOL | boolean | boolean | bool | bool | bool | boolean | - |
INT8 | byte | integer | int | int8 | int8_t | number | - |
INT16 | short | integer | int | int16 | int16_t | number | - |
INT32 | int | integer | int | int32 | int32_t | number | - |
INT64 | long | integer | long | int64 | int64_t | number | - |
FLOAT | float | 不支持 | float | float32 | 不支持 | number | - |
DOUBLE | double | double | float | float64 | double | number | - |
STRING | String | string | str | string | string | string | 不能包含'\0' |
BINARY | byte[] | string | string | []byte | string | string | - |
RAWBINARY | byte[] | 不支持 | 不支持 | []byte | 不支持 | 不支持 | 不能作为实体组键,主键和二级索引属性 |
集合类型 | List | array | list | slice | vector | array | 支持二级索引 |
表的数据在物理组织上支持两种索引结构:
- 主键 索引(Primary Key index) - 必选,由一到多个表属性组成
- 所有其余属性按照实体组键(若有)+主键顺序存储,写入时必须指定实体组键(若有)和主键,每条数据消耗1个单位写配额, 读取时,每条记录消耗1个单位读配额
局部二级索引 (Local Secondary Index) - 可选,使用局部二级索引必须要定义实体组键,由一个到多个表属性组成。索引分为Lazy,Eager和Immutable三种类别
- Lazy索引 - 此类型的索引不支持投影属性和唯一索引。
- Eager索引 - 此类型的索引可以支持唯一索引(Unique Index),并且可以定义一组属性作为 投影(Projection),与索引存储在一起(可视为主记录中对应属性的一份拷贝,并且属性值保持强 一致)。
Immutable索引 - 此类型的索引适合只读数据,即写入后数据不会再修改(需要用户自己来保证)。 此类型索引支持投影,但不支持唯一索引。
这几种索引会造成不同的额外配额消耗,用户需要按照实际应用场景选用合适的索引类型
开发者可以根据数据的读取模式,选择是否支持实体组键,以及是否定义二级索引。
二索引类别 | 适用场景 | 解释 |
---|---|---|
LAZY | 写多读少 | 适合写入较多,读取较少且对延迟不敏感的情况 |
EAGER | 写少读多 | 与投影配合使用,适合读取相对频繁或者对读延迟比较敏感的场合 |
IMMUTABLE | 适合只读数据 | 即写入后数据不再修改 |
目前不支持动态修改表的实体组键(包括哈希分布选项),主键,除索引类型外的其 他二级索引选项),以及属性的数据类型和编码方式,
名称 | 实体组键 | 主键 | 索引类型 | 表属性 | 数据类型 | 编码方式 |
---|---|---|---|---|---|---|
动态修改 | 不支持 | 不支持 | 仅允许由Immutable->Eager | 不支持 | 不支持 | 不支持 |
二级索引的类型可以修改,但仅允许Immutable改为Eager,适合当表中数据由不可更新改为可写的情况。 一种常见的场景是:
建表初期导入已有数据,此时数据是只读的,不会存在更新的情况(需要开发者自己保证), 此时索引定义为Immutable,可以节约读配额,数据导入完成后开始线上服务之前,将索引改为Eager模式。
哈希分布
对于实体组键,可以定义是否进行哈希分布,开启此选项后, 会添加取值范围为[0,255]的哈希值,从而实现负载均衡的效果,可用于消除请求热点,建议开启。
需要注意, 打开此选项后,表中的数据将不再保证全局有序。一般情况下,没有特殊原因,强烈建议设置实体组键并开启哈希
设计表的Schema以及估算请求量时,应保证每个实体组上的单位时间消耗的读写配额峰值尽可能的小,原则上不应不超过1000/秒,否则将不保整个表的读写请求配额。实体组的数量的多少不影响性能,所以在满足业务查功能前提下,应该尽可能降低每个实体组上的读写配额,避免读写热点,尤其避免同时大量读写一个或少数几个实体组中的记录
注意: 当实体组键开启哈希分布时,主键需要包含至少一个属性,如果schema中没有可以作为主键的属性,建议在主键中 使用一个默认的占位属性(例如,如果一个表只有一个userId作为实体组键属性,那么可以添加一个额外的recordId 属性作为主键,取值为常数0,表示某个用户下的第1条记录)。
升序与降序
对于实体组键,主键以及二级索引的属性的编码(KeySpec),可以通过asc选择决定是否是升序还是降序(例如, 整型降序编码时,其排序为..., 2, 1, 0, -1, ...与正序相反)。
正序扫描和逆序扫描
对于扫描(Scan)操作,可以通过通过设置 reverse选项进行正序和逆序扫描,但是正序扫描效率高于逆序扫描,所以定义表结构的时候,需要根据关键路径 上的查询模式来决定编码顺序,尽量保证关键路径是正序扫描。
记录行的物理组织格式
未设置实体组键的表物理组织
主记录行1 主记录行2 ... 主记录行n
设置实体组键的表物理组织
主记录行1 二级索引行1 主记录行2 二级索引行2 ... 主记录行n 二级索引行n
- 主记录(主键)行的组织形式为:
[实体组前缀] [主键属性1] ... [主键属性m]:{表属性1, ..., 表属性p}
物理存储时,会按照以上定义的顺序进行存储,即先按实体组前缀,和主键属性1到m的顺序,再根据属性定义的编码方式(asc/desc),对实体组键的属性和主键属性编码成rowkey,进行排序存储
其中实体组键前缀的组成形式为:
[实体组哈希值] [实体组键属性1] ... [实体组键属性k]
其中实体组前缀是可选的,仅当表定义了实体组键时和二级索引时,二级索引行的组织形式为:
[实体组前缀] [索引id] [二级索引属性1] ... [二级索引属性n] [主键属性1] ... [主键属性m]:
{投影属性1, ..., 投影属性q}
二级索引行在物理存储时同样按照以上定义的顺序进行存储。
投影属性
1、投影属性是主记录行属性的副本,与主数据行总是保证一致,且仅当eager索引才可以定义投影属性。 2、投影属性以空间换取时间,在仅查找二级索引的情况下可以快速读取既定属性的值
一致性
SDS存储是强一致的模型,即后续发生的读总能读到以前写入的数据。数据存储三备份,并且会异步的同步到备集群,备集群目前只提供只读功能,用于离线分析。
事务性
行级别的事务保证
对于同一次put(非batch)的记录数 据,能够保证原子性,例如,两个并发的put分别写入同一行的两个属性p和q: (p1, q1)和(p2, q2), 最终结果不会出现(p1, q2)或者(p2, q1)的情况。
实体组内的事务保证
属于同一事务组内的记录行,可以支持batch的原子性,可以在建表的时候进行配置是否开启,如果需要定义二级索引,则必须开启batch原子性。同一事务组内可以支持局部二级索引,并且索引跟主记录之间是强一致的。
自增操作支持
目前支持在整型数据类型上的自增操作
条件修改
SDS支持条件修改(put和delete),这样可以在应用层实现自己的同步逻辑(比如锁)。