一、背景
StarRocks(以下简称SR)是新一代极速全场景 MPP 数据库,可以满足多种分析需求,包括 OLAP 多维分析、定制报表、实时数据分析;伴随公司 WOS 升级战略,BI 在 WOS 系统中的选型 SR 作为数据分析层数据库;SR 应用实践过程中随迁移 WOS 的商户越来越来多,SR 内数据随之增大,逐渐暴露出来一些内存不足问题,主要为以下问题造成:
主键模型表常驻内存持续增大,最高占用可用内存的16%。
tablet过多,270张表160W+个tablets,小于100M的约占90%。
二、问题分析
2.1 第一个问题主键模型常驻内存较大,查询官方对主键模型的介绍。
主键模型适用于主键占用空间相对可控的场景。主键模型会将主键索引加载至内存中,所以相对于其他模型,主键模型对内存的要求比较高
主键模型数据有冷热特征:即最近几天的热数据才经常被修改,老的冷数据很少被修改。例如,MySQL 订单表实时同步到 SR 中提供分析查询。其中,数据按天分区,对订单的修改集中在最近几天新创建的订单,老的订单完成后就不再更新,因此导入时其主键索引就不会加载,也就不会占用内存,内存中仅会加载最近几天的索引。
经查询分析库中主键模型主要应用在实时分析中,实时分析主要为当天数据,数据量不会太大,根据官方描述主键模型数据有冷热特征,对实时分析 DB 的表进行Show data 查询:发现三张表数据量总量为 17GB 左右,查询三张表的 DDL 发现三张表均未分区,因此三张表的数据会全部加载到内存,最终造成了主键模型常驻内存较大。
2.2、Tablet过多,且单个 Ttablet 数据量较小
官方对 Tablet 定义:在同⼀分区内,分桶键哈希值相同的数据形成 Tablet,Tablet 以多副本冗余的形式存储,是数据均衡和恢复的最⼩单位。Tablet 的副本由⼀个单独的本地存储引擎管理,数据导⼊和查询最终都下沉到所涉及的 Tablet 副本上。
官方建议:单个分区原始数据量建议不要超过 100 GB,每个 Tablet 数据文件大小在 100 MB 至 1 GB 左右。
执行如下语句:
SHOW DATA;
SHOW DATA; 分析库中表,存在以下问题:
大部分表是按日分区,3个副本,3个分桶;目前一些表数据量很小,但是ReplicaCount(分片数)很多,算下来每个分片数据量很少。
以某一表 ads_xxxx_d 为例,ReplicaCount=BUCKETS 3 * replication_num = 3 * dd(2019-12-20 到 2022-07-08)分区数量=5598 个tablet,算下来每个 Tablet 数据量 17Kb 左右,与官方建议相差巨大,Tablet 过多浪费大量元数据。
目前我们大部分使用更新模型,Tablet 过多,多次导入数据,数据版本较多,compaction 速度较慢,导致表的存储量大于实际存储量很多。
三、优化方案
3.1、第一个问题主键模型常驻内存较大
优化方案:3张表修改为分区表,且增加分区生命周期,只保持近10天数据。
优化执行步骤如下:
--第一步停止实时任务
--第二步新建bak表
CREATE TABLE realtime_sr_db.`ads_xxx_d_bak` (
`id` bigint(20) NOT NULL COMMENT "id",
`dd` date NOT NULL COMMENT "日期",
) ENGINE=OLAP
PRIMARY KEY(`id`,`dd`)
COMMENT "实时xxx明细"
PARTITION BY RANGE(`dd`)
( START ('2022-07-12') END ('2022-08-25') EVERY (INTERVAL 1 DAY) )
DISTRIBUTED BY HASH(`id`) BUCKETS 3
PROPERTIES (
"replication_num" = "3",
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "day",
"dynamic_partition.time_zone" = "Asia/Shanghai",
"dynamic_partition.start" = "-10",
"dynamic_partition.end" = "2",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "3",
"in_memory" = "false",
"storage_format" = "DEFAULT"
);
--第三步迁移数据
INSERT INTO realtime_sr_db.ads_xxx_d_bak SELECT * FROM realtime_sr_db.ads_xxx_d where topicdate>'2022-08-08';
--第四步更换表名称
ALTER TABLE ads_xxx_d RENAME ads_xxx_d_bak_1;
ALTER TABLE ads_xxx_d_bak RENAME ads_xxx_d;
--第五步删除表
DROP TABLE ads_xxx_d_bak_1;
--第六步 开启实时任务
3.2、第二个问题:tablet过多,且单个tablet数据量较小
优化方案:梳理出 132 张需要治理的表,分三批进行优化,第一批治理数据量小于1GB 的 53 张表,第二批治理数据量小于 20G 的表,第三批治理 20G 以上的表;对每一批表分别进行评估,根据数据量将分区修改为按周、按月、按年分区。
评估规则:
1、查看分区数据占用详情
执行如下语句,查看 ads_xxx_dwm 表中分区情况:
SHOW PARTITIONS FROM ads_xxx_dwm;
根据分区详情数据,该表目前是按天分区,每分区当数据极小分桶后,每个桶数据量远远小于官方建议的100M。
2、分区合并规则
根据分区数据量判断,例如下图 DDL 内,2021 年之前的历史数据量,按年分区,才会满足 Tablet 大于 100MB 的条件,因此可以把 2021 年之前的数据按年分区;2021-01-01 到 2022-06-01 期间的数据按照月分区满足 tablet 大于 100MB 的条件,可以将这部分数据按照月分区;以此类推,WEEK,DAY 分区时间段都可按照数据量判断。
优化执行步骤如下:
--第一步新建新结构bak表
CREATE TABLE `ads_xxx_d_bak` (
`id` bigint(20) NULL COMMENT "ID",
`dd` date NULL COMMENT "数据日期",
) ENGINE=OLAP
UNIQUE KEY(`id`, `dd`)
COMMENT "xxx"
PARTITION BY RANGE(`dd`)
( START ('2021-01-01') END ('2023-01-01') EVERY (INTERVAL 1 YEAR),
START ('2023-01-01') END ('2023-02-01') EVERY (INTERVAL 1 MONTH)
)
DISTRIBUTED BY HASH(`id` ) BUCKETS 3
PROPERTIES (
"replication_num" = "3",
"dynamic_partition.enable" = "true",
"dynamic_partition.time_unit" = "MONTH",
"dynamic_partition.time_zone" = "Asia/Shanghai",
"dynamic_partition.start" = "-2147483648",
"dynamic_partition.end" = "1",
"dynamic_partition.prefix" = "p",
"dynamic_partition.buckets" = "3",
"in_memory" = "false",
"storage_format" = "DEFAULT"
);
--第二步迁移数据到bak表
INSERT INTO tmp.ads_xxx_d_bak SELECT * FROM tmp.ads_xxx_d;
--第三步更换表名称
ALTER TABLE ads_xxx_d RENAME ads_xxx_d_bak_1;
ALTER TABLE ads_xxx_d_bak RENAME ads_xxx_d;
--第四步删除表
DROP TABLE ads_xxx_d_bak_1;
4.2、Tablet过多优化:
经过三轮分区合并,Tablet 数量由治理前的 160W+下降为 30W+,大约下降了81%,BE meta Men内存由原来的平均每台 10.9GB 降为平均每台 8.9GB,下降18.34% 左右。
优化后FE及BE内存变化:
FE jvm heap:
FE 的 JVM 堆使用情况,之前最高为 18G,优化后峰值在 4G。
BE Mem :BE的使用内存使用情况,集群层面,常驻内存下降55g。
优化结论总结:
经过4轮优化,BE 的使用内存集群层面,常驻内存下降 55GB,FE 节点 JVM 堆内存占用下降了77.77%,Tablet 数量大约下降了 81%,集群健康度有所提高。