Doris简介部署架构设计介绍(本人总结干货,最后有实际项目中遇到的问题)

Doris教程

概述:

Apache Doris Palo由百度研发,MPP分析型数据库,10PB的数据集

可以实现:固定历史报表实时数据分析交互式,探索式数据分析

MPP:大规模并行处理

可使用范围:

mysql,oracal这种db产生的数据

后端应用产生的数据

前端,pc或者移动端页面产生的数据

网络事件监听

特点:

1、有自己的一套sql语法,进行大数据分析

2、支持大数据分析引擎,如Flink,Spark等

3、使用ODBC的方式,利用Doris的外表方式将Mysql或es建立映射关系(可直接在doris中操作数据库)

具体可实现功能:

1、最开始的功能是制作报表

2、现在可进行市场营销,金融投资类的分析,广告投放分析等

核心特性:

MPP架构、秒级查询、标准SQL语言兼容Mysql的协议、向量化执行器(高版本添加)、聚合表技术、Rollup可以获取更加粗粒度的结果、三高性能、运维简单

架构:

两种角色,两种进程(这种模式相当于前后端的意思)

大致流程:

fe接收解析调度,be计算结果返回给fe,fe展示给用户

基本架构:

FE(基于Java):存储、维护集群元数据;负责接收、解析查询请求,规划查询计划,调度查询执行,返回查询结果。主要有三个角色:

LeaderFollower:主要是用来达到元数据的高可用,保证单节点宕机的情况下,元数据能够实时地在线恢复,而不影响整个服务。

Observer:用来扩展查询节点,同时起到元数据备份的作用。如果在发现集群压力非常大的情况下,需要去扩展整个查询的能力,那么可以加 observer 的节点。observer 不参与任何的写入,只参与读取。

BE(基于C++):负责物理数据的存储和计算;依据 FE 生成的物理计划,分布式地执行查询。数据的可靠性由 BE 保证,BE 会对整个数据存储多副本或者是三副本。副本数可根据需求动态调整。

MySQL Client:Doris 借助 MySQL 协议,用户使用任意 MySQL 的 ODBC/JDBC 以及 MySQL 的客户端,都可以直接访问 Doris。

Broker:主要用于支持 Doris 读写远端存储上的文件和目录。(如:阿里云的oss之类的)

完全不依赖于外部组件

默认端口

实例名称端口名称默认端口通讯方向说明
BEbe_prot9060FE-->BEBE 上 thrift server 的端口 用于接收来自 FE 的请求
BEwebserver_port8040BE<-->FEBE 上的 http server 端口
BEheartbeat_service_port9050FE-->BEBE 上心跳服务端口 用于接收来自 FE 的心跳
BEbrpc_prot*8060FE<-->BE BE<-->BEBE 上的 brpc 端口 用于 BE 之间通信
FEhttp_port8030FE<-->FE 用户<--> FEFE 上的 http_server 端口
FErpc_port9020BE-->FE FE<-->FEFE 上 thirt server 端口号
FEquery_port9030用户<--> FEFE 上的 mysql server 端口
FEedit_log_port9010FE<-->FEFE 上 bdbje 之间通信用的端口
Brokerbroker_ipc_port8000FE-->BROKER BE-->BROKERBroker 上的 thrift server 用于接收请求

安装

docker安装(官方推荐)

直接编译

安装前系统要求
系统要求
Linux版本
Centos7.1及以上
Ubuntu16.04及以上
软件要求
软件版本
Java1.8及以上
GCC4.8.2及以上
开发及测试环境硬件配置需求
模块CPU内存磁盘网络实例数量
Frontend(FE)8核+8GB+SSD 或 SATA,10GB+ *千兆网卡1
Backend(BE)8核+16GB+SSD 或 SATA,50GB+ *千兆网卡1-3 *
生产环境硬件配置需求
模块CPU内存磁盘网络实例数量(最低要求)
Frontend16核+64GB+SSD 或 RAID 卡,100GB+ *万兆网卡1-5 *
Backend16核+64GB+SSD 或 SATA,100G+ *万兆网卡10-100 *
操作系统环境要求
#1.打开文件
vim /etc/security/limits.conf 
#2.在文件最后添加下面几行信息(注意* 也要复制进去)
​
* soft nofile 65536
* hard nofile 65536 
* soft nproc 65536
* hard nproc 65536
​
ulimit -n 65536 临时生效
​
#修改完文件后需要重新启动虚拟机
#重启永久生效,也可以用 。
​
​
#如果不修改这个句柄数大于等于60000,回头启动doris的be节点的时候就会报如下的错
#如果报错:Please set the maximum number of open file descriptors to be 65536 using 'ulimit -n 65536'.
代表句柄数没有生效,需要临时设置或者重启电脑
​
​
#第一次启动的时候可能会报错
Please set vm.max_map_count to be 2000000 under root using 'sysctl -w vm.max_map_count=2000000'.
#解决方案:
#命令行输入:
sysctl -w vm.max_map_count=2000000
设置文件包含限制一个进程可以拥有的VMA(虚拟内存区域)的数量
#临时生效:
sysctl -w vm.max_map_count=2000000
​
#永久剩下
vim /etc/sysctl.conf
#在文件最后一行添加
vm.max_map_count=2000000
​
#让他永久生效
sysctl -p
​
#检查是否生效
sysctl -a|grep vm.max_map_count
时钟同步(云服务器一般无需同步时间,多机部署需做此操作

Doris 的元数据要求时间精度要小于5000ms,所以所有集群所有机器要进行时钟同步,避免因为时钟问题引发的元数据不一致导致服务出现异常。

#如何时间同步??
首先安装 ntpdate   
# ntpdate是一个向互联网上的时间服务器进行时间同步的软件
yum install ntpdate -y
#然后开始三台机器自己同步时间
ntpdate ntp.sjtu.edu.cn
​
美国标准技术院时间服务器:time.nist.gov(192.43.244.18)
上海交通大学网络中心NTP服务器地址:ntp.sjtu.edu.cn(202.120.2.101)
中国国家授时中心服务器地址:cn.pool.ntp.org(210.72.145.44)
​
# 将当前时间写入bios,这样才能永久生效不变,不然reboot后还会恢复到原来的时间
clock -w 
关闭交换分区(swap)

交换分区是linux用来当做虚拟内存用的磁盘分区;

linux可以把一块磁盘分区当做内存来使用(虚拟内存、交换分区);

Linux使用交换分区会给Doris带来很严重的性能问题,建议在安装之前禁用交换分区;

#1、查看 Linux 当前 Swap 分区
​
free -m
#2、关闭 Swap 分区
​
swapoff -a
​
free -m
              total        used        free      shared  buff/cache   available
Mem:           5840         997        4176           9         666        4604
Swap:          6015           0        6015
​
swapoff -a
​
3.验证是否关闭成功
free -m 
              total        used        free      shared  buff/cache   available
Mem:           5840         933        4235           9         671        4667
Swap:             0           0           0
注意事项:
  • FE 的磁盘空间主要用于存储元数据,包括日志和 image。通常从几百 MB 到几个GB 不等。

  • BE 的磁盘空间主要用于存放用户数据,总磁盘空间按用户总数据量* 3(3 副本)计算,然后再预留额外 40%的空间用作后台 compaction 以及一些中间数据的存放。

  • 一台机器上可以部署多个 BE 实例,但是只能部署一个 FE。如果需要 3 副本数 据,那么至少需要 3 台机器各部署一个 BE 实例(而不是 1 台机器部署 3 个 BE 实例)。多 个 FE 所在服务器的时钟必须保持一致(允许最多 5 秒的时钟偏差)

  • 测试环境也可以仅适用一个 BE 进行测试。实际生产环境,BE 实例数量直接决定了整体查询延迟。

  • 所有部署节点关闭 Swap。

  • FE 节点数据至少为 1(1 个 Follower)。当部署 1 个 Follower 和 1 个 Observer 时,可以实现读高可用。当部署 3 个 Follower 时,可以实现读写高可用(HA)。

  • Follower 的数量必须为奇数,Observer 数量随意。

  • 当集群可用性要求很高时(比如提供在线业务),可以部署 3 个Follower 和 1-3 个 Observer。如果是离线业务,建议部署 1 个 Follower 和 1-3 个 Observer。

  • Broker 是用于访问外部数据源(如 HDFS)的进程。通常,在每台机器上部署一个 broker 实例即可。

安装FE和BE(老版本是分开下载)
1、去官网下载源码包,官网地址:Apache Doris: Open source data warehouse for real time data analytics - Apache Doris

根据自己的配置选择性点击下载(avx2指令集和CPU有关,为提升效率,详情请自行查阅)

当然你也可以选择历史版本下载

2、上传到linux
3、解压
官网下载下来的是gz结尾的,所以解压需要用
tar -zxvf xxx.tar.gz -C 路径名
4、修改FE配置文件
去自己的路劲中找到fe.conf文件
vim /opt/doris/fe/conf/fe.conf(`自己安装的路径`)
#配置文件中指定元数据路径
`注意这个文件夹要自己创建`
meta_dir = /opt/doris/doris-meta(`自己想要存放的位置`)
#修改绑定 ip(每台机器修改成自己的 ip) 
priority_networks = `自己的ip地址(云服务器填写内网地址)`/24 
注意事项:
  • 生产环境强烈建议单独指定目录不要放在 Doris 安装目录下,最好是单独的磁盘(如果有SSD最好)

  • 如果机器有多个 ip, 比如内网外网, 虚拟机 docker 等, 需要进行 ip 绑定,才能正确识别。

  • JAVA_OPTS 默认 java 最大堆内存为 4GB,建议生产环境调整至 8G 以上。

5、修改BE配置文件
#去自己的路劲中找到be.conf文件
vim /opt/doris/be/conf/be.conf(`自己安装的路径`)
#配置文件中指定数据存放路径
`注意这个文件夹要自己创建`
storage_root_path = /opt/module/apache-doris-0.15.0/doris•storage1;/opt/module/apache-doris-0.15.0/doris-storage2(`自己所要存放的所有位置,可以为多个,用;隔开,最后一个不要加`)
#修改绑定 ip(每台机器修改成自己的 ip) 
priority_networks = `自己的ip地址(云服务器填写内网地址)`/24 
6、启动FE和BE
#进入到fe的bin目录下执行
./start_fe.sh(`前台启动,第一次推荐前台启动,可能会报错`)
./start_fe.sh --daemon(`后台启动`)
#进入be的bin目录下执行
./start_be.sh(`前台启动,第一次推荐前台启动,可能会报错`)
./start_be.sh --daemon(`后台启动`)
#第一次启动的时候可能会报错
Please set vm.max_map_count to be 2000000 under root using 'sysctl -w vm.max_map_count=2000000'.
#解决方案:
命令行输入:sysctl -w vm.max_map_count=2000000
​
如果报错:Please set the maximum number of open file descriptors to be 65536 using 'ulimit -n 65536'.
解决方案:`临时修改,永久修改看上边`
命令行输入:ulimit -n 65536
7、查看FE和BE是否开启
#FE是否启动
#命令行输入
jps
#显示含有下面信息则证明FE启动成功
87965 PaloFe
(`数字为进程号,无需关心是否一致`)
#BE是否启动
#命令行输入
jps
或
netstat -nltp |grep be
#jps命令显示含有下面信息则证明BE启动成功
88553 DorisBE
(`数字为进程号,无需关心是否一致`)

如果命令netstat -nltp |grep be,显示以下界面

8、如没有启动查询日志(可选)
#进入FE日志文件夹
cd /opt/doris/fe/log/
#错误日志一般名为
fe.warn.log
#进入BE日志文件夹
cd /opt/doris/be/log/
#错误日志一般名为
be.warn.log
注意事项:
  • storage_root_path 默认在 be/storage 下,需要手动创建该目录。多个路径之间使用英文状态的分号;分隔(最后一个目录后不要加)。

  • 可以通过路径区别存储目录的介质,HDD 或 SSD。可以添加容量限制在每个路径的末尾,通过英文状态逗号,隔开,如storage_root_path=/home/disk1/doris.HDD,50;/home/disk2/doris.SSD,10;/home/disk2/doris

  • 说明:

  • /home/disk1/doris.HDD,50,表示存储限制为 50GB,HDD;

  • /home/disk2/doris.SSD,10,存储限制为 10GB,SSD;

  • /home/disk2/doris,存储限制为磁盘最大容量,默认为 HDD

  • 如果机器有多个 IP, 比如内网外网, 虚拟机 docker 等, 需要进行 IP 绑定,才能正确识别。

因为FE和BE两个都是单独的个体,所以他俩相互间还不认识,就需要我们通过mysql的客户端将他们建立起联系

如果没有装mysql的家伙,记得先装mysql(安装教程自行搜索)

使用 MySQL Client 连接 FE

连接FE
#命令行输入
mysql -h 127.0.0.1 -P 9030 -uroot -p
(`填写fe节点的IP,默认无密码,如果fe在本机,不写密码,也可登录,必须填写127.0.0.1,如果填写内网地址会报错`)
(`注意P的大小写`)
#默认root无密码,通过命令行修改root密码
SET PASSWORD FOR 'root' = PASSWORD('******');
#默认admin无密码,通过命令行修改admin密码(admin为http方式登录的用户)
SET PASSWORD FOR 'admin' = PASSWORD('******');
查询FE状态
#以表格方式查看
SHOW PROC '/frontends';
#以文本行方式查看
SHOW PROC '/frontends' \G;(`推荐方式`)
表格方式演示

文本行方式演示(注:如果FOLLOWER的IsMaster为true则证明此FOLLOWER是Leader)

添加BE节点
#命令行输入(可多个)
ALTER SYSTEM ADD BACKEND "192.168.1.1:9050";(`填写be节点的IP,如果为本机,云服务器必须填写内网地址,否则无效`)
ALTER SYSTEM ADD BACKEND "192.168.1.2:9050";
ALTER SYSTEM ADD BACKEND "192.168.1.3:9050";
删除BE节点
#命令行输入
ALTER SYSTEM DECOMMISSION BACKEND "192.168.1.1:9050";
查看BE节点状态
#以表格方式查看
SHOW PROC '/backends';
#以文本行方式查看
show proc '/backends' \G;(`推荐方式`)
表格方式演示

文本行方式演示(注:Alive 为 true 表示该 BE 节点存活)

也可通过Http方式链接FE

在浏览器中输入地址(输入自己IP地址):
http://192.168.1.1:8030/
默认用户名为:
admin(老版本默认用户名可能为:root和admin都可)
默认无密码

通过Http界面执行SQL

如果FE已经连接BE,可通过以下方式查看

通过Http页面查看日志

部署 FS_Broker(可选)

基本介绍

Broker 以插件的形式,独立于 Doris 部署。如果需要从第三方存储系统导入数据,需要部署相应的 Broker,默认提供了读取 HDFS、百度云 BOS 及 Amazon S3 的 fs_broker。

fs_broker 是无状态的,建议每一个 FE 和 BE 节点都部署一个 Broker。

1、编译 FS_BROKER 并拷贝文件

(1)进入源码目录下的 fs_brokers 目录,使用 sh build.sh 进行编译

(2)拷贝源码 fs_broker 的 output 目录下的相应Broker目录到需要部署的所有节点上,改名为: apache_hdfs_broker。建议和 BE 或者 FE 目录保持同级。

2、启动 Broker
#进入到所安装的broker目录
如:
cd /opt/doris/apache_hdfs_broker/bin
./start_broker.sh --daemon
3、添加 Broker

要让 Doris 的 FE 和 BE 知道 Broker 在哪些节点上,通过 sql 命令添加Broker节点列表。

#使用mysql-client连接启动的 FE,执行以下命令: 
mysql -h 127.0.0.1 -P 9030 -uroot -p
(`填写fe节点的IP,默认无密码,如果fe在本机,不写密码,也可登录,必须填写127.0.0.1,如果填写内网地址会报错`)
(`注意P的大小写`)
ALTER SYSTEM ADD BROKER broker_name"192.168.1.1:8000","192.168.1.2:8000","192.168.1.3:8000"; 
(`其中broker_host为Broker所在节点ip;broker_ipc_port在Broker配置文件中的conf/apache_hdfs_broker.conf`)
4、查看 Broker 状态
#使用 mysql-client 连接任一已启动的 FE,执行以下命令查看 Broker 状态: 
SHOW PROC "/brokers" \G;
注意事项:
  • 在生产环境中,所有实例都应使用守护进程启动,以保证进程退出后,会被自动拉起,如Supervisor(opens new window)。

  • 如需使用守护进程启动,在 0.9.0 及之前版本中,需要修改各个 start_xx.sh 脚本,去掉最后的 & 符号。

  • 从 0.10.0 版本开始,直接调用sh start_xx.sh启动即可。

数据表设计

1、字段类型
字段字节范围
TINYINT1 字节范围:-2^7 + 1 ~ 2^7 - 1
SMALLINT2 字节范围:-2^15 + 1 ~ 2^15 - 1
INT4 字节范围:-2^31 + 1 ~ 2^31 - 1
BIGINT8 字节范围:-2^63 + 1 ~ 2^63 - 1
LARGEINT16 字节范围:-2^127 + 1 ~ 2^127 - 1
FLOAT4 字节支持科学计数法
DOUBLE12 字节支持科学计数法
DECIMAL[(precision, scale)]16 字节保证精度的小数类型。默认是DECIMAL(10, 0) ,precision: 1 ~ 27 ,scale: 0 ~ 9,其中整数部分为 1 ~ 18,不支持科学计数法
DATE3 字节范围:0000-01-01 ~ 9999-12-31
DATETIME8 字节范围: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
HLL1~16385 个字节hll 列类型,不需要指定长度和默认值,长度根据数据的聚合程度系统内控制,并且 HLL 列只能通过 配套的hll_union_agg、Hll_cardinality、hll_hash 进行查询或使用
BITMAPbitmap 列类型,不需要指定长度和默认值。表示整型的集合,元素最大支持到 2^64 - 1
STRING变长字符串,0.15 版本支持,最大支持 2147483643 字节(2GB-4),长度还受 be 配置string_type_soft_limit, 实际能存储的最大长度取两者最小值。只能用在 value 列,不能用在 key列和分区、分桶列
2、创建用户和数据库
(1)创建test用户
mysql -h 192.168.1.1 -P 9030 -uroot -p()
(`填写fe节点的IP,默认无密码,如果fe在本机,不写密码,也可登录,必须填写127.0.0.1,如果填写内网地址会报错`)
(`注意P的大小写`)
create user 'test' identified by 'test';
(2)创建数据库
create database test_db;
(3)用户授权
grant all on test_db to test;
3、表的基本概念

在 Doris 中,数据都以关系表(Table)的形式进行逻辑上的描述。

(1)Row & Column

一张表包括行(Row)和列(Column)。Row 即用户的一行数据。Column 用于描述一行数据中不同的字段。

  • 在默认的数据模型中,Column 只分为排序列和非排序列。存储引擎会按照排序列对数据进行排序存储,并建立稀疏索引,以便在排序数据上进行快速查找。

  • 而在聚合模型中,Column可以分为两大类:Key 和 Value。从业务角度看,Key和Value 可以分别对应维度列和指标列。从聚合模型的角度来说,Key 列相同的行,会聚合成一行。其中Value列的聚合方式由用户在建表时指定。

(2)Partition & Tablet

在 Doris 的存储引擎中,用户数据首先被划分成若干个分区(Partition),划分的规则通常是按照用户指定的分区列进行范围划分,比如按时间划分。而在每个分区内,数据被进一步的按照 Hash 的方式分桶,分桶的规则是要找用户指定的分桶列的值进行 Hash 后分桶。

每个分桶就是一个数据分片(Tablet),也是数据划分的最小逻辑单元。

Doris 支持两层的数据划分。第一层是 Partition,支持 Range 和 List 的划分方式。第二层是 Bucket(Tablet),仅支持 Hash 的划分方式。

也可以仅使用一层分区。使用一层分区时,只支持 Bucket 划分。

partition(分区):是在逻辑上将一张表按行(横向)划分

  • Partition 列可以指定一列或多列,在聚合模型中,分区列必须为 KEY 列。

  • 不论分区列是什么类型,在写分区值时,都需要加双引号。

  • 分区数量理论上没有上限。

  • 当不使用 Partition 建表时,系统会自动生成一个和表名同名的,全值范围的 Partition。该 Partition 对用户不可见,并且不可删改。

  • 创建分区时不可添加范围重叠的分区。

  • Partition可以视为是逻辑上最小的管理单元。数据的导入与删除,都可以或仅能针对一个 Partition 进行

Range 分区
--range分区创建语法
--Range Partition
drop table if exists test.expamle_range_tb;
CREATE TABLE IF NOT EXISTS test.expamle_range_tb1
(
    `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 2;

  • 分区列通常为时间列,以方便的管理新旧数据。

  • Partition 支持通过 VALUES LESS THAN (...) 仅指定上界,系统会将前一个分区的上界作为该分区的下界,生成一个左闭右开的区间。同时,也支持通过 VALUES [...) 指定上下界,生成一个左闭右开的区间。

  • 通过 VALUES [...) 同时指定上下界比较容易理解。这里举例说明,当使用 VALUES LESS THAN (...) 语句进行分区的增删操作时,分区范围的变化情况:

--如上 expamle_range_tbl 得建表语句中可以看到,当建表完成后,会自动生成如下3个分区:
--查看表中分区得情况
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)

注意到 p201702 和 p201705 的分区范围并没有发生变化,而这两个分区之间,出现了一个空洞:[2017-03-01, 2017-04-01)。即如果导入的数据范围在这个空洞范围内,是无法导入的。

继续删除分区 p201702,分区结果如下:

p201701: [MIN_VALUE,  2017-02-01)
p201705: [2017-04-01, 2017-06-01)
​
空洞范围变为:[2017-02-01, 2017-04-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)

现在删除分区 p201701,并添加分区 p201612 VALUES LESS THAN ("2017-01-01"),分区结果如下:

p201612:    [MIN_VALUE,  2017-01-01)
p201702new: [2017-02-01, 2017-03-01)
p201705:    [2017-04-01, 2017-06-01) 
​
即出现了一个新的空洞:[2017-01-01, 2017-02-01)

综上,分区的删除不会改变已存在分区的范围。删除分区可能出现空洞。通过 VALUES LESS THAN 语句增加分区时,分区的下界紧接上一个分区的上界。

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)) 

注意,最后一个分区用户缺失,只指定了 date 列的分区值,所以 id 列的分区值会默认填充 MIN_VALUE。当用户插入数据时,分区列值会按照顺序依次比较,最终得到对应的分区。举例如下:

List 分区
  • 分区列支持 BOOLEAN, TINYINT, SMALLINT, INT, BIGINT, LARGEINT, DATE, DATETIME, CHAR, VARCHAR 数据类型,分区值为枚举值。只有当数据为目标分区枚举值其中之一时,才可以命中分区。

  • Partition 支持通过 VALUES IN (...) 来指定每个分区包含的枚举值。

  • 下面通过示例说明,进行分区的增删操作时,分区的变化。

--List分区创建语法
--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"
);

如上 example_list_tbl 示例,当建表完成后,会自动生成如下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")

当我们删除分区 p_jp,分区结果如下:

p_cn: ("Beijing", "Shanghai", "Hong Kong")
p_usa: ("New York", "San Francisco")
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"))
)

在以上示例中,我们指定 id(INT 类型) 和 city(VARCHAR 类型) 作为分区列。以上示例最终得到的分区如下:

* p1_city: [("1", "Beijing"), ("1", "Shanghai")]
* p2_city: [("2", "Beijing"), ("2", "Shanghai")]
* p3_city: [("3", "Beijing"), ("3", "Shanghai")]

当用户插入数据时,分区列值会按照顺序依次比较,最终得到对应的分区。举例如下:

* 数据  --->  分区
* 1, Beijing     ---> p1_city
* 1, Shanghai    ---> p1_city
* 2, Shanghai    ---> p2_city
* 3, Beijing     ---> p3_city
* 1, Tianjin     ---> 无法导入
* 4, Beijing     ---> 无法导入

tablet(又叫bucket,分桶):在物理上对一个分区再按行(横向)划分

  • Tablet之间的数据是没有交集的,独立存储的。Tablet 也是数据移动、复制等操作的最小物理存储单元。

  • 如果使用了 Partition,则 DISTRIBUTED ... 语句描述的是数据在各个分区内的划分规则。如果不使用 Partition,则描述的是对整个表的数据的划分规则。

  • 分桶列可以是多列,但必须为 Key 列。分桶列可以和 Partition 列相同或不同。

  • 分桶列的选择,是在 查询吞吐 和 查询并发之间的一种权衡:

    • 如果选择多个分桶列,则数据分布更均匀。如果一个查询条件不包含所有分桶列的等值条件,那么该查询会触发所有分桶同时扫描,这样查询的吞吐会增加,单个查询的延迟随之降低。这个方式适合高吞吐低并发的查询场景。

    • 如果仅选择一个或少数分桶列,则对应的点查询可以仅触发一个分桶扫描。此时,当多个点查询并发时,这些查询有较大的概率分别触发不同的分桶扫描,各个查询之间的IO影响较小(尤其当不同桶分布在不同磁盘上时),所以这种方式适合高并发的点查询场景。

  • 分桶的数量理论上没有上限

关于 Partition 和 Bucket的数量和数据量的建议

  1. 一个表的 Tablet 总数量等于 (Partition num * Bucket num)

  2. 一个表的 Tablet 数量,在不考虑扩容的情况下,推荐略多于整个集群的磁盘数量。 数量原则

  3. 单个Tablet的数据量理论上没有上下界,但建议在1G - 10G的范围内。如果单个Tablet数据量过小,则数据的聚合效果不佳,且元数据管理压力大。如果数据量过大,则不利于副本的迁移、补齐,且会增加 Schema Change 或者 Rollup 操作失败重试的代价(这些操作失败重试的粒度是Tablet)。分桶应该控制桶内数据量 ,不易过大或者过小

  4. 当 Tablet 的数据量原则和数量原则冲突时,建议优先考虑数据量原则

  5. 在建表时,每个分区的 Bucket 数量统一指定。但是在动态增加分区时(ADD PARTITION),可以单独指定新分区的 Bucket 数量。可以利用这个功能方便的应对数据缩小或膨胀。

  6. 一个 Partition 的 Bucket 数量一旦指定,不可更改。所以在确定 Bucket 数量时,需要预先考虑集群扩容的情况。比如当前只有 3 台 host,每台 host 有 1 块盘。如果 Bucket 的数量只设置为 3 或更小,那么后期即使再增加机器,也不能提高并发度。

4、索引

索引用于帮助快速过滤或查找数据。

目前 Doris 主要支持两类索引:

  • 内建的智能索引:包括前缀索引和 ZoneMap 索引。 doris自己给我们创建的 根据什么创建

  • 用户创建的二级索引:包括 Bloom Filter 索引 和 Bitmap倒排索引。

其中 ZoneMap 索引是在列存格式上,对每一列自动维护的索引信息,包括 Min/Max,Null 值个数等等。这种索引对用户透明。

(1)前缀索引

建表时会自动为指定的key创建前缀索引

doris中,对于前缀索引有如下约束:

  • 他的索引键最大长度是36个字节

  • 当他遇到了varchar数据类型的时候,即使没有超过36个字节,也会自动截断

所以在建表时,正确的选择列顺序,能够极大地提高查询效率

(2)Bloom 索引

用户可以通过创建 bitmap index 加速查询

创建索
create index 索引名称 on 表名(给什么字段创建bitmap索引) using bitmap COMMENT '********';
​
create index user_id_bitmap on sale_detail_bloom(sku_id) USING BITMAP COMMENT '使用user_id创建的bitmap索引';
查看索引
SHOW INDEX FROM example_db.table_name;
删除索引
DROP INDEX [IF EXISTS] index_name ON [db_name.]table_name;
注意事项:
  • bitmap 索引仅在单列上创建。

  • bitmap 索引能够应用在 Duplicate、Uniq 数据模型的所有列和 Aggregate模型的key列上。

  • bitmap 索引支持的数据类型如下:(老版本只支持bitmap类型)

    • TINYINT,SMALLINT,INT,BIGINT,CHAR,VARCHAR,DATE,DATETIME,LARGEINT,DECIMAL,BOOL

  • bitmap索引仅在 Segment V2 下生效(Segment V2是升级版本的文件格式)。当创建 index 时,表的存储格式将默认转换为 V2 格式

(3)Bitmap Filter 索引

Doris的BloomFilter索引是从通过建表的时候指定,或者通过表的ALTER操作来完成。

建表时指定 BloomFilter 索引
PROPERTIES (
"bloom_filter_columns"="name,age,uid"
)
alter修改表的时候指定
ALTER TABLE sale_detail_bloom SET ("bloom_filter_columns" = "k1,k3");
​
ALTER TABLE sale_detail_bloom SET ("bloom_filter_columns" = "k1,k4");
​
ALTER TABLE sale_detail_bloom SET ("bloom_filter_columns" = "");
建表示例:
CREATE TABLE IF NOT EXISTS sale_detail_bloom  (
    sale_date date NOT NULL COMMENT "销售时间",
    customer_id int NOT NULL COMMENT "客户编号",
    saler_id int NOT NULL COMMENT "销售员",
    sku_id int NOT NULL COMMENT "商品编号",
    category_id int NOT NULL COMMENT "商品分类",
    sale_count int NOT NULL COMMENT "销售数量",
    sale_price DECIMAL(12,2) NOT NULL COMMENT "单价",
    sale_amt DECIMAL(20,2)  COMMENT "销售总金额"
)
Duplicate  KEY(sale_date, customer_id,saler_id,sku_id,category_id)
PARTITION BY RANGE(sale_date)
(
PARTITION P_202111 VALUES [('2021-11-01'), ('2021-12-01'))
)
DISTRIBUTED BY HASH(saler_id) BUCKETS 1
properties(
"bloom_filter_columns" = "customer_id,saler_id"
);
查看BloomFilter索引:
SHOW CREATE TABLE sale_detail_bloom \G;
Doris BloomFilter适用场景:

满足以下几个条件时可以考虑对某列建立Bloom Filter 索引:

  1. BloomFilter是在无法利用前缀索引的查询场景中,来加快查询速度的。

  2. 查询会根据该列高频过滤,而且查询条件大多是 in 和 = 过滤。

  3. 不同于Bitmap, BloomFilter适用于高基数列。比如UserID。因为如果创建在低基数的列上,比如 “性别” 列,则每个Block几乎都会包含所有取值,导致BloomFilter索引失去意义。字段随机

注意事项:
  • 不支持对Tinyint、Float、Double 类型的列建Bloom Filter索引。

  • Bloom Filter索引只对 in 和 = 过滤查询有加速效果。

doris数据库使用注意事项

sql中使用with as 表名()临时表时,表名必须为小写可使用下划线(_),有的版本可能不支持大小写混合

用pagehelper插件分页时,必须加排序,某些版本可能存在翻页条件没问题,但数据无变化

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孤雾,

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值