在建 Doris表时,如何合理确定 Partition 和 Bucket 的粒度?
在 Apache Doris 中,Partition(分区) 和 Bucket(分桶) 的设计直接决定了集群的查询性能、并发能力以及系统的稳定性(如 FE 的元数据压力、BE 的 Compaction 压力)。
Doris 的数据组织结构为:Table -> Partition -> Bucket (Tablet)。一个 Bucket 就是一个物理上的 Tablet。
合理确定这两者的粒度,核心原则是:控制单个 Tablet 的物理文件大小,并充分利用集群的分布式计算能力。
以下是详细的设计指南和计算步骤:
一、 Partition(分区)粒度设计
分区是逻辑划分,主要用于数据的生命周期管理和查询时的分区裁剪(减少扫描数据量)。
1. 分区键的选择
- 绝对首选:时间字段(如
create_time,log_date)。按天、周、月进行分区。 - 特殊场景: 如果是极其庞大的多租户系统,且经常按租户删除数据,可以将时间+租户ID结合作为复合分区(通常不建议,除非单租户数据量极大)。
2. 分区粒度(时间范围)的确定
决定按“天”、“周”还是“月”分区,主要取决于数据量:
- 单分区原始数据量建议在 1GB ~ 100GB 之间。
- 每天数据量 < 1GB: 建议按 月 分区。
- 每天数据量 1GB ~ 10GB: 建议按 周 或 天 分区。
- 每天数据量 > 10GB: 建议按 天 分区。
- 每天数据量 > 500GB: 建议按 天 分区,甚至按 小时 分区(结合大集群)。
3. 注意事项与避坑
- 避免分区过多: FE 会把所有元数据加载到内存中。单表分区数建议控制在 数千个以内。不要盲目按小时分区,否则会导致元数据爆炸。
- 生命周期管理: 结合动态分区(Dynamic Partition)功能,自动创建新分区,自动
DROP老分区,避免磁盘打满。
二、 Bucket(分桶)粒度设计
分桶是物理划分,主要用于解决数据倾斜、提高并发处理能力。分桶数决定了一个分区下的物理 Tablet 数量。
1. 分桶键(Bucket Key)的选择
- 高基数字段: 选择区分度高的数据列(如
user_id,device_id),保证数据通过 Hash 散列后均匀分布,避免数据倾斜。 - 常用于 JOIN / GROUP BY 的字段: 如果按
user_id分桶,查询时包含GROUP BY user_id,可以在本地直接聚合,减少网络 Shuffle。同理,两张表按相同的键分桶,可以实现高效的 Colocate Join。 - 纯明细日志(无 Hash 需求): 在 Doris 2.0+ 中,可以使用 Random 分桶,数据绝对均匀,写入速度最快。
2. 分桶数(Bucket 数量)的确定法则(核心)
确定分桶数有两个黄金法则需要同时满足:
法则一:控制单 Tablet 大小(最重要)
- 建议单个 Tablet 的数据量(压缩后的磁盘物理大小)在 1GB ~ 10GB 之间。
- 千万不要出现几十 MB 的小 Tablet(会导致小文件过多,Compaction 耗死 CPU,FE 元数据 OOM)。
- 千万不要出现上百 GB 的大 Tablet(会导致查询变慢,数据迁移/恢复极慢,容易 OOM)。
法则二:匹配集群的计算资源
- 为了让查询能够调动所有 BE 节点,分桶数最好是 集群 BE 节点总数(或磁盘总数)的倍数。
- 例如:有 10 个 BE 节点,分桶数设为 10、20、30,能保证每个 BE 均匀分摊计算任务。如果只设为 3 个分桶,查询该分区时只有 3 个 BE 在工作,7 个闲置。
三、 实战:手把手计算分桶数量
假设你的集群有 10 台 BE 节点,每台 BE 有 3 块磁盘。
场景 1:中等数据量表
- 预估: 每天增量原始数据 50GB。
- 压缩: Doris 的列存压缩比通常在 1:3 到 1:5。物理数据大约 15GB 左右。
- 分区: 每天 15GB,适合按天分区。
- 分桶计算:
- 按法则一:15GB / 3GB(目标Tablet大小) ≈ 5 个分桶。
- 按法则二:集群有 10 个 BE。如果设为 5 个分桶,查询时一半节点闲置。
- 最终决定: 设置为 10 个分桶。每个 Tablet 大小约为 1.5GB,既在健康范围内,又完美利用了 10 个 BE 节点并发。
场景 2:超小数据量表(维表或小事实表)
- 预估: 每天增量原始数据 100MB。
- 压缩: 物理大小约 30MB。
- 分区: 每天太少,建议按月分区(每月物理大小约 1GB)。
- 分桶计算: 1GB 数据量。为了避免小文件,分桶数绝不能是 10。
- 最终决定: 设置为 1 个分桶。不要为了并发去切碎小表,小表单节点扫即可。
场景 3:海量日志表
- 预估: 每天增量原始数据 2TB。
- 压缩: 物理大小约 500GB。
- 分区: 按天分区(如果查询常限定在几小时内,也可按小时分区)。
- 分桶计算:
- 按法则一:500GB / 5GB(目标大小) = 100 个分桶。
- 按法则二:10个 BE * 3块盘 = 30 个并发度。100 个分桶能很好的分布在这 30 块盘上。
- 最终决定: 设置为 90 或 120 个分桶(30的整数倍),确保各磁盘负载绝对均衡。
四、 高级特性与最佳实践(强烈建议)
1. 开启 Auto Bucket(Doris 1.2.2+ 引入)
如果你觉得手动计算太麻烦,或者每天的数据量波动巨大(大促时 1TB,平时 10GB),强烈建议使用 Auto Bucket 功能。
- 建表时不指定具体数字,直接写
DISTRIBUTED BY HASH(user_id) BUCKETS AUTO。 - Doris 会根据过去数据的写入量,自动推算下一个分区需要多少个分桶。
- 这是目前绝大多数中大型集群的标配。
2. 数据倾斜的终极解决方案
如果业务上必须按 tenant_id 分桶,但其中一个大客户占了 80% 的数据,会导致某个 Tablet 巨大,查询和 Compaction 卡死。
- 方案A(组合Hash):
DISTRIBUTED BY HASH(tenant_id, user_id),加入一个高基数列打散。 - 方案B(Random分桶): 如果不需要按 Hash 键做聚合或 Join,直接
DISTRIBUTED BY RANDOM BUCKETS AUTO。
3. 历史数据处理
很多表刚建立时数据量不大,分桶设的很少;后来业务爆发,数据量翻倍,老的分桶数不够用了。
- Doris 支持动态修改新建分区的分桶数。可以通过
ALTER TABLE t1 MODIFY PARTITION p1 SET ("replication_num"="3");或者修改动态分区的默认分桶数,让未来的新数据使用更大的分桶数。
总结
- 分区(Partition): 用时间,控制单分区在合理范围,结合生命周期管理。
- 分桶(Bucket): 目标是让单个物理 Tablet 落在 1GB - 10GB。
- 节点协同: 分桶数尽量是 BE 节点数的整数倍(前提是不能产生过多小文件)。
- 偷懒利器: 尽量使用
BUCKETS AUTO拥抱自动化。
右滑查看面试常问