StarRocks入门学习<一>

其他更多java基础文章:
java基础学习(目录)


本文为尚硅谷StarRocks视频的整理总结,另外发现一个讲StarRocks的系列博客

1. StarRocks介绍

  • StarRocks是新一代极速全场景MPP数据库。
  • StarRocks致力于构建极速统一分析体验,满足企业用户的多种数据分析场景,支持多种数据模型(明细模型、聚合模型、更新模型),多种导入方式(批量和实时),可整合和接入多种现有系统(Spark、Flink、Hive、ElasticSearch)。
  • StarRocks兼容MySQL协议,可使用MySQL客户端和常用BI工具对接StarRocks来进行数据分析。

image.png

2. StarRocks适合什么场景

StarRocks可以满足企业级用户的多种分析需求,包括OLAP多维分析、定制报表、实时数据分析和Ad-hoc数据分析等。具体的业务场景包括:

  1. OLAP多维分析:用户行为分析、用户画像、财务报表、系统监控分析
  2. 实时数据分析:电商数据分析、直播质量分析、物流运单分析、广告投放分析
  3. 高并发查询:广告主表分析、Dashbroad多页面分析
  4. 统一分析:通过使用一套系统解决上述场景,降低系统复杂度和多技术栈开发成本

3. StarRocks基本概念

  • FE:FrontEnd简称FE,是StarRocks的前端节点,负责管理元数据,管理客户端连接,进行查询规划,查询调度等工作。
  • BE:BackEnd简称BE,是StarRocks的后端节点,负责数据存储,计算执行,以及compaction,副本管理等工作
  • Broker:StarRocks中和外部HDFS/对象存储等外部数据对接的中转服务,辅助提供导入导出功能。
  • StarRocksManager:StarRocks的管理工具,提供StarRocks集群管理、在线查询、故障查询、监控报警的可视化工具。
  • Tablet:StarRocks中表的逻辑分片,也是StarRocks中副本管理的基本单位,每个表根据分区和分桶机制被划分成多个Tablet存储在不同BE节点上。

image.png

FE

  • FE接收MySQL客户端的连接, 解析并执行SQL语句。
  • 管理元数据, 执行SQL DDL命令, 用Catalog记录库, 表, 分区, tablet副本等信息。
  • FE高可用部署, 使用复制协议选主和主从同步元数据, 所有的元数据修改操作, 由FE leader节点完成, FE follower节点可执行读操作。元数据的读写满足顺序一致性。FE的节点数目采用2n+1, 可容忍n个节点故障。当FE leader故障时, 从现有的follower节点重新选主, 完成故障切换。
  • FE的SQL layer对用户提交的SQL进行解析, 分析, 改写, 语义分析和关系代数优化, 生产逻辑执行计划。
  • FE的Planner负责把逻辑计划转化为可分布式执行的物理计划, 分发给一组BE。
  • FE监督BE, 管理BE的上下线, 根据BE的存活和健康状态, 维持tablet副本的数量。
  • FE协调数据导入, 保证数据导入的一致性。

BE

  • BE管理tablet副本, tablet是table经过分区分桶形成的子表, 采用列式存储。
  • BE受FE指导, 创建或删除子表。
  • BE接收FE分发的物理执行计划并指定BE coordinator节点, 在BE coordinator的调度下, 与其他BE worker共同协作完成执行。
  • BE读本地的列存储引擎获取数据,并通过索引和谓词下沉快速过滤数据。
  • BE后台执行compact任务, 减少查询时的读放大。
  • 数据导入时, 由FE指定BE coordinator, 将数据以fanout的形式写入到tablet多副本所在的BE上。

4. 表设计原理

4.1 列式存储

image.png StarRocks的表和关系型数据相同, 由行和列构成. 每行数据对应用户一条记录, 每列数据有相同数据类型. 所有数据行的列数相同, 可以动态增删列.  StarRocks中, 一张表的列可以分为维度列(也成为key列)和指标列(value列), 维度列用于分组和排序, 指标列可通过聚合函数SUM, COUNT, MIN, MAX, REPLACE, HLL_UNION, BITMAP_UNION等累加起来. 因此, StarRocks的表也可以认为是多维的key到多维指标的映射。

查询时, 如果指定了维度列的等值条件或者范围条件, 并且这些条件中维度列可构成表维度列的前缀, 则可以利用数据的有序性, 使用range-scan快速锁定目标行。例如:

  • 对于表table1: (event_day, siteid, citycode, username)➜(pv);
    • 当查询条件为event_day > 2020-09-18 and siteid = 2, 则可以使用范围查找;
    • 如果指定条件为citycode = 4 and username in ["Andy", "Boby", "Christian", "StarRocks"], 则无法使用范围查找

4.2 稀疏索引

当进行范围查询时,StarRocks如何快速定位到起始目标行呢?答案是使用shortkey index。 shortkey index为稀疏索引。

image.png

表中组织由三个部分组成:

  1. shortkey index表:  表中数据每1024行, 构成一个逻辑block. 每个逻辑block在shortkey index表中存储一项索引, 内容为表的维度列的前缀, 并且不超过36字节.  shortkey index为稀疏索引, 用数据行的维度列的前缀查找索引表, 可以确定该行数据所在逻辑块的起始行号.
  2. Per-column data block: 表中每一列数据按64KB分块存储,  数据块作为一个单位单独编码压缩, 也作为IO单位, 整体写回设备或者读出.
  3. Per-column cardinal index:  表中的每列数据有各自的行号索引表,  列的数据块和行号索引项一一对应, 索引项由数据块的起始行号和数据块的位置和长度信息构成, 用数据行的行号查找行号索引表, 可以获取包含该行号的数据块所在位置, 读取目标数据块后, 可以进一步查找数据.

由此可见, 查找维度列的前缀的查找过程为:  

  1. 先查找shortkey index, 获得逻辑块的起始行号,
  2. 查找维度列的行号索引, 获得目标列的数据块,
  3. 读取数据块, 然后解压解码, 从数据块中找到维度列前缀对应的数据项.

4.3 加速数据处理

  1. 预先聚合:  StarRocks支持聚合模型, 维度列取值相同数据行可合并一行, 合并后数据行的维度列取值不变, 指标列的取值为这些数据行的聚合结果, 用户需要给指标列指定聚合函数.  通过预先聚合, 可以加速聚合操作.
  2. 分区分桶:  事实上StarRocks的表被划分成tablet, 每个tablet多副本冗余存储在BE上, BE和tablet的数量可以根据计算资源和数据规模而弹性伸缩. 查询时, 多台BE可并行地查找tablet快速获取数据. 此外, tablet的副本可复制和迁移, 增强了数据的可靠性, 避免了数据倾斜. 总之, 分区分桶保证了数据访问的高效性和稳定性.
  3. RollUp表索引(物化视图): shortkey index可加速数据查找, 然后shortkey index依赖维度列排列次序. 如果使用非前缀的维度列构造查找谓词, 则无法使用shortkey index. 用户可以为数据表创建若干RollUp表索引, RollUp表索引的数据组织和存储和数据表相同, 但RollUp表拥有自身的shortkey index. 用户创建RollUp表索引时, 可选择聚合的粒度, 列的数量, 维度列的次序; 使频繁使用的查询条件能够命中相应的RollUp表索引.
  4. 列级别的索引技术:  Bloomfilter可快速判断数据块中不含所查找值, ZoneMap通过数据范围快速过滤待查找值, Bitmap索引可快速计算出枚举类型的列满足一定条件的行

4.4 数据模型

目前StarRocks根据摄入数据和实际存储数据之间的映射关系,分为明细模型(Duplicate key)、聚合模型(Aggregate key)、更新模型(Unique key)和主键模型(Primary key)

明细模型

StarRocks建表默认采用明细模型,排序列使用稀疏索引,可以快速过滤数据。明细模型用于保存所有历史数据,并且用户可以考虑将过滤条件中频繁使用的维度列作为排序键

mysql> create database test;
mysql> use test;
CREATE TABLE IF NOT EXISTS detail (
    event_time DATETIME NOT NULL COMMENT "datetime of event",
    event_type INT NOT NULL COMMENT "type of event",
    user_id INT COMMENT "id of user",
    device_code INT COMMENT "device of ",
    channel INT COMMENT "")
    DUPLICATE KEY(event_time, event_type)
    DISTRIBUTED BY HASH(user_id) BUCKETS 8
复制代码

聚合模型

在数据分析中,很多场景需要基于明细数据进行统计和汇总,这个时候就可以使用聚合模型了。比如:统计app访问流量、用户访问时长、用户访问次数、展示总量、消费统计等等场景。聚合模型会在数据导入时将维度列相同的数据根据指标列设定的聚合函数进行聚合,最终表格中只会保留聚合后的数据。聚合模型可以减少查询时需要处理的数据量,进而提升查询的效率。

适合聚合模型来分析的业务场景有以下特点:

  1. 业务方进行查询为汇总类查询,比如sum、count、max
  2. 不需要查看原始明细数据
  3. 老数据不会被频繁修改,只会追加和新增
  4. 查询维度固定
CREATE TABLE IF NOT EXISTS aggregate_tbl (
    site_id LARGEINT NOT NULL COMMENT "id of site",
    DATE DATE NOT NULL COMMENT "time of event",
    city_code VARCHAR(20) COMMENT "city_code of user",
    pv BIGINT SUM DEFAULT "0" COMMENT "total page views",
    mt BIGINT MAX
)
DISTRIBUTED BY HASH(site_id) BUCKETS 8;
复制代码

更新模型

有些分析场景之下,数据需要进行更新比如拉链表,StarRocks则采用更新模型来满足这种需求,比如电商场景中,订单的状态经常会发生变化,每天的订单更新量可突破上亿。这种业务场景下,如果只靠明细模型下通过delete+insert的方式,是无法满足频繁更新需求的,因此,用户需要使用更新模型来满足分析需求。但是如果用户需要更加实时/频繁的更新操作,建议使用主键模型。

使用更新模型的场景特点:

  1. 已经写入的数据有大量的更新需求
  2. 需要进行实时数据分析
CREATE TABLE IF NOT EXISTS update_detail (
    create_time DATE NOT NULL COMMENT "create time of an order",
    order_id BIGINT NOT NULL COMMENT "id of an order",
    order_state INT COMMENT "state of an order",
    total_price BIGINT COMMENT "price of an order"
)
UNIQUE KEY(create_time, order_id)
DISTRIBUTED BY HASH(order_id) BUCKETS 8
复制代码

这里还需要注意,更新模型的“更新”,并不是说其支持update,而是通过追加式的数据写入,用新的数据去覆盖主键相同的历史数据,从而实现更新。同时,更新模型在导入数据时需要将所有字段补全才能够完成更新操作。

对于更新模型的数据读取,因为需要在查询时完成多版本合并,当版本过多时会导致查询性能降低。所以在向更新模型导入数据时,应该适当降低导入频率,从而提升查询性能。建议在设计导入频率时以满足业务对实时性的要求为准。如果业务对实时性的要求是分钟级别,那么每分钟导入一次更新数据即可,不需要秒级导入。

主键模型

相比较更新模型,主键模型可以更好地支持实时/频繁更新的功能。虽然更新模型也可以实现实时对数据的更新,但是更新模型采用Merge on Read读时合并策略会大大限制查询功能,在主键模型更好地解决了行级的更新操作。配合Flink-connector-starrocks可以完成Mysql CDC实时同步的方案。
需要注意的是:由于存储引擎会为主键建立索引,导入数据时会把索引加载到内存中,所以主键模型对内存的要求更高,所以不适合主键模型的场景还是比较多的。

目前比较适合使用主键模型的场景有这两种:

  1. 数据冷热特征,比如最近几天的数据才需要修改,老的冷数据很少需要修改,比如订单数据,老的订单完成后就不在更新,并且分区是按天进行分区的,那么在导入数据时历史分区的数据的主键就不会被加载,也就不会占用内存了,内存中仅会加载近几天的索引。
  2. 大宽表(数百列数千列),主键只占整个数据的很小一部分,内存开销比较低。比如用户状态/画像表,虽然列非常多,但总的用户数量不大(千万-亿级别),主键索引内存占用相对可控。

原理:由于更新模型采用Merge策略,使得谓词无法下推和索引无法使用,严重影响查询性能。所以主键模型通过主键约束,保证同一个主键仅存一条数据的记录,这样就规避了Merge操作。
StarRocks收到对某记录的更新操作时,会通过主键索引找到该条数据的位置,并对其标记为删除,再插入一条数据,相当于把update改写为delete+insert。

CREATE TABLE users (
    user_id BIGINT NOT NULL,
    NAME STRING NOT NULL,
    email STRING NULL,
    address STRING NULL,
    age TINYINT NULL,
    sex TINYINT NULL
) PRIMARY KEY (user_id)
DISTRIBUTED BY HASH(user_id) BUCKETS 4
复制代码

4.5 排序键

StarRocks为了加速查询,底层的数据是按照指定的列排序存储的,这部分用于排序的列(可以是一列或多列),就称为排序键(Sort Key)。以排序列作为条件进行数据查找,会非常的高效。

直观来看,各个模型的排序键就是建表语句中DUPLICATE KEY(明细模型)AGGREGATE KEY(聚合模型)UNIQUE KEY(更新模型)PRIMARY KEY(主键模型) 后面指定的列。

总结一下排序键的注意事项:

  1. 排序键中包含的列必须是从第一列开始,并且是连续的
  2. 排序键中列的顺序是由create table语句中的列顺序决定的
  3. 排序键不需要包含过多的列。如果选择了大量的列用于排序,那么排序的开销会导致数据导入的时间和资源使用增加;
  4. 在大多数时候,排序键中的前面几列也能很准确的定位到数据行所在的区间,更多列的排序也不会带来查询的提升;
  5. 排序键的选择需要结合查询场景,我们需要把经常作为查询条件的列建议放在排序键中。当排序键涉及多个列的时候,我们要将区分度高、经常查询的列建议放在前面。若一个字段只是偶尔查询,不需要将其放入排序键(当使用更新模型或主键模型时尤其注意这一点)。

前缀索引shortkey index

前面提到,StarRocks的底层数据是按照排序键排序后存储的。而前缀索引(shortkey index),就是在排序键的基础上实现的一种根据给定前缀列,有效加速查询的索引方式。

首先明确一点,前缀索引不需要我们单独手动创建或指定,在建表时其实已经默认完成了指定,它是StarRocks自带的一种加速方式。前缀索引的默认要求主要有:

  1. 前缀索引包含的列只能是排序键中的列;
  2. 前缀索引包含的列数不超过3;
  3. 前缀索引的字节数不超过36字节;
  4. 前缀索引不能包含FLOAT/DOUBLE类型的列;
  5. 前缀索引中VARCHAR类型列只能出现一次,并且是末尾位置(即使没有达到36个字节,如果遇到VARCHAR,也会直接截断,不再往后继续);
  6. 若在建表语句中指定PROPERTIES {"short_key" = "integer"}时, 可突破上面的第2、3条限制。

StarRocks默认每1024行构成一个逻辑块,默认取逻辑块首行数据的前36个字节作为这行数据的前缀索引存储在shortkey index表中(这个表上层不可感知)。

4.6 分区分桶与副本数

分区

StarRocks中的分区是在建表时通过PARTITION BY RANGE() 语句设置,用于分区的列也被称之为分区键,当前分区键仅支持日期类型和整数类型,且仅支持一列
若建表时我们不进行分区,StarRocksm默认会将整个table作为一个分区(这个分区的名称和表名相同)。

分桶

对每个分区的数据,StarRocks还会再进行Hash分桶。我们在建表时通过DISTRIBUTED BY HASH() 语句来设置分桶,用于分桶的列也被称之为分桶键。
分桶键可以是一列或多列,例如前文中表table06的user_id就是分桶键。在聚合模型和更新模型\主键模型下,分桶键必需是排序键中的列。

分桶的目的就是将数据打散为一个个逻辑分片(Tablet),以Tablet作为数据均衡的最小单位,使数据尽量均匀的分布在集群的各个BE节点上,以便在查询时充分发挥集群多机多核的优势。

在StarRocks中,Partition是数据导入和备份恢复的最小逻辑单位,Tablet是数据复制和均衡的最小物理单位。表(Table)、分区(Partition)、逻辑分片(Tablet)的关系如下图

image.png

副本数

StarRocks中的副本数就是同一个Tablet保存的份数,在建表时通过replication_num参数指定,也可以后面修改。
默认不指定时,StarRocks使用三副本建表,也即每个Tablet会在不同节点存储三份(StarRocks的副本策略会将某个tablet的副本存储在与其不同IP的节点)。

总结一下:分区是针对表的,是对表的数据取段。分桶是针对每个分区的,会将分区后的每段数据打散为逻辑分片Tablet。副本数是针对Tablet的,是指Tablet保存的份数。

那么我们不难发现,对某一个数据表,若每个分区的分桶数一致,其总Tablet数:
总Tablet数=分区数 * 分桶数 * 副本数

动态分区/分区分桶修改/临时分区/冷热分区

第2.4章:StarRocks表设计--分区分桶与副本数

  • 动态分区
    • 在StarRocks中,必须先有分区,才能将对应的数据导入进来,不然导入就会报错(提示there is a row couldn’t find a partition)。比如使用日期作为分区,那就需要先创建每天的分区,再进行数据导入。在日常业务中,除了每日会新增数据,我们还会对旧的历史数据进行清理。动态分区就是StarRocks用来实现新分区自动创建以及过期分区自动删除的方式
  • 分区分桶修改
    • 在建表完成后,我们也可以手动增加分区。此时,如果没有指定分桶方式,则自动使用建表时的分桶方式。如果指定分桶方式,则使用新的分桶方式创建(这里当前只能修改分桶数,不能修改分桶方式或分桶列)。另外注意,动态分区表的分区不能直接增删改,若要操作,需要先关闭其动态分区属性。
  • 副本数修改
  • 临时分区
    • StarRocks中也有临时分区的概念,通过临时分区,我们可以较为方便的调整原数据表中不合理分区的分桶数或者分区范围,也可以在StarRocks中基于lambda模式方便的进行数据导入(用T+1的数据修正实时数据)。
  • 冷热分区
    • 当同一台服务器中既有SSD又有HDD时,StarRocks并不会自动识别磁盘的类型,我们需要在be.conf中为storage_root_path显式的指定存储介质类型

4.7 列级别索引

  • Bitmap索引适合低基数列(基数是指某个列可能拥有的不重复数值的个数),可以快速计算出枚举类型的列满足一定条件的行。
  • Bloomfilter索引用于高基数列,可快速判断数据块中不含所查找值。

4.7.1 Bitmap索引

适用场景
  • 非前缀过滤:前面提到过,StarRocks对于表结构中的前几列可以通过前缀索引快速过滤。如果需要对非前置列进行快速过滤,就可以对这些列建立Bitmap索引。
  • 多列过滤:Bitmap可以快速的进行bitwise运算,所以在多列过滤的场景中,也可以考虑对每列分别建立Bitmap索引。
注意事项

使用Bitmap索引前我们需要注意以下几点:

  1. 对于明细模型,所有列都可以创建Bitmap 索引。聚合模型和更新模型,只有Key列可以建Bitmap索引。主键模型允许为非主键列创建bitmap索引,但需要建表时指定
  2. Bitmap索引,应该在取值为枚举型,取值大量重复,较低基数,并且用作等值条件查询或者可转化为等值条件查询的列上创建;
  3. 不支持对Float、Double、Decimal类型的列建Bitmap索引;
  4. 创建索引为异步操作,若需要为表中多列创建索引,需要在一个创建完成后再创建下一个。
索引操作
在创建表时创建Bitmap索引:
CREATE TABLE table01 (
    user_id INT COMMENT "id of user",
    device_code INT COMMENT "code of device",
    device_price DECIMAL(10,2) COMMENT "",
    event_time DATETIME NOT NULL COMMENT "datetime of event",
    total DECIMAL(18,2) SUM DEFAULT "0" COMMENT "total amount of equipment",
    index index01 (user_id) USING BITMAP COMMENT "bitmap index"
)


建表完成后需要为表添加索引:
CREATE INDEX index_name1 ON table02 (channel) USING BITMAP COMMENT 'Bitmap Index';

创建索引为异步操作,我们可以通过下面的命令查看状态:
mysql> SHOW ALTER TABLE COLUMN WHERE TableName = "table02";
当State为FINISHED时,即表示创建完成。

查看table02表Bitmap索引:
mysql> SHOW INDEX FROM table02;

删除channel列的bitmap索引:
mysql> DROP INDEX index_name1 ON table02;
Query OK, 0 rows affected (0.02 sec)
删除索引也为异步操作,还是通过上面的show语句查看状态,当State为FINISHED时,即表示删除完毕。
复制代码

4.7.2 BloomFilter索引

在查询时,BloomFilter可以快速判断某个列中是否存在某个值,如果Bloom Filter判定该列中不存在指定的值,就不需要读取数据文件,进而提升查询效率。

适用场景

以下几种场景时可以考虑创建Bloom Filter 索引:

  1. 非前缀列过滤;
  2. 高基数列;
  3. 查询需对某列高频过滤,且查询条件是in和=(Bloom Filter索引只对in和=过滤查询有加速效果);
注意事项
  1. 非Tinyint、Float、Double、DECIMAL类型的列(这些类型暂不支持)。
  2. 对于明细模型,所有列都可以创建Bloom Filter索引。聚合模型和更新模型,只有Key列可以建Bloom Filter索引。主键模型允许为非主键列创建Bloom Filter索引,仍需要建表时指定。
索引操作

不同于Bitmap索引,我们需要在表的PROPERTIES中指定需要建BloomFilter索引的列(一列或多列都可以),格式为:PROPERTIES{"bloom_filter_columns"="c1,c2,c3"}

例如table01的:
mysql> CREATE TABLE table01 (
    user_id INT COMMENT "id of user",
    device_code INT COMMENT "code of device",
    device_price DECIMAL(10,2) COMMENT "",
    event_time DATETIME NOT NULL COMMENT "datetime of event",
    total DECIMAL(18,2) SUM DEFAULT "0" COMMENT " total amount of equipment",
……………………………………
PROPERTIES (
"replication_num" = "1",
"bloom_filter_columns"="event_time"
);

table01的BloomFilter索引查看方式目前为:
mysql> SHOW CREATE TABLE table01;

删除索引,也即将索引列从bloom_filter_columns属性中移除:
mysql> ALTER TABLE table01 SET ("bloom_filter_columns" = "");

删除操作为异步操作,查看进度方法也是:
mysql> SHOW ALTER TABLE COLUMN WHERE TableName = "table01";

修改索引,即为修改表的bloom_filter_columns属性:
mysql> ALTER TABLE table01 SET ("bloom_filter_columns" = "device_code,event_time");

修改操作也为异步,可使用上面的show语句查看状态,当State为FINISHED时即为修改完成。
复制代码

猜你喜欢

转载自juejin.im/post/7060874903922147365