集群健康度通过多个维度的健康指标得出的参考性结论。是评判集群的运行状况、出现问题风险的重要风向标。相比监控指标,健康度指标的实时性偏低(每小时采集过去一小时的最大值),反映的问题更偏长期治理解决。
说明
一个类比:监控是体征检测仪,健康度是体检报告。
健康度指标:
健康度等级:
作为集群的整体概览,抽象反映整体健康情况。
有以下四个等级,和健康度指标的档位有对应关系:
危险:有 1 项危险指标;
不及格:没有危险指标,且 1 项以上指标为不及格指标;
及格:没有危险和不及格,且 1 项以上指标为及格;
良好:每一项都是良好。
前提条件:
操作步骤
指标含义: 数据盘(ByteHouse 目录所在磁盘)的占用率。磁盘使用率过高会影响后续的数据导入。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
(0,60] | (60,80] | (80,95] | (95,100] |
优化建议:
select database, name, total_bytes from system.tables order by total_bytes desc limit 100
查看系统中较大的表。指标含义: 指操作系统的 inode 使用率。过高时会影响集群数据导入和查询。通常是由写入的 Part 太碎,不能及时 Merge 造成的。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
(0,60] | (60,80] | (80,90] | (90,100] |
优化建议:
1. 检查表定义:
如果表定义里面 partition-key 过多,那么就会造成过多的分区。
select database, table, countDistinct(partition_id) as partition_num from system.parts where active group by database, table order by partition_num desc limit 10
通过这个 SQL 对分区特别多的表进行查询。如果存在这种分区极多的表(e.g. >1万),可以考虑让表的责任人调整表结构。
2. 限制导入的频次:
对于 Parts 多的另一个情况就是导入太碎,造成了比较多的零碎 parts,可以通过以下 SQL 查看:
select database, table, count() as partition_num, sum(rows) as total_rows from system.parts where active group by database, table order by partition_num desc limit 10
如果可以看到每个 Partition 所拥有的 Rows 比较少,那么可以确定导入时落盘太频繁;若是 Insert Into 导入,建议每次写一万行以上,若是 Kafka 导入,建议配置 stream_flush_interval_ms
为 8000,即 8 秒攒一批数据写入。
3. 关注 MAP 引起的 Part 过多:
ByteMap 默认为隐式列设计,即每个 key 为 1 列,key 的数量增多可能引起 Parts 过多。
若使用默认多隐式列 MAP ,建议设置 max_map_key_num
参数为 3000,即每个 Map 最多导入 3000 个 key。若超过 3000,则建议使用单隐式列 MAP 和 KV map,可认为无需刻意限制 key 上限。
指标含义: 无法联通节点 / 全部节点数。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
0% | (0,20] | (20,50] | (50,100] |
优化建议:
指标含义: 集群 *MergeTree 表的总数量。表数量越多,可能会导致 Zookeeper 压力大,导致数据同步问题。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
[0,500] | (500,1000] | (1000,5000] | > 5000 |
优化建议:
指标含义: 集群 HaKafka 表的总数量。表数量越多,可能会导致集群的资源均用于写入,无资源查询。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
[0,20] | (20,50] | (50,90] | > 90 |
优化建议:
指标含义: HaMergeTree/HaUniqueMergeTree 引擎的主备同步日志记录在系统表 ha_queue
中,这个指标标识了 ha_queue
中未处理日志最多的一张表的剩余日志数量,代表这张表的主备同步发生了一些问题,很可能只有一个节点数据完整,在承担查询工作,导致负载不均。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
[0,100] | (100,1000] | (1000,10000] | > 10000 |
处理步骤:
1. 查看是什么表什么类型的 ha_queue
最多
在每个节点上执行:
select database, table, type, count() from system.ha_queue group by database,table, type order by count()
通过此 SQL 可以获得 Part 异常的表。后面的排查操作都是基于对异常表进行。
2. 先确认是否是这些表 Part 过多导致的:
针对ha_queue
剩余日志最多的表,建议根据 最大文件数占比 章节的 “优化建议”,确认当前表是否存在 Part 过多的问题,以及分区键设置是否合理。
3. 判断异常表的 Type,快速清理存量日志
3.1. 主要 Type 为 MERGE_PARTS
:
可以直接清理。系统会自动生成。
SYSTEM SKIP LOG db.table where type = 'MERGE_PARTS';
该命令暂时跳过了 Merge 命令,让后续日志继续执行。但是,由于分区键设置不合理,合并任务不进行等问题导致的 MERGE_PARTS 阻塞仍会再次发生。如果问题再次发生,建议根据”最大文件数占比”章节的“优化建议”再进行一些优化。
3.2. 主要 Type 为 GET_PART
则表示有大量 Part 同步任务受阻。需要分析如下:
2.2.1. (针对私有化部署)本节点磁盘是不是有损坏等硬件问题;如果有,直接替换这个节点;
2.2.2. 检查本节点上表是否是 leader?
在本节点上执行:
SELECT is_leader, absolute_delay FROM system.ha_replicas WHERE table = 'xxx_local'
如果 is_leader= 1
则是 leader,否则则不是 leader。
2.2.2.1. 如果本节点是 leader:
促进本节点数据拉全:
SYSTEM EXECUTE LOG db.table where type ='GET_PART';
2.2.2.2. 如果本节点不是 leader:
检查本节点的同 Shard 的另一个节点(以下简称备节点) 数据是否完整,在备节点上执行:
SELECT is_leader, absolute_delay FROM system.ha_replicas WHERE table = 'xxx_local'
情况1:如果输出是 is_leader: 1 , absolute_delay: 0
表示备节点数据全,则问题原因是产生 log 太频繁,本节点拉取跟不上。可以将本节点 log 清理掉从最新的状态再拉取。
在本节点上执行(注意,一定是在异常节点上,不是在数据完整的备节点上):
SYSTEM SKIP LOG db.table_local where 1; SYSTEM MARK lost db.table; DETACH table db.table; ATTACH table db.table;
情况2:如果输出is_leader:1 ,absolute_delay:<>0
表示备节点数据更多,但是也不全。
那先促进备节点获得所有数据,在备节点上执行:
SYSTEM EXECUTE LOG db.table where type ='GET_PART';
等备节点数据同步完,再处理主节点:
SYSTEM SKIP LOG db.table_local where 1; SYSTEM MARK lost db.table_local; DETACH table db.table_local; ATTACH table db.table_local;
2.3. 如果同时含有 GET_PART
和 DROP_RANGE
这种一般是因为过多的过期的小 Part 积压,正在等待被缓慢删除。
select name,min_time,max_time,rows from system.parts where table='xxx_local';
如果上面列出的 part 日期都在 TTL 之外,那就符合本条件。
原因是导入了太多 TTL 之外的历史数据或异常值,来不及 Drop。
如果是 Insert Into
或批式导入方式,则需要上游尽可能清洗数据,不导入超过 TTL 的数据。
如果是 Kafka 方式导入,则可以通过在消费时候设置过滤解决,例如:
ALTER TABLE db.CONSUMER_table_local ADD CONSTRAINT callTimes_constraint CHECK toDate(generate_time) < today() + 10 and toDate(generate_time) > today() - 10 --CONSUMER_table_local 是导入任务创建的 HaKafka 表,例如 ttl 为 10 天 --同时增加 toDate(generate_time) < today() + 10 则为了清洗异常时间值
3. 以上都无法解决
联系表的所有者,确认可以丢数据的前提下,执行以下操作:
SYSTEM SKIP LOG db.table where type ='GET_PART';
指标含义: 1 小时内最高时刻的查询并发数。由于 ByteHouse 并非一个高并发数据库,对并发的承载能力通常情况下在200左右。数字越大,集群健康状况越差。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
(0,20] | (20,100] | (100,200] | >200 |
优化建议:
max_execution_time
等限制参数,控制高并发集群禁止出现大查询。指标含义: 集群所有查询时延的 P95 分位(单位:秒),可基本反应集群查询的返回速度。数字越大,集群健康情况越差。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
(0,1] | (1,5] | (5,10] | >10 |
优化建议:
该指标不健康表明集群的查询速度很慢,慢于一般用户对 ClickHouse 的预期。首先收集各下游业务反馈,如果本身业务查询的数据量确实很大,并且可以接受目前的查询速度,则可以暂时忽略问题,后续再持续追踪。
如果下游业务反馈查询不稳定,且越来越变慢。则通过“数据管理与查询->查询管理->查询历史”功能,找到这个集群对应的大查询,判断大查询是否可以被优化。判断的条件包括但不限于:
Select *
。count distinct
、uniqExact
、quantileExact
,case when
等。对于 CPU 的开销很大,都可能导致查询耗时久,并且某些算子的查询效率无法通过扩容集群提升。如果不需要保证结果完全精确,可以将count distinct
、uniqExact
、quantileExact
等函数替换为相应的模糊计算函数,可以牺牲 1% - 2% 的精度以显著提升查询效率:
若所有大查询均无法再被优化了,则考虑让大查询的用户的数据迁移到单独集群,并在本集群设置 max_execution_time
等限制参数。
指标含义: 集群所有查询的成功率,反映是否有大面积超时和 SQL 语法错误,越低表示健康情况越差。
评分阈值:
健康 | 及格 | 不及格 | 危险 |
---|---|---|---|
(99,100] | (95,99] | (90,95] | <95 |
优化建议: