前几天线上出了个StarRocks的Bug,我排查了一夜才解决。

事情是这样的:我们的实时数仓用了StarRocks,一直跑得挺稳定。那天晚上,突然收到告警,说StarRocks的查询延迟飙升,部分查询超时。我赶紧爬起来排查,折腾了一夜,终于找到原因并解决了。

本文记录这次排查的全过程,包括问题现象、排查思路、定位过程、根本原因、解决方法,以及从中总结的经验教训。希望能帮到遇到类似问题的同学。

一、问题现象

那天晚上11点多,我正准备睡觉,手机突然响了。

是监控系统的告警:StarRocks集群的P99查询延迟,从平时的200ms飙升到了5秒,而且有越来越多的查询超时。

我赶紧打开监控面板,看到:

  • 查询延迟:P99从200ms涨到5s,P95从100ms涨到2s
  • 查询成功率:从99.9%降到95%
  • CPU使用率:BE节点的CPU从40%涨到90%+
  • 内存使用率:BE节点的内存从60%涨到85%
  • 磁盘IO:正常,没有明显升高
  • 网络:正常

而且,延迟是慢慢涨上去的,不是突然飙升。从晚上9点开始慢慢涨,到11点已经涨到5秒了。

我第一反应是:是不是有慢查询把资源占满了?

二、初步排查

第一步:看正在运行的查询

我登录StarRocks的管理界面,看正在运行的查询。

SHOW PROCESSLIST;

发现有几个查询已经跑了好几分钟了,还没结束。这些查询都是同一个业务方的,查询的是一张大表(大约50亿行),条件比较复杂。

我以为是这些慢查询把资源占满了,导致其他查询排队。于是我先把这几个慢查询杀掉了。

KILL QUERY <query_id>;

杀掉之后,查询延迟确实降了一点,但没过多久,又涨上去了。而且,新的慢查询又出现了。

这说明,慢查询只是表象,不是根本原因。

第二步:看BE节点的状态

我看了一下BE节点的状态,发现有一个BE节点的CPU和内存明显比其他节点高。

SHOW BACKENDS;

这个节点的CPU是95%,内存是90%,而其他节点都是50%左右。

我怀疑是数据倾斜,导致某个节点负载过高。

第三步:看数据分布

我查了一下那张大表的数据分布,发现数据确实倾斜了。

SELECT 
  tablet_id,
  COUNT(*) as cnt
FROM table_name
GROUP BY tablet_id
ORDER BY cnt DESC
LIMIT 10;

有几个tablet的数据量特别大,是其他tablet的10倍。而且这些大tablet都在同一个BE节点上。

我以为是数据倾斜导致的问题,于是做了一次数据重分布(ALTER TABLE ... DISTRIBUTED BY ...)。

重分布之后,数据确实均匀了,那个BE节点的负载也降下来了。我以为问题解决了,准备回去睡觉。

结果,没过半小时,延迟又涨上去了。而且这次,所有BE节点的CPU都很高,不是单个节点的问题了。

这说明,数据倾斜也不是根本原因。

三、深入排查

这时候已经凌晨1点多了。我有点慌了,因为问题还没找到,而延迟还在涨。

我决定换个思路,从系统层面排查。

第四步:看BE的日志

我登录到那个负载最高的BE节点,看BE的日志。

tail -f be/log/be.INFO

日志里有很多查询,但没有明显的报错。不过,我注意到一个细节:日志里频繁出现"memory limit exceeded"的警告。

W0516 01:23:45.123456 12345 memory_limiter.cpp:123] Memory limit exceeded: query_id=xxx, used=85%, limit=80%

这说明,查询因为内存超限被限流了。但为什么内存会超限呢?

第五步:看内存使用详情

我用StarRocks的内存分析工具,看了一下内存的使用情况。

SHOW PROC '/memory';

发现大部分内存被"query memory"占用了,也就是查询用的内存。而且,有几个查询的内存使用量特别大,每个都用了好几GB。

我看了一下这些查询的SQL,发现它们都用了一个共同的特性:Bitmap去重。

SELECT COUNT(DISTINCT user_id) FROM table_name WHERE ...

StarRocks的COUNT(DISTINCT)默认是用Bitmap实现的。Bitmap在数据量大的时候,会占用很多内存。

我怀疑是Bitmap去重导致的内存问题。但这个表一直都在用Bitmap去重,以前没问题,为什么今天突然有问题?

第六步:看数据量变化

我查了一下这张表的数据量,发现今天的数据量比平时多了很多。

SELECT COUNT(*) FROM table_name WHERE dt = '2022-05-16';

平时每天新增大约1亿行,今天新增了5亿行。是平时的5倍!

我问了一下业务方,才知道今天他们做了一个活动,用户量暴增,所以数据量也暴增了。

数据量暴增,导致Bitmap去重的内存使用量暴增,进而导致查询内存超限,查询被限流,延迟飙升。

但这还不是根本原因。因为数据量虽然大了5倍,但集群的资源应该能扛住。为什么会导致所有查询都慢呢?

第七步:看内存限流的影响

我仔细看了一下内存限流的逻辑。

StarRocks有一个内存限制机制:当整个BE节点的内存使用超过阈值(默认80%)时,会对新的查询进行限流,甚至拒绝查询。

问题就在这里。那几个大查询(Bitmap去重)占用了大量内存,导致整个BE节点的内存超过了80%。然后,所有新的查询都被限流了,不管查询大小,都要排队等内存。

这就解释了为什么所有查询都变慢了——不是因为查询本身慢,而是因为内存限流,查询在排队。

而且,这是一个恶性循环:大查询占用内存 → 内存超限 → 小查询被限流排队 → 排队的查询越来越多 → 内存占用更高 → 更严重的限流。

四、根本原因

找到这里,根本原因就清楚了:

  1. 直接原因:业务活动导致数据量暴增5倍
  2. 触发因素:Bitmap去重查询在大数据量下占用大量内存
  3. 根本原因:StarRocks的内存限流机制是节点级别的,单个大查询会导致整个节点的所有查询被限流

简单说就是:几个大查询把内存占满了,导致所有查询都被限流,进而导致整个集群的查询延迟飙升。

五、解决方法

找到原因后,我采取了以下措施:

1. 立即缓解:杀掉大查询,限制并发

先把那几个占用内存大的Bitmap查询杀掉,然后限制这类查询的并发数。

-- 杀掉慢查询
KILL QUERY <query_id>;

-- 限制用户并发
SET PROPERTY FOR 'user_name' 'max_user_connections' = '5';

杀掉大查询后,内存很快降下来了,查询延迟也恢复了正常。

2. 短期优化:调整内存配置

调整了BE的内存配置,增大了查询内存的限制,同时调整了内存限流的阈值。

# be.conf
query_mem_limit = 80%  # 每个查询的内存限制
mem_limit = 85%        # 节点内存限制

另外,给Bitmap查询单独设置了资源组,限制它们的资源使用,避免影响其他查询。

3. 长期优化:优化查询和表结构

从根本上解决问题,需要优化查询和表结构:

  • 对Bitmap列做预聚合,减少查询时的计算量
  • 用物化视图预计算常用的去重指标
  • 对大查询做异步化,避免影响在线查询
  • 增加集群资源,应对数据量增长

六、经验教训

这次排查折腾了一夜,总结了几条经验教训。

1. 监控要细,不能只看整体

我们的监控只看了整体的查询延迟和成功率,没有细分到查询类型和资源使用。如果一开始就能看到内存使用和查询类型,就能更快定位问题。

以后要加更细的监控:

  • 按查询类型监控延迟和资源使用
  • 监控内存使用,特别是查询内存
  • 监控Bitmap等特殊功能的使用情况

2. 大查询要隔离,不能和小查询混跑

大查询(比如Bitmap去重、大表Join)占用资源多,应该和小查询隔离开。用资源组或者单独的集群,避免大查询影响小查询。

3. 数据量增长要有预案

业务活动导致数据量暴增,这种情况应该有预案。提前评估数据量增长对系统的影响,做好扩容和优化。

4. 了解底层机制很重要

这次问题的根本原因,是StarRocks的内存限流机制。如果不了解这个机制,就很难定位问题。

用任何技术,都要了解它的底层机制和限制。不能只停留在会用的层面。

5. 排查问题要系统,不能想当然

我一开始以为是慢查询,后来以为是数据倾斜,都没找到根本原因。后来从系统层面(日志、内存、配置)排查,才找到真正的原因。

排查问题要系统,从现象到本质,一步步来,不能想当然。

七、StarRocks使用的其他建议

借着这次经历,也说说我用StarRocks的一些建议。

1. 合理设计分桶

分桶数要合适,太多太少都不好。一般建议每个tablet的数据量在1-10GB之间。分桶键要选择分布均匀的列,避免数据倾斜。

2. 用好物化视图

物化视图是StarRocks的一大利器。对于常用的聚合查询,可以用物化视图预计算,大大提升查询速度。

3. 注意内存使用

StarRocks是内存密集型的,要特别注意内存使用。监控内存,合理配置内存限制,避免OOM。

4. 定期Compaction

数据导入后会产生很多小的版本,需要Compaction合并。定期检查Compaction状态,必要时手动触发。

5. 做好备份

虽然StarRocks有多副本,但还是要定期备份。用BACKUP命令备份数据,以防万一。

八、写在最后

这次StarRocks的Bug排查,折腾了我一夜,但也让我对StarRocks的理解更深了。

技术就是这样,每踩一个坑,就多一分理解。没有白踩的坑,也没有白熬的夜。

希望这篇文章能帮到遇到类似问题的同学。如果你也在用StarRocks,遇到了查询延迟飙升的问题,可以从内存、大查询、数据倾斜这几个方面排查。

2022年了,StarRocks已经越来越成熟,成为了很多公司实时数仓的首选。但不管用什么技术,了解底层机制、做好监控、有应急预案,都是不变的真理。

最后,用一句话总结:"线上问题不可怕,可怕的是不知道为什么。只要系统排查,总能找到原因。"

愿大家的线上系统都能稳定运行,不用熬夜排查问题。