ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

StarRocks查表占用存储全攻略:从SHOW DATA到BE物理文件排查

StarRocks查表占用存储全攻略:从SHOW DATA到BE物理文件排查 某天下午我正盯着监控面板群里突然有人发来一条消息BE-03磁盘使用率92%了赶紧看看是哪张表在吃空间。这也是我在日常运维StarRocks时最常被问的问题之一。StarRocks把数据打散存储在一组BE节点上一份数据还有多个副本想弄清楚某张表到底占了多大存储远没有在MySQL里执行一条information_schema来得直接。不同口径下大小可以差出两三倍是压缩前还是压缩后算不算副本逻辑表大小和BE磁盘上的物理占用又对不上。这篇文章我从实际运维视角把StarRocks查看每张表占用存储的常用方法和踩坑经验完整梳理一遍适合正在管理StarRocks集群的DBA、数据开发以及刚接手集群想知道底细的朋友。1. 为什么在StarRocks里查表大小和MySQL完全不是一个逻辑先说一个最容易被忽略的背景StarRocks并不是把一张表当成一个文件存在某台机器上。表的每个分桶对应一个tablettablet按照副本数默认3分散到不同BE节点上。一份数据实际上被拆成了很多小格子每个格子又有三份拷贝错落地放在不同磁盘里。所以这张表占用多少存储这句话本身就有至少三种理解角度逻辑数据量不考虑副本、不计算索引和元数据开销纯粹看数据内容有多大。含副本的数据量一个tablet存了三份三份都算进去磁盘空间确实被吃掉了三份。物理磁盘占用数据文件、索引文件、compaction中间产物、还没清理的垃圾文件全部算进去这才是真正让磁盘告警的那个数字。我常用一个类比来解释一张表像一大箱货StarRocks会把货拆成若干小格子tablet每个格子复制三份分别锁进三台不同仓库。有人问这箱货多大你得先反问回去——你问的是单份重量、三份合计还是连同货架和库房过道一起算的占地面积这三个数字差异巨大但没有一个算是错的。搞清楚这一点后后面所有命令和脚本就都不会看迷糊了。接下来我从最轻量、最常用的入口开始再逐步深入到BE文件系统层面。2. SHOW DATA最轻量的入口但Size口径要弄清楚如果你只是想快速知道哪个库哪张表大SHOW DATA是StarRocks里最直接的命令也是我在巡检时用得最多的一个。2.1 基本用法与输出列解读最简单的用法是直接执行SHOW DATA;这会列出所有库下所有表的汇总信息。指定库和表也可以SHOW DATA FROM db_name; SHOW DATA FROM db_name.table_name;当指定到某张表时输出会细到每个Index主表以及表上的物化视图/rollup这对定位是不是某个物化视图把空间吃掉了很有用。典型的输出列大致包含这些字段含义TableName表名或者Index名Size数据大小字节为单位ReplicaCount副本数RowCount行数RemoteSize远端存储大小存算分离环境下出现一般本地部署没有注意不同小版本对列的命名和展示略有差异我看到过的输出里就有多一个RemoteSize列的情况但核心的Size、RowCount基本都在。2.2 Size数字里藏着两层口径压缩和副本这是最容易误解的地方我单独拿出来说。官方文档里的说法是Size代表整个表的数据大小展示数值为副本中数据大小的总和。结合我自己的实测这里有两个关键点**Size是压缩后的数据量。**StarRocks是列式存储本身就带压缩遇到重复度高的数值型字段压缩比可以非常夸张。我见过一个线上表导入源文件大约10GBSHOW DATA里Size只显示2.3GB刚开始以为数据丢了后来才确认是压缩效果。**Size默认包含了所有副本。**一张默认3副本的表如果单份数据量是10GBSize一般会显示30GB左右。如果这张表当时被改成了2副本那Size就是20GB以此类推。所以当你想估算单份数据大小时可以简单用Size / ReplicaCount来折算。但折算出来的也只是逻辑数据量不是物理文件占用。2.3 快速找出Top大表的土办法用客户端执行SHOW DATA的结果通常是几十行甚至几百行肉眼去扫很费劲。我一般直接在shell里处理mysql -h fe_host -P 9030 -u root -e SHOW DATA FROM dwd; \ | awk NR1 {print $1, $2} \ | sort -k2 -hr \ | head -20这里假设输出里第二列是Size字节数NR1跳过头两行表头和一个分隔行。sort -k2 -hr按数字倒序排取前20个。这套组合拳几秒钟就能告诉我今天又该收拾哪张表了。不过SHOW DATA的粒度只到表或Index没法回答这张表哪个分区最大哪个BE上副本分布最不均匀这类问题。一旦需要下钻就要用到第三节的information_schema表。3. information_schema.be_tablets精确到表、分区、副本SHOW DATA够用但不够细。真正做存储治理的时候我更依赖information_schema.be_tablets这张系统表。它把每个BE上每个tablet的元数据都暴露出来粒度直接到tablet可以聚合出任意维度的存储分布。3.1 先确认你环境里的字段不同StarRocks版本里be_tablets的字段有差异尤其是列名大小写和一些新增字段。稳妥起见先看一眼再写SQLDESC information_schema.be_tablets;我用的版本里常见字段有这些DATABASE_NAME、TABLE_NAME库名、表名PARTITION_NAME分区名TABLEt_IDtablet idBE_IDtablet副本所在BEDATA_SIZE该副本的数据大小ROW_COUNT行数STORAGE_PATHtablet目录所在的存储路径INDEX_NAMEIndex名如果你执行DESC发现字段名大小写不一样就把后面SQL里的列名相应替换一下原理完全一样。3.2 按表聚合一张SQL拿到全局TopN我最常跑的聚合查询长这样SELECT DATABASE_NAME, TABLE_NAME, ROUND(SUM(DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, SUM(ROW_COUNT) AS row_count, COUNT(*) AS tablet_count FROM information_schema.be_tablets GROUP BY DATABASE_NAME, TABLE_NAME ORDER BY size_gb DESC LIMIT 20;这个结果和SHOW DATA的Size总体对得上因为每个tablet在哪个BE上都会单独占一行SUM(DATA_SIZE)天然就是把所有副本都算了进去。如果某张表是3副本这里看到的数值大致就是单份数据量的3倍。如果想知道单份数据量可以按表的实际副本数折算也可以先按DATABASE_NAME, TABLE_NAME去重后对每个BE只取属于该表的一份副本。不过运维场景下我更习惯直接看含副本的合计值因为磁盘告警是由物理占用触发的而物理占用恰恰是副本都算上的。3.3 按分区、按BE继续下钻这是be_tablets相比SHOW DATA最大的优势。排查某个大分区表哪一天的数据最肥时直接按PARTITION_NAME聚合SELECT PARTITION_NAME, ROUND(SUM(DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, SUM(ROW_COUNT) AS row_count, COUNT(*) AS tablet_count FROM information_schema.be_tablets WHERE DATABASE_NAME dwd AND TABLE_NAME dwd_order_detail GROUP BY PARTITION_NAME ORDER BY size_gb DESC LIMIT 20;想确认集群里BE之间是否均衡就按BE_ID聚合SELECT BE_ID, ROUND(SUM(DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, COUNT(*) AS tablet_count FROM information_schema.be_tablets GROUP BY BE_ID ORDER BY size_gb DESC;这两个SQL可以快速回答两个高频问题哪张表哪个分区最占空间、哪个BE的副本总重量已经冒尖了。有个权限上的坑需要提前提醒be_tablets里的信息来自BE上报给FE的统计普通低权限账号有可能查不到或者查询返回空。我遇到过的情况是业务账号执行上面SQL直接报错。可以先跑一句SELECT COUNT(*) FROM information_schema.be_tablets;自测一下如果没权限找管理员给账号授权后再用。4. 落到BE磁盘上验证物理占用逻辑口径只能帮你定位嫌疑表一旦遇到磁盘真的快满、需要确认物理文件到底占了多少的情况就得落到BE节点上看实际文件。这一步才是让告警消失的闭环。4.1 先从BE的web端和指标接口看水位每个BE默认会在be_http_port通常是8040上提供HTTP服务。浏览器访问http://BE_IP:8040能看到该BE的基本信息入口包括磁盘使用情况。如果集群接了Prometheus监控在BE的metrics接口里也能直接拉到磁盘容量和实际占用相关指标。这一步主要确认一个问题告警的那台BE到底是整块数据盘都满了还是某一块盘被某个大表目录撑满了。只有确定了是哪块盘下一步才值得去做。4.2 tablet目录对应关系与单个大tablet的验证BE上tablet的落盘路径大致是这样的结构{storage_root_path}/data/{cluster_id}/{tablet_id}/{schema_hash}tablet_id就是be_tablets里的TABLEt_IDschema_hash是表的哈希标识。里面主要是数据文件和索引文件例如.dat、.idx、.meta、.gc之类。当你通过information_schema.be_tablets找到了某张表最大的几个tablet就可以直接登录BE节点用du验证物理目录大小# 在BE节点执行查看某个大tablet的物理目录占用 du -sh /mnt/disk1/starrocks/data/10001/106234/*这里mnt/disk1/starrocks是假设的storage_root_path10001是cluster_id106234是tablet_id。如果结果和DATA_SIZE基本一致说明这个tablet没有太多垃圾文件堆积如果大出很多多半是compaction没跟上或存在未回收的旧版本文件。4.3 整批统计某个BE上每张表的物理占用很多tablet要一个个du太慢我建议按下面的思路做批量统计在FE上执行SQL拉出目标BE上所有tablet_id、表名、DATA_SIZESELECT TABLEt_ID, TABLE_NAME, DATABASE_NAME, DATA_SIZE FROM information_schema.be_tablets WHERE BE_ID 10003 ORDER BY DATA_SIZE DESC;把结果保存成tablet_list.tsv然后登录BE节点。在BE上用一个循环脚本统计每个tablet目录的真实大小#!/bin/bash # 在BE节点执行 ROOT/mnt/disk1/starrocks/storage CLUSTER_ID$(ls ${ROOT}/data | head -1) while read tablet_id table_name; do size_bytes$(du -sb ${ROOT}/data/${CLUSTER_ID}/${tablet_id} 2/dev/null | awk {print $1}) echo -e ${tablet_id}\t${table_name}\t${size_bytes} done /tmp/tablet_list.tsv /tmp/be_tablet_sizes.tsv注意如果BE上tablet数量非常大全量du -sb会非常慢几十万级目录可能要跑很久。我通常只对DATA_SIZE排在前面的几百个tablet做物理验证而不会全量做。把统计结果与FE侧的SQL结果合并就能得到BE磁盘层面哪张表实际吃掉了多少空间。4.4 为什么物理占用总是比DATA_SIZE大这是我每次做磁盘专项排查都会遇到的问题。一个tablet的DATA_SIZE是5GB但du出来可能有6GB甚至更多。多出来的部分主要来自segment索引和元数据文件.idx、.meta这类文件不计入DATA_SIZE但真实占据磁盘。compact过程中产生的临时文件合并还没完成时会存在两份文件。尚未被GC清理的垃圾文件表结构变更、分区删除、副本迁移后旧文件并不立即物理删除而是等待垃圾回收机制处理。小文件过多tablet数量大但每个tablet数据量很小文件系统层面Inode和最小块开销反而更明显。所以如果你发现du的结果比SHOW DATA折算出来的大不少先别急着认为是统计错了绝大多数情况下是物理文件合理开销。5. 一套可复用的排查模板Top表、Top分区、倾斜诊断到这里方法论基本齐了。我把平时真正会用到的排查流程固定成了四步模板遇到磁盘告警类问题直接按顺序跑一遍基本能在十分钟内定位到根因。5.1 四步法从全局看到单表第一步看全局Top20表。用第三节的聚合SQL或者直接SHOW DATA确定哪些表是大头。第二步对Top表按分区下钻。找到最占空间的分区看一下是不是某个近期分区异常膨胀还是历史分区没有按预期清理。SELECT PARTITION_NAME, ROUND(SUM(DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb, SUM(ROW_COUNT) AS row_count, COUNT(*) AS tablet_count FROM information_schema.be_tablets WHERE DATABASE_NAME dwd AND TABLE_NAME dwd_order_detail GROUP BY PARTITION_NAME ORDER BY size_gb DESC LIMIT 20;第三步对嫌疑表按BE分组看存储是否倾斜。如果某张表的tablet在BE-01上有大量副本、在BE-02上很少说明数据分布不均衡这在后续分桶策略调整时要重点考虑。第四步拉出最大tablet明细。如果一个tablet的单副本体积明显大于同表其他tablet数值上几十倍的话基本可以判断分桶键选择有问题或者出现了数据倾斜SELECT TABLET_ID, BE_ID, ROUND(DATA_SIZE / 1024 / 1024, 2) AS size_mb, ROW_COUNT FROM information_schema.be_tablets WHERE DATABASE_NAME dwd AND TABLE_NAME dwd_order_detail ORDER BY DATA_SIZE DESC LIMIT 20;5.2 不同方法的对比方便按场景选我在内部文档里维护了一张简单对照表每次写排查报告也会附上方法粒度是否含副本是否压缩精确性是否需要BE权限SHOW DATA表 / Index含压缩后逻辑大小中有汇总延迟无需BE权限be_tablets聚合表 / 分区 / tablet / BE含每个副本一行压缩后逻辑大小较高来自BE上报需要information_schema权限BE文件系统du单个BE上的目录级单节点上的副本物理压缩后大小最高需要登录BE这个表解决的核心问题是该信哪个数字。结论是日常巡检信SHOW DATA下钻定位信be_tablets磁盘到底满没满必须信du。5.3 顺手算一下单行平均大小也能发现隐患用be_tablets聚合出大小和行数之后可以顺手算一算单行平均大小SELECT DATABASE_NAME, TABLE_NAME, ROUND(SUM(DATA_SIZE) / SUM(ROW_COUNT), 2) AS avg_row_size, ROUND(SUM(DATA_SIZE) / 1024 / 1024 / 1024, 2) AS size_gb FROM information_schema.be_tablets WHERE ROW_COUNT 0 GROUP BY DATABASE_NAME, TABLE_NAME ORDER BY avg_row_size DESC LIMIT 20;如果一张表行数不多但单行平均大小异常高多半是里面有超宽字段、长字符串或者分桶设计不合理导致压缩率上不去。这个指标对优化表结构很有参考价值。6. 那些年查表大小时踩过的坑前面每一节其实都埋了一些坑但有几个坑是反复出现的值得集中说一说免得你走弯路。6.1 数据少了的惊吓第一次用SHOW DATA看一张刚导入完的表时Size比源文件小了太多我当时第一反应是数据是不是没导全。核对行数没问题后才反应过来是列式存储压缩的效果。数值型数据里大量重复的维度值、枚举值压缩比可以非常夸张。后来我就养成了习惯**拿源文件大小和表Size对比的时候只用来估算压缩比不要用来验证数据完整性。**验证数据完整性的靠谱方式是行数和关键字段SUM值不是大小。6.2 副本数改了以后所有历史统计口径都变了有段时间我们把一批冷表从3副本降到了2副本。降完以后SHOW DATA和be_tablets聚合出来的数值都变小了因为副本少了一份。如果拿这个数字去跟降副本之前比会误以为清理出了1/3空间。实际上逻辑数据量单份没变只是冗余少了。所以在任何存储趋势报表里务必记录每张表的副本数或者干脆统一按单份口径折算否则趋势线会被副本调整的假象带偏。6.3 删了分区BE磁盘空间却不掉这可能是最让人抓狂的坑。SHOW DATA FROM已经看不到某个分区了be_tablets里也查不到对应tablet但df -h一看磁盘占用纹丝不动。原因就是删除分区是标记删除tablet数据文件要等待GC线程真正回收而GC经常有延迟尤其在tablet数量非常多的时候。遇到这种情况先等一等观察BE日志里的gc信息如果迟迟不回收需要检查GC是不是被卡住了。记住一个原则逻辑上删除和物理上释放是两件事中间隔着compaction和gc。6.4 be_tablets的权限和版本差异低版本StarRocks不一定有information_schema.be_tablets就算有字段命名在不同版本之间也可能不一致。我在2.x和3.x的环境里就遇到过DATA_SIZE和data_size写法的差异直接照抄网上的SQL可能报错。所以每次在新环境里第一次用这个表我都先执行DESC information_schema.be_tablets;确认一下再写聚合SQL。另外权限问题前面也提过普通账号很可能查不到拿管理员账号先跑通再决定怎么给业务账号授权。6.5 不要依赖客户端格式化输出做脚本自动化如果你们是直接执行SHOW DATA然后接awk处理有个细节要留神某些管理平台或客户端会把Size显示成2.3 GB这种人类可读格式而不是纯数字字节。这时候sort -hr还能勉强用但如果你做的是精确汇总建议统一走be_tablets按字节算不要在格式化字符串上做运算。我在写自动化巡检脚本时踩过这个坑后来所有统计一律以information_schema.be_tablets为准SHOW DATA只用来人工肉眼巡检。我个人现在的日常习惯是每日巡检用SHOW DATA看有没有表的Size突然异常增长出了磁盘告警立刻用be_tablets做表、分区、BE三轮下钻如果还定位不到直接上BE节点对前几百个大tablet目录做du验证。这套流程基本覆盖了我遇到过的所有表把磁盘吃满了的场面。最后再分享一个小经验把这些SQL固化成一个巡检脚本每周跑一次把Top表和Top分区的变化趋势记下来很多存储问题在爆发前其实是有苗头的。
返回列表