其他更多java基础文章:
java基础学习(目录)
- 本文为尚硅谷StarRocks视频的整理总结,另外发现一个讲StarRocks的系列博客。
- StarRocks导入官方文档
1. 数据导入与查询
1.1 Stream Load
StarRocks支持从本地直接导入数据,支持CSV文件格式。数据量在10GB以下。
Stream Load 是一种同步的导入方式,用户通过发送 HTTP 请求将本地文件或数据流导入到 StarRocks 中。Stream Load 同步执行导入并返回导入结果。用户可直接通过请求的返回值判断导入是否成功。
基本原理
Stream Load 中,用户通过HTTP协议提交导入命令。如果提交到FE节点,则FE节点会通过HTTP redirect指令将请求转发给某一个BE节点,用户也可以直接提交导入命令给某一指定BE节点。该BE节点作为Coordinator节点,将数据按表schema划分并分发数据到相关的BE节点。导入的最终结果由 Coordinator节点返回给用户。
下图展示了Stream Load的主要流程:
示例
- 以user表为例,创建对应的CSV文件
[root@hadoop101 ~]# vim test.csv
1001,'test1',123456@.qqcom,'测试地址1',18,1
1002,'test2',123456@.qqcom,'测试地址2',18,1
1003,'test3',123456@.qqcom,'测试地址3',20,0
1004,'test4',123456@.qqcom,'测试地址4',21,1
1005,'test5',123456@.qqcom,'测试地址5',23,0
1006,'test6',123456@.qqcom,'测试地址6',22,1
1007,'test7',123456@.qqcom,'测试地址7',18,0
1008,'test8',123456@.qqcom,'测试地址8',25,1
1009,'test9',123456@.qqcom,'测试地址9',19,0
1010,'test10',123456@.qqcom,'测试地址10',10,1
1011,'test11',123456@.qqcom,'测试地址11',18,1
- 根据官网语法将CSV数据导入对应user表中,官网语法:
curl --location-trusted -u user:passwd [-H ""...] -T data.file -XPUT \
http://fe_host:http_port/api/{db}/{table}/_stream_load
注意:命令-H 为头部信息 column_separator为测试文件中字段间隔符,虽然官网写着支持csv但默认是\t,默认支持tsv所以这把这个参数改成逗号
[root@hadoop101 ~]# curl --location-trusted -u root -T test.csv -H "column_separator:," http://hadoop101:8030/api/test/users/_stream_load
-
因为Stream load是同步导入,所以可以立马看到是否导入成功
-
导入成功后,查看对应的users表
select *from users;
1.2 Broker Load
StarRocks支持从Apache HDFS、Amazon S3等外部存储系统导入数据,支持CSV、ORCFile、Parquet等文件格式。数据量在几十GB到上百GB 级别。
在Broker Load模式下,通过部署的Broker程序,StarRocks可读取对应数据源(如HDFS, S3)上的数据,利用自身的计算资源对数据进行预处理和导入。这是一种异步的导入方式,用户需要通过MySQL协议创建导入,并通过查看导入命令检查导入结果。
基本原理
用户在提交导入任务后,FE 会生成对应的 Plan 并根据目前 BE 的个数和文件的大小,将 Plan 分给多个 BE 执行,每个 BE 执行一部分导入任务。BE 在执行过程中会通过 Broker 拉取数据,在对数据预处理之后将数据导入系统。所有 BE 均完成导入后,由 FE 最终判断导入是否成功。
下图展示了 Broker Load 的主要流程:
示例
(1)先保证启动broker进程
[root@hadoop101 ~]# /opt/module/StarRocks-1.19.1/apache_hdfs_broker/bin/start_broker.sh --daemon
[root@hadoop102 ~]# /opt/module/StarRocks-1.19.1/apache_hdfs_broker/bin/start_broker.sh --daemon
[root@hadoop103 ~]# /opt/module/StarRocks-1.19.1/apache_hdfs_broker/bin/start_broker.sh --daemon
(2)这里演示Apache HDFS导入StarRocks,将Hadoop集群的hdfs-site.xml文件复制到对应broker conf 目录下
[root@hadoop101 ~]# cp /opt/module/hadoop-3.1.3/etc/hadoop/hdfs-site.xml /opt/module/StarRocks-1.19.1/apache_hdfs_broker/conf/
[root@hadoop102 ~]# cp /opt/module/hadoop-3.1.3/etc/hadoop/hdfs-site.xml /opt/module/StarRocks-1.19.1/apache_hdfs_broker/conf/
[root@hadoop103 ~]# cp /opt/module/hadoop-3.1.3/etc/hadoop/hdfs-site.xml /opt/module/StarRocks-1.19.1/apache_hdfs_broker/conf/
(3)Broker Load官方任务语法如下:
LOAD LABEL db_name.label_name
(data_desc, ...)
WITH BROKER broker_name broker_properties
[PROPERTIES (key1=value1, ... )]
data_desc:
DATA INFILE ('file_path', ...)
[NEGATIVE]
INTO TABLE tbl_name
[PARTITION (p1, p2)]
[COLUMNS TERMINATED BY column_separator ]
[FORMAT AS file_type]
[(col1, ...)]
[COLUMNS FROM PATH AS (colx, ...)]
[SET (k1=f1(xx), k2=f2(xx))]
[WHERE predicate]
broker_properties:
(key2=value2, ...)
(4)启动hadoop集群,进入到hive中创建一张测试表,采用parquet列式存储,snappy压缩
create external table test_member(
uid int,
ad_id int,
birthday string,
email string,
fullname string)
partitioned by(
dt string,
dn string)
ROW FORMAT DELIMITED
STORED AS PARQUET TBLPROPERTIES('parquet.compression'='SNAPPY');
(5)插入几条测试数据
insert into test_member values(1001,1,'1990-01-01','111@qq.com','test1','2021-11-20','A'),
(1002,2,'1990-01-01','111@qq.com','test1','2021-11-20','A'),
(1003,3,'1990-01-01','111@qq.com','test1','2021-11-20','A'),
(1004,4,'1990-01-01','111@qq.com','test1','2021-11-20','A'),
(1005,5,'1990-01-01','111@qq.com','test1','2021-11-20','A');
(6)创建对应StartRocks表
CREATE TABLE test_bl(
uid INT,
ad_id INT,
birthday varchar(20),
email varchar(20),
fullname varchar(20),
dt varchar(20),
dn varchar(20) )
DUPLICATE KEY(uid)
DISTRIBUTED BY HASH(uid) BUCKETS 8;
(7)据官方语法创建Broker Load将数据导入到StartRocks
LOAD LABEL test.label1
(
DATA INFILE("hdfs://mycluster/user/hive/warehouse/test_member/dt=2021-11-20/dn=A/*")
INTO TABLE test_bl
FORMAT AS "parquet"
(uid,ad_id,birthday,email,fullname)
SET
(
uid=uid,
ad_id=ad_id,
birthday=birthday,
email=email,
fullname=fullname,
dt='2021-11-20',
dn='A'
)
)
WITH BROKER "broker1"
(
"dfs.nameservices"="mycluster",
"dfs.ha.namenodes.mycluster"="nn1,nn2,nn3",
"dfs.namenode.rpc-address.mycluster.nn1"= "hadoop101:8020",
"dfs.namenode.rpc-address.mycluster.nn2"= "hadoop102:8020",
"dfs.namenode.rpc-address.mycluster.nn3"="hadoop103:8020",
"dfs.client.failover.proxy.provider.mycluster"="org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider"
)
PROPERTIES
(
"timeout" = "3600"
);
(8)查看load计划,
show load where label='label1';
(9)查看StarRock表数据
select *from test_bl;
1.3 Rountine Load
Routine Load 是一种例行导入方式,StarRocks通过这种方式支持从Kafka持续不断的导入数据,并且支持通过SQL控制导入任务的暂停、重启、停止。本节主要介绍该功能的基本原理和使用方式。
基本原理
导入流程如下图:
- 用户通过支持MySQL协议的客户端向 FE 提交一个Kafka导入任务。
- FE将一个导入任务拆分成若干个Task,每个Task负责导入指定的一部分数据。
- 每个Task被分配到指定的 BE 上执行。在 BE 上,一个 Task 被视为一个普通的导入任务, 通过 Stream Load 的导入机制进行导入。
- BE导入完成后,向 FE 汇报。
- FE 根据汇报结果,继续生成后续新的 Task,或者对失败的 Task 进行重试。
- FE 会不断的产生新的 Task,来完成数据不间断的导入。
示例
(1)创建load将kafka中的数据导入到test_bl中;
CREATE ROUTINE LOAD rl_test on test_bl
COLUMNS TERMINATED BY ","
PROPERTIES
(
"desired_concurrent_number"="3",
"max_error_number"="1000"
)
FROM KAFKA
(
"kafka_broker_list"= "hadoop101:9092,hadoop102:9092,hadoop103:9092",
"kafka_topic" = "test",
"property.group.id" = "start-rocks-test",
"property.kafka_default_offsets" = "OFFSET_BEGINNING"
);
(2)查看load任务,可以看到接收到了数据,并且任务一直是running正在运行状态
- 查看当前正在运行的所有Routine Load任务
SHOW ROUTINE LOAD\G; - 显示 [database] 下,所有的例行导入作业(包括已停止或取消的作业)。结果为一行或多行。
SHOW ALL ROUTINE LOAD; - 显示 [database] 下,名称为 job_name 的当前正在运行的例行导入作业。
SHOW ROUTINE LOAD FOR [database.][job_name];
1.4 导入过程中完成数据转换
StarRocks能够在数据导入时完成数据转化的操作。这样在数据源与目标表中内容不一致的情况下,用户不需要外部的ETL工作,可以直接通过StarRocks提供的能力在导入时就完成数据转化。本功能只能在本地文件导入、HDFS导入、Kafka导入中使用
通过StarRocks提供的能力,用户可以在数据导入时实现以下目标:
- 选择需要导入的列。一方面通过此功能可以跳过不需要导入的列;另一方面当表中列的顺序与文件中字段顺序不一致时,可以通过此功能建立两者的字段映射,从而导入文件。
- 过滤不需要的行。在导入时可以通过指定表达式,从而跳过不需要导入的行,只导入必要的行内容。
- 导入时生成衍生列(即通过计算处理产生新的列)导入到StarRocks目标表中。
- 支持Hive分区路径命名方式,StarRocks能够从文件路径中获取分区列的内容。
1.5 Spark Load
Spark Load 通过外部的 Spark 资源实现对导入数据的预处理,提高 StarRocks 大数据量的导入性能并且节省 StarRocks 集群的计算资源。主要用于初次迁移、大数据量导入 StarRocks 的场景(数据量可到TB级别)。
Spark Load 是一种异步导入方式,用户需要通过 MySQL 协议创建 Spark 类型导入任务,并可以通过 SHOW LOAD 查看导入结果。
基本原理
用户通过 MySQL 客户端提交 Spark 类型导入任务,FE记录元数据并返回用户提交成功。
Spark Load 任务的执行主要分为以下几个阶段:
- 用户向 FE 提交 Spark Load 任务;
- FE 调度提交 ETL 任务到 Spark 集群执行。
- Spark 集群执行 ETL 完成对导入数据的预处理。包括全局字典构建(BITMAP类型)、分区、排序、聚合等。
- ETL 任务完成后,FE 获取预处理过的每个分片的数据路径,并调度相关的 BE 执行 Push 任务。
- BE 通过 Broker 读取数据,转化为 StarRocks 存储格式。
- FE 调度生效版本,完成导入任务。 下图展示了 Spark Load 的主要流程:
示例
1.6 Insert Into
Insert Into 语句的使用方式和 MySQL 等数据库中 Insert Into 语句的使用方式类似。 但在 StarRocks 中,所有的数据写入都是一个独立的导入作业
1.7 Flink Connector
flink的用户想要将数据sink到StarRocks当中,但是flink官方只提供了flink-connector-jdbc, 不足以满足导入性能要求,为此我们新增了一个flink-connector-starrocks,内部实现是通过缓存并批量由stream load导入。
示例
(1) pom.xml引入jar包,点击 版本信息 查看页面Latest Version信息,替换下面x.x.x内容
<dependency>
<groupId>com.starrocks</groupId>
<artifactId>flink-connector-starrocks</artifactId>
<!-- for flink-1.11, flink-1.12 -->
<version>x.x.xx_flink-1.11</version>
<!-- for flink-1.13 -->
<version>x.x.xx_flink-1.13</version>
</dependency>
(2)访问StarRocks,创建测试表
CREATE TABLE IF NOT EXISTS flink_student (
uid INT,
name VARCHAR(20),
age INT,
email VARCHAR(20),
sex VARCHAR(10)
)
DUPLICATE KEY(uid)
DISTRIBUTED BY HASH(uid) BUCKETS 8
(3)使用stream方式插入表中
package com.atguigu.starrocks.test;
import com.google.gson.Gson;
import com.starrocks.connector.flink.StarRocksSink;
import com.starrocks.connector.flink.table.StarRocksSinkOptions;
import org.apache.flink.streaming.api.datastream.DataStreamSource;
import org.apache.flink.streaming.api.environment.StreamExecutionEnvironment;
import java.util.Arrays;
public class FlinkToStarRocksTest {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
FlinkToStarRocksTest ft = new FlinkToStarRocksTest();
ft.useStream(env);
env.execute();
}
void useStream(StreamExecutionEnvironment env) {
Gson gson = new Gson();
DataStreamSource<String> studentDataStreamSource = env.fromCollection(Arrays.asList(
gson.toJson(new Student(1001, "张三", 18, "111@qq.com", "男")),
gson.toJson(new Student(1002, "李四", 19, "222@qq.com", "女")),
gson.toJson(new Student(1003, "王五", 20, "333@qq.com", "男"))));
studentDataStreamSource.addSink(StarRocksSink.sink(
StarRocksSinkOptions.builder()
.withProperty("jdbc-url", "jdbc:mysql://hadoop101:9030")
.withProperty("load-url", "hadoop101:8030;hadoop102:8030;hadoop103:8030")
.withProperty("username", "root")
.withProperty("password", "")
.withProperty("table-name", "flink_student")
.withProperty("database-name", "test")
.withProperty("sink.properties.format", "json")
.withProperty("sink.properties.strip_outer_array", "true")
.build()
)
);
}
}
class Student {
private int uid;
private String name;
private int age;
private String email;
private String sex;
public Student(int uid, String name, int age, String email, String sex) {
this.uid = uid;
this.name = name;
this.age = age;
this.email = email;
this.sex = sex;
}
}
(4)使用sql的方式导入
public class FlinkToStarRocksTest {
public static void main(String[] args) throws Exception {
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
StreamTableEnvironment tableEnv = StreamTableEnvironment.create(env);
FlinkToStarRocksTest ft = new FlinkToStarRocksTest();
ft.useSql(tableEnv);
}
void useSql(StreamTableEnvironment env) {
env.executeSql("CREATE TABLE flink_student(\n" +
"uid INT,\n" +
"name VARCHAR(20),\n" +
"age INT,\n" +
"email VARCHAR(20),\n" +
"sex VARCHAR(10)\n" +
")WITH(\n" +
"'connector' = 'starrocks',\n" +
"'jdbc-url'='jdbc:mysql://hadoop101:9030',\n" +
"'load-url'='hadoop101:8030;hadoop102:8030;hadoop103:8030',\n" +
"'username'='root',\n" +
"'password'='',\n" +
"'table-name'='flink_student', \n" +
"'database-name'='test',\n" +
"'sink.properties.format'='json',\n" +
"'sink.properties.strip_outer_array'='true' \n" +
")");
StatementSet statementSet = env.createStatementSet();
statementSet.addInsertSql("insert into flink_student values(1001,'李四',19,'111.qq.com','女')," +
"(1002,'张三',20,'222@qq.com','男')");
statementSet.execute();
}
}