上篇文章简单讲了doris的安装,本章分享的是doris中fe和be节点的扩容缩容以及doris的数据表
使用 MySQL 登录客户端后,可以使用 sql 命令查看 FE 状态,目前就一台 FE
mysql -h linux -P 9030 -uroot -p
mysql> SHOW PROC '/frontends'\G;
*************************** 1. row ***************************
Name: 192.168.***.*_9010_1661510658077
IP: 192.168.17.3
HostName: doitedu01
EditLogPort: 9010
HttpPort: 8030
QueryPort: 9030
RpcPort: 9020
Role: FOLLOWER
IsMaster: true
ClusterId: 1133836578
Join: true
Alive: true
ReplayedJournalId: 2472
LastHeartbeat: 2022-08-26 13:07:47
IsHelper: true
ErrMsg:
Version: 1.1.1-rc03-2dbd70bf9
CurrentConnected: Yes
1 row in set (0.03 sec)
添加FE的新节点:
FE 分为 Leader,Follower 和 Observer 三种角色。 默认一个集群,只能有一个 Leader,可以有多个 Follower 和 Observer。其中 Leader 和 Follower 组成一个 Paxos 选择组,如果Leader 宕机,则剩下的 Follower 会自动选出新的 Leader,保证写入高可用。Observer 同步 Leader 的数据,但是不参加选举。
如果只部署一个 FE,则 FE 默认就是 Leader。在此基础上,可以添加若干 Follower 和 Observer。
ALTER SYSTEM ADD FOLLOWER "linux02:9010";
ALTER SYSTEM ADD OBSERVER "linux03:9010";
在02和03上分别启动fe节点
如果没有配置环境变量需要写全安装路径
/opt/app/doris/fe/bin/start_fe.sh --helper linux01:9010 --daemon
注意:如果是第一次添加的话,一定要加这两个参数 --helper linux01:9010
此时你再去查看FE的状态就发现有3台
mysql> SHOW PROC '/frontends'\G;
*************************** 1. row ***************************
Name: 192.168.***.*_9010_1661490723344
IP: 192.168.17.4
HostName: doitedu02
EditLogPort: 9010
HttpPort: 8030
QueryPort: 0
RpcPort: 0
Role: FOLLOWER
IsMaster: false
ClusterId: 1133836578
Join: false
Alive: false
ReplayedJournalId: 0
LastHeartbeat: NULL
IsHelper: true
ErrMsg: java.net.ConnectException: Connection refused (Connection refused)
Version: NULL
CurrentConnected: No
*************************** 2. row ***************************
Name: 192.168.***.*_9010_1661490727316
IP: 192.168.17.5
HostName: doitedu03
EditLogPort: 9010
HttpPort: 8030
QueryPort: 0
RpcPort: 0
Role: OBSERVER
IsMaster: false
ClusterId: 1133836578
Join: false
Alive: false
ReplayedJournalId: 0
LastHeartbeat: NULL
IsHelper: false
ErrMsg: java.net.ConnectException: Connection refused (Connection refused)
Version: NULL
CurrentConnected: No
*************************** 3. row ***************************
Name: 192.168.***.*_9010_1661510658077
IP: 192.168.17.3
HostName: doitedu01
EditLogPort: 9010
HttpPort: 8030
QueryPort: 9030
RpcPort: 9020
Role: FOLLOWER
IsMaster: true
ClusterId: 1133836578
Join: true
Alive: true
ReplayedJournalId: 2577
LastHeartbeat: 2022-08-26 13:13:33
IsHelper: true
ErrMsg:
Version: 1.1.1-rc03-2dbd70bf9
CurrentConnected: Yes
3 rows in set (0.04 sec)
删除FE节点命令
ALTER SYSTEM DROP FOLLOWER[OBSERVER] "fe_host:edit_log_port";
ALTER SYSTEM DROP FOLLOWER "linux01:9010";
增加 BE 节点
在 MySQL 客户端,通过
ALTER SYSTEM ADD BACKEND 命令增加 BE 节点。
ALTER SYSTEM ADD BACKEND "linux01:9050";
DECOMMISSION 方式删除 BE 节点
ALTER SYSTEM DECOMMISSION BACKEND "be_host:be_heartbeat_service_port";
ALTER SYSTEM DECOMMISSION BACKEND "linux01:9050";
TINYINT | 1 字节 | 范围:-2^7 + 1 ~ 2^7 - 1 |
---|---|---|
SMALLINT | 2 字节 | 范围:-2^15 + 1 ~ 2^15 - 1 |
INT | 4 字节 | 范围:-2^31 + 1 ~ 2^31 - 1 |
BIGINT | 8 字节 | 范围:-2^63 + 1 ~ 2^63 - 1 |
LARGEINT | 16 字节 | 范围:-2^127 + 1 ~ 2^127 - 1 |
FLOAT | 12 字节 | 支持科学计数法 |
DECIMAL[(precision, scale)] | 16 字节 | 保证精度的小数类型。默认是DECIMAL(10, 0) ,precision: 1 ~ 27 ,scale: 0 ~ 9,其中整数部分为 1 ~ 18,不支持科学计数法 |
DATE | 3 字节 | 范围:0000-01-01 ~ 9999-12-31 |
DATETIME | 8 字节 | 范围:0000-01-01 00:00:00 ~ 9999-12-31 23:59:59 |
CHAR[(length)] | 定长字符串。长度范围:1 ~ 255。默认为 1 | |
VARCHAR[(length)] | 变长字符串。长度范围:1 ~ 65533 | |
BOOLEAN | 与 TINYINT 一样,0 代表 false,1 代表 true | |
HLL | 1~16385 个字节 | hll 列类型,不需要指定长度和默认值,长度根据数据的聚合程度系统内控制,并且 HLL 列只能通过 配套的hll_union_agg、Hll_cardinality、hll_hash 进行查询或使用 |
BITMAP | bitmap 列类型,不需要指定长度和默认值。表示整型的集合,元素最大支持到 2^64 - 1 | |
STRING | 变长字符串,0.15 版本支持,最大支持 2147483643 字节(2GB-4),长度还受 be 配置string_type_soft_limit , 实际能存储的最大长度取两者最小值。只能用在 value 列,不能用在 key列和分区、分桶列 |
一张表包括行(Row)和列(Column);
Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。
doris中的列分为两类:key列和value列
key列在doris中有两种作用:
聚合表模型中,key是聚合和排序的依据
其他表模型中,key是排序依据
-- Range Partition
drop table if exists test.expamle_range_tbl;
CREATE TABLE IF NOT EXISTS test.expamle_range_tbl
(
`user_id` LARGEINT NOT NULL COMMENT "用户id",
`date` DATE NOT NULL COMMENT "数据灌入日期时间",
`timestamp` DATETIME NOT NULL COMMENT "数据灌入的时间戳",
`city` VARCHAR(20) COMMENT "用户所在城市",
`age` SMALLINT COMMENT "用户年龄",
`sex` TINYINT COMMENT "用户性别"
)
ENGINE=OLAP
DUPLICATE KEY(`user_id`, `date`) -- 表模型
-- 分区的语法
PARTITION BY RANGE(`date`) -- 指定分区类型和分区列
(
-- 指定分区名称,分区的上界 前闭后开
PARTITION `p201701` VALUES LESS THAN ("2017-02-01"),
PARTITION `p201702` VALUES LESS THAN ("2017-03-01"),
PARTITION `p201703` VALUES LESS THAN ("2017-04-01")
)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1;
-- 查看表中分区得情况
SHOW PARTITIONS FROM test.expamle_range_tbl \G;
mysql> SHOW PARTITIONS FROM test.expamle_range_tbl \G;
*************************** 1. row ***************************
PartitionId: 12020
PartitionName: p201701
VisibleVersion: 1
VisibleVersionTime: 2022-08-30 21:57:36
State: NORMAL
PartitionKey: date
Range: [types: [DATE]; keys: [0000-01-01]; ..types: [DATE]; keys: [2017-02-01]; )
DistributionKey: user_id
Buckets: 1
ReplicationNum: 3
StorageMedium: HDD
CooldownTime: 9999-12-31 23:59:59
LastConsistencyCheckTime: NULL
DataSize: 0.000
IsInMemory: false
ReplicaAllocation: tag.location.default: 3
*************************** 2. row ***************************
PartitionId: 12021
PartitionName: p201702
VisibleVersion: 1
VisibleVersionTime: 2022-08-30 21:57:36
State: NORMAL
PartitionKey: date
Range: [types: [DATE]; keys: [2017-02-01]; ..types: [DATE]; keys: [2017-03-01]; )
DistributionKey: user_id
Buckets: 1
ReplicationNum: 3
StorageMedium: HDD
CooldownTime: 9999-12-31 23:59:59
LastConsistencyCheckTime: NULL
DataSize: 0.000
IsInMemory: false
ReplicaAllocation: tag.location.default: 3
*************************** 3. row ***************************
PartitionId: 12022
PartitionName: p201703
VisibleVersion: 1
VisibleVersionTime: 2022-08-30 21:57:35
State: NORMAL
PartitionKey: date
Range: [types: [DATE]; keys: [2017-03-01]; ..types: [DATE]; keys: [2017-04-01]; )
DistributionKey: user_id
Buckets: 1
ReplicationNum: 3
StorageMedium: HDD
CooldownTime: 9999-12-31 23:59:59
LastConsistencyCheckTime: NULL
DataSize: 0.000
IsInMemory: false
ReplicaAllocation: tag.location.default: 3
3 rows in set (0.00 sec)
这是他生成得三个分区:
p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201703: [2017-03-01, 2017-04-01)
增加一个分区 p201705 VALUES LESS THAN (“2017-06-01”),分区结果如下:
ALTER TABLE test.expamle_range_tbl ADD PARTITION p201705 VALUES LESS THAN ("2017-06-01");
p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201703: [2017-03-01, 2017-04-01)
p201705: [2017-04-01, 2017-06-01)
删除分区 p201703,则分区结果如下:
ALTER TABLE test.expamle_range_tbl DROP PARTITION p201703;
p201701: [MIN_VALUE, 2017-02-01)
p201702: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)
增加一个分区 p201702new VALUES LESS THAN (“2017-03-01”),分区结果如下:
p201701: [MIN_VALUE, 2017-02-01)
p201702new: [2017-02-01, 2017-03-01)
p201705: [2017-04-01, 2017-06-01)
可以看到空洞范围缩小为:[2017-03-01, 2017-04-01)
Range分区除了上述看到的单列分区,也支持多列分区,示例如下:
PARTITION BY RANGE(`date`, `id`) 前闭后开
(
PARTITION `p201701_1000` VALUES LESS THAN ("2017-02-01", "1000"),
PARTITION `p201702_2000` VALUES LESS THAN ("2017-03-01", "2000"),
PARTITION `p201703_all` VALUES LESS THAN ("2017-04-01")-- 默认采用id类型的最小值
)
指定 date(DATE 类型) 和 id(INT 类型) 作为分区列。以上示例最终得到的分区如下:
* p201701_1000: [(MIN_VALUE, MIN_VALUE), ("2017-02-01", "1000") )
* p201702_2000: [("2017-02-01", "1000"), ("2017-03-01", "2000") )
* p201703_all: [("2017-03-01", "2000"), ("2017-04-01", MIN_VALUE))
-- List Partition
CREATE TABLE IF NOT EXISTS test.expamle_list_tbl
(
`user_id` LARGEINT NOT NULL COMMENT "用户id",
`date` DATE NOT NULL COMMENT "数据灌入日期时间",
`timestamp` DATETIME NOT NULL COMMENT "数据灌入的时间戳",
`city` VARCHAR(20) NOT NULL COMMENT "用户所在城市",
`age` SMALLINT NOT NULL COMMENT "用户年龄",
`sex` TINYINT NOT NULL COMMENT "用户性别",
`last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间",
`cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
`max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
`min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时间"
)
ENGINE=olap
AGGREGATE KEY(`user_id`, `date`, `timestamp`, `city`, `age`, `sex`)
PARTITION BY LIST(`city`)
(
PARTITION `p_cn` VALUES IN ("Beijing", "Shanghai", "Hong Kong"),
PARTITION `p_usa` VALUES IN ("New York", "San Francisco"),
PARTITION `p_jp` VALUES IN ("Tokyo")
)
-- 指定分桶的语法
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1
PROPERTIES
(
"replication_num" = "3"
);
当建表完成后,会自动生成如下3个分区:
p_cn: ("Beijing", "Shanghai", "Hong Kong")
p_usa: ("New York", "San Francisco")
p_jp: ("Tokyo")
增加一个分区 p_uk VALUES IN (“London”),分区结果如下:
p_cn: ("Beijing", "Shanghai", "Hong Kong")
p_usa: ("New York", "San Francisco")
p_jp: ("Tokyo")
p_uk: ("London")
List分区也支持多列分区,示例如下:
PARTITION BY LIST(`id`, `city`)
(
PARTITION `p1_city` VALUES IN (("1", "Beijing",), ("2", "Shanghai")),
PARTITION `p2_city` VALUES IN (("2", "Beijing"), ("1", "Shanghai")),
PARTITION `p3_city` VALUES IN (("3", "Beijing"), ("4", "Shanghai"))
)
关于 Partition 和 Bucket的数量和数据量的建议。
Doris 的数据模型主要分为3类:
是相同key的数据进行自动聚合的表模型。表中的列按照是否设置了 AggregationType,分为 Key(维度列)和 Value(指标列),没有设置 AggregationType 的称为 Key,设置了 AggregationType 的称为 Value。当我们导入数据时,对于 Key 列相同的行会聚合成一行,而 Value 列会按照设置的AggregationType 进行聚合。AggregationType 目前有以下四种聚合方式:
sql示例:
-- 这是一个用户消费和行为记录的数据表
CREATE TABLE IF NOT EXISTS test.ex_user
(
`user_id` LARGEINT NOT NULL COMMENT "用户 id",
`date` DATE NOT NULL COMMENT "数据灌入日期时间",
`city` VARCHAR(20) COMMENT "用户所在城市",
`age` SMALLINT COMMENT "用户年龄",
`sex` TINYINT COMMENT "用户性别",
`last_visit_date` DATETIME REPLACE DEFAULT "1970-01-01 00:00:00" COMMENT "用户最后一次访问时间",
`cost` BIGINT SUM DEFAULT "0" COMMENT "用户总消费",
`max_dwell_time` INT MAX DEFAULT "0" COMMENT "用户最大停留时间",
`min_dwell_time` INT MIN DEFAULT "99999" COMMENT "用户最小停留时间"
)
ENGINE=olap
AGGREGATE KEY(`user_id`, `date`, `city`, `age`, `sex`)
-- 分区
-- 分桶
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1;
向表中插入部分数据
insert into test.ex_user values\
(10000,'2017-10-01','北京',20,0,'2017-10-01 06:00:00',20,10,10),\
(10000,'2017-10-01','北京',20,0,'2017-10-01 07:00:00',15,2,2),\
(10001,'2017-10-01','北京',30,1,'2017-10-01 17:05:45',2,22,22),\
(10002,'2017-10-02','上海',20,1,'2017-10-02 12:59:12',200,5,5),\
(10003,'2017-10-02','广州',32,0,'2017-10-02 11:20:00',30,11,11),\
(10004,'2017-10-01','深圳',35,0,'2017-10-01 10:00:15',100,3,3),\
(10004,'2017-10-03','深圳',35,0,'2017-10-03 10:20:22',11,6,6);
查看数据的时候发现,数据只剩下6条了,就是因为再key相同的时候,将后面的结果聚合了
是相同key的数据进行自动去重的表模型。在某些多维分析场景下,用户更关注的是如何保证 Key 的唯一性,即如何获得 Primary Key 唯一性约束。因此,引入了 Uniq 的数据模型。该模型本质上是聚合模型的一个特例,也是一种简化的表结构表示方式。
建表示例:
drop table if exists test.user;
CREATE TABLE IF NOT EXISTS test.user
(
-- key列
`user_id` LARGEINT NOT NULL COMMENT "用户 id",
`username` VARCHAR(50) NOT NULL COMMENT "用户昵称",
-- value列
`city` VARCHAR(20) COMMENT "用户所在城市",
`age` SMALLINT COMMENT "用户年龄",
`sex` TINYINT COMMENT "用户性别",
`phone` LARGEINT COMMENT "用户电话",
`address` VARCHAR(500) COMMENT "用户地址",
`register_time` DATETIME COMMENT "用户注册时间"
)
UNIQUE KEY(`user_id`, `username`)
DISTRIBUTED BY HASH(`user_id`) BUCKETS 1;
插入语句
insert into test.user values\
(10000,'zss','北京',18,0,12345678910,'北京朝阳区 ','2017-10-01 07:00:00'),\
(10000,'zss','北京',19,0,12345678910,'北京顺义区 ','2018-10-01 07:00:00'),\
(10000,'lss','北京',20,0,12345678910,'北京海淀区','2017-11-15 06:10:20');
查询结果后发现,相同的数据就会被替换掉
因此:Uniq 模型完全可以用聚合模型中的 REPLACE 方式替代。其内部的实现方式和数据存储方式也完全一样。
就是存明细数据的表模型,既不做聚合也不做去重。在某些多维分析场景下,数据既没有主键,也没有聚合需求。Duplicate 数据模型可以满足这类需求。数据完全按照导入文件中的数据进行存储,不会有任何聚合。即使两行数据完全相同,也都会保留。 而在建表语句中指定的 DUPLICATE KEY,只是用来指明底层数据按照那些列进行排序。
建表语句:
CREATE TABLE IF NOT EXISTS test.log_detail
(
`timestamp` DATETIME NOT NULL COMMENT "日志时间",
`type` INT NOT NULL COMMENT "日志类型",
`error_code` INT COMMENT "错误码",
`error_msg` VARCHAR(1024) COMMENT "错误详细信息",
`op_id` BIGINT COMMENT "负责人 id",
`op_time` DATETIME COMMENT "处理时间"
)
DUPLICATE KEY(`timestamp`, `type`) -- 为啥他还要分key列和value列 排序
DISTRIBUTED BY HASH(`timestamp`) BUCKETS 1;
插入部分数据
insert into test.log_detail values\
('2017-10-01 08:00:05',1,404,'not found page', 101, '2017-10-01 08:00:05'),\
('2017-10-01 08:00:05',1,404,'not found page', 101, '2017-10-01 08:00:05'),\
('2017-10-01 08:00:05',2,404,'not found page', 101, '2017-10-01 08:00:06'),\
('2017-10-01 08:00:06',2,404,'not found page', 101, '2017-10-01 08:00:07');
查询结果后发现,插入的数据全部会被保留,即使两条数据一模一样,也会保留,正常可以操作用户行为日志数据这种
数据模型在建表时就已经确定,且无法修改;所以,选择一个合适的数据模型非常重要。