news 2026/4/30 4:46:37

ClickHouse系列(九):慢查询、内存 OOM 与稳定性治理

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ClickHouse系列(九):慢查询、内存 OOM 与稳定性治理

系列定位:性能与稳定性 —— 解决线上慢查询、Merge 炸内存等核心痛点

ClickHouse 的查询速度令人印象深刻,但在生产环境中,慢查询和内存溢出(OOM)是最常见的两类稳定性杀手。本篇将从诊断工具、内存模型、治理手段三个维度,系统性地讲解如何让 ClickHouse 集群长期稳定运行。


一、ClickHouse 的慢查询体系

与 MySQL 的slow_query_log不同,ClickHouse 没有独立的慢查询日志文件,而是将所有查询信息统一写入系统表system.query_log。这张表本身就是一张 MergeTree 表,支持全部 SQL 分析能力。

1.1 核心配置

<!-- config.xml 或 users.xml --><query_log><database>system</database><table>query_log</table><flush_interval_milliseconds>7500</flush_interval_milliseconds></query_log>

用户级别可以控制日志行为:

SETlog_queries=1;-- 开启查询日志(默认开启)SETlog_queries_min_type='QUERY_FINISH';-- 只记录完成的查询

1.2 query_log 的生命周期

每条查询在query_log中最多产生 4 条记录,通过type字段区分:

type含义触发时机
QueryStart查询开始解析完成、开始执行
QueryFinish查询正常结束执行完毕
ExceptionBeforeStart启动前异常语法错误、权限不足
ExceptionWhileProcessing执行中异常OOM、超时等

实际诊断时,我们主要关注QueryFinishExceptionWhileProcessing


二、system.query_log 的正确使用

2.1 找出 Top 慢查询

SELECTquery_duration_ms,read_rows,read_bytes,memory_usage,queryFROMsystem.query_logWHEREtype='QueryFinish'ANDevent_date=today()ANDquery_duration_ms>5000ORDERBYquery_duration_msDESCLIMIT20;

2.2 按用户 / 来源聚合

SELECTuser,client_hostname,count()ASquery_count,avg(query_duration_ms)ASavg_ms,max(memory_usage)ASmax_memFROMsystem.query_logWHEREtype='QueryFinish'ANDevent_date>=today()-7GROUPBYuser,client_hostnameORDERBYavg_msDESC;

2.3 捕获异常查询

SELECTevent_time,exception_code,exception,queryFROMsystem.query_logWHEREtype='ExceptionWhileProcessing'ANDevent_date=today()ORDERBYevent_timeDESCLIMIT10;

三、normalizeQuery 的聚合分析

生产环境中,同一类查询因参数不同会产生大量不同的 SQL 文本。normalizeQuery()函数将参数替换为占位符,使我们能够按查询模式聚合分析。

SELECTnormalizeQuery(query)ASnormalized,count()AScnt,avg(query_duration_ms)ASavg_ms,avg(read_rows)ASavg_rows,avg(memory_usage)ASavg_memFROMsystem.query_logWHEREtype='QueryFinish'ANDevent_date=today()GROUPBYnormalizedORDERBYcnt*avg_msDESCLIMIT20;

这条 SQL 的排序逻辑是cnt * avg_ms,即"总耗时贡献"最大的查询模式排在前面。这比单纯看最慢查询更有实际意义——一条 100ms 的查询如果每秒执行 1000 次,其影响远大于一条 10s 的偶发查询。

normalizeQuery的典型输出:

-- 原始 SQL SELECT * FROM events WHERE user_id = 12345 AND event_date = '2024-01-15' -- normalize 后 SELECT * FROM events WHERE user_id = ? AND event_date = ?

四、read_rows / read_bytes 的诊断意义

query_log中的read_rowsread_bytes是判断查询是否合理的关键指标。

4.1 诊断矩阵

场景read_rows耗时诊断
正常查询✅ 索引命中良好
全表扫描极多❌ 缺少 WHERE 或主键未命中
数据膨胀中等⚠️ 分区粒度过粗
返回行少但读取多⚠️ 过滤在读取之后,考虑调整排序键

4.2 实际案例

-- 查看某类查询的扫描效率SELECTnormalizeQuery(query)ASnq,avg(read_rows)ASavg_read,avg(result_rows)ASavg_result,avg(read_rows)/greatest(avg(result_rows),1)ASamplificationFROMsystem.query_logWHEREtype='QueryFinish'ANDevent_date=today()GROUPBYnqHAVINGamplification>1000ORDERBYamplificationDESCLIMIT10;

amplification(放大系数)超过 1000 意味着每返回 1 行结果需要扫描超过 1000 行原始数据,这类查询是优化的首要目标。


五、Merge / Aggregation 的内存模型

5.1 Merge 的内存消耗

ClickHouse 的后台 Merge 进程会将多个 data part 合并为更大的 part。Merge 过程中需要在内存中维护排序状态,内存消耗与以下因素正相关:

  • 参与合并的 part 数量和大小
  • 排序键的宽度(列数和类型)
  • 是否涉及AggregatingMergeTree的聚合状态

关键配置:

-- 单次 Merge 的最大内存(默认无限制,建议设置)SETmax_bytes_to_merge_at_max_space_in_pool=161061273600;-- 150GB-- 后台 Merge 线程数SETbackground_pool_size=16;

5.2 Aggregation 的内存模型

GROUP BY是 ClickHouse 中最大的内存消费者。其内存模型分为两个阶段:

  1. HashMap 构建阶段:将所有分组键和聚合状态存入内存 HashMap
  2. 溢出阶段(如果启用):当内存超过阈值时,将部分数据溢出到磁盘
-- 单次查询的内存上限SETmax_memory_usage=10000000000;-- 10GB-- GROUP BY 超过内存限制时的行为SETmax_memory_usage_for_user=20000000000;-- 用户级 20GB-- 允许 GROUP BY 溢出到磁盘(牺牲性能换稳定性)SETmax_bytes_before_external_group_by=5000000000;-- 5GB 后溢出SETmax_bytes_before_external_sort=5000000000;

5.3 内存消耗估算

对于GROUP BY查询,内存消耗的粗略公式:

内存 ≈ 分组基数 × (所有 GROUP BY 列的平均宽度 + 所有聚合状态的宽度)

例如:GROUP BY user_id (UInt64), event_type (String avg 20B),聚合count(), sum(amount)

每行 ≈ 8 + 20 + 8 + 8 = 44 字节 1 亿个不同的 user_id × 44B ≈ 4.1 GB

六、MEMORY_LIMIT_EXCEEDED 的典型场景与治理

6.1 典型触发场景

场景原因频率
高基数 GROUP BY分组键组合爆炸⭐⭐⭐⭐⭐
大表 JOIN右表被全量加载到内存⭐⭐⭐⭐
ORDER BY 无 LIMIT全量排序⭐⭐⭐
不合理的 IN 子查询子查询结果集过大⭐⭐⭐
后台 Merge 叠加查询内存争抢⭐⭐

6.2 治理策略

策略一:设置多层内存防线

<!-- users.xml --><profiles><default><!-- 单查询上限 --><max_memory_usage>10000000000</max_memory_usage><!-- 单用户上限 --><max_memory_usage_for_user>30000000000</max_memory_usage_for_user><!-- 服务器总上限比例 --><max_server_memory_usage_to_ram_ratio>0.8</max_server_memory_usage_to_ram_ratio></default></profiles>

策略二:启用溢出到磁盘

SETmax_bytes_before_external_group_by=5000000000;SETmax_bytes_before_external_sort=5000000000;

这会在内存达到阈值时将中间结果写入临时目录,查询不会失败但速度会下降。

策略三:查询改写

-- ❌ 高基数 GROUP BYSELECTuser_id,count()FROMeventsGROUPBYuser_id;-- ✅ 使用近似算法SELECTuniqHLL12(user_id)FROMevents;-- ❌ 大表 JOINSELECT*FROMaJOINbONa.id=b.id;-- ✅ 使用 IN 替代(如果只需要过滤)SELECT*FROMaWHEREidIN(SELECTidFROMbWHERE...);

策略四:限制并发

<profiles><default><max_concurrent_queries_for_user>10</max_concurrent_queries_for_user></default></profiles>

6.3 监控告警

建议对以下指标建立告警:

-- 最近 1 小时 OOM 次数SELECTcount()FROMsystem.query_logWHEREtype='ExceptionWhileProcessing'ANDexception_code=241-- MEMORY_LIMIT_EXCEEDEDANDevent_time>now()-INTERVAL1HOUR;
-- 当前内存使用率SELECTformatReadableSize(value)AScurrent_memoryFROMsystem.metricsWHEREmetric='MemoryTracking';

小结

ClickHouse 的稳定性治理核心在于:可观测 → 可诊断 → 可防御

  1. system.query_log+normalizeQuery()建立查询画像
  2. read_rows/memory_usage定位问题查询
  3. 用内存限制 + 溢出机制 + 查询改写构建多层防线
  4. 用监控告警实现事前预防而非事后救火

下一篇我们将进入系列的最后一篇,聚焦生产架构与最佳实践总结。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/11 4:11:59

AI翻唱神器RVC入门教程:快速搭建个人语音变声环境

AI翻唱神器RVC入门教程&#xff1a;快速搭建个人语音变声环境 1. 引言&#xff1a;从听到“假声”到创造“新声” 不知道你有没有过这样的经历&#xff1a;在和朋友语音聊天、看直播或者刷短视频时&#xff0c;突然听到一个声音&#xff0c;感觉特别熟悉&#xff0c;但又明显…

作者头像 李华
网站建设 2026/4/11 4:11:15

【Matlab】移动机器人室内自主导航路径优化

一、引言 随着机器人技术与人工智能的深度融合,移动机器人已广泛应用于室内仓储、智能家居、医疗护理、工业巡检等领域,室内自主导航是其实现自主作业的核心能力,而路径优化作为自主导航系统的关键环节,直接决定了机器人的作业效率、运动安全性与能耗经济性。室内环境存在…

作者头像 李华
网站建设 2026/4/11 4:11:10

awesome-ml中的免费AI工具清单:无需付费的强大资源

awesome-ml中的免费AI工具清单&#xff1a;无需付费的强大资源 【免费下载链接】awesome-ml Curated list of useful LLM / Analytics / Datascience resources 项目地址: https://gitcode.com/gh_mirrors/aw/awesome-ml awesome-ml项目是一个精心策划的LLM、分析和数据…

作者头像 李华
网站建设 2026/4/12 9:50:34

MOSN负载均衡完全教程:从基础算法到高级策略实战

MOSN负载均衡完全教程&#xff1a;从基础算法到高级策略实战 【免费下载链接】mosn The Cloud-Native Network Proxy Platform 项目地址: https://gitcode.com/gh_mirrors/mo/mosn MOSN&#xff08;The Cloud-Native Network Proxy Platform&#xff09;作为云原生网络代…

作者头像 李华
网站建设 2026/4/11 4:06:10

L07A音响系统分析:在尝试固化SSH服务过程中遇到的技术问题

本文记录了对L07A音响进行系统分析的一次失败尝试。目标是实现SSH服务的开机自动启动&#xff0c;以便通过网络进行管理。然而&#xff0c;在尝试了多种方案后&#xff0c;均以失败告终。本文将详细记录这一过程中的技术探索、遇到的障碍以及最终的分析结论。0x00 失败的开始&a…

作者头像 李华