挖掘单节点Clickhouse极致性能上限

0.背景

在公司为验证是否满足使用需求,我测试了单节点clickhouse的性能表现。文章内容屏蔽了公司业务相关内容,不涉及商业秘密,只为学术分享、交流。

1.测试目标

本次测试是对Clickhouse在内存测试数据读写场景开展性能的验证与评估,通过采集写入耗时、查询耗时、数据压缩比等指标,确认单节点Clickhouse在TB级别的数据读写场景下的最优性能是否满足要求,并输出该性能场景下的最优配置方案。

2.测试用例设计

2.1测试场景

  1. 场景一:单表独立写入

各测试用例采用固定批量大小写入单个表。

  1. 场景二:模拟真实业务多表混合写入

各测试用例采用多类型结构化数据混合写入多个不同的表,不同表数据写入分别使用 100 万、200 万、300 万、400 万的批量大小提交。

  1. 数据总量:选择1000 万、1 亿、10 亿、100 亿几种数量级;

  2. 批量数:测试50万、100 万、500 万、1000 万几种数量级下性能的不同表现;

2.2 测试量级设定

数据总量级:1000 万、1 亿、10 亿、100 亿

写入批量大小:50 万、100 万、500 万、1000 万

2.3 测试数据

测试用的单一表数据包含以下内容:

{Id UInt64,group UInt8,back UInt8,flag UInt8,row UInt8,dt String}

另外一个表数据包含以下内容:

{Id UInt64,max UInt8,min UInt8,dt String}

其他表模拟数据类似。

3.测试环境

|--------------|------------|
| Clickhouse版本 | 26.3.3.20 |
| Java版本 | OpenJDK 21 |
| 系统总内存 | 135G |
| CPU核数 | 72 |

4.测试方法

4.1 生成数据

基于Java程序循环生成标准结构化的数据,并将拼接成字节流;针对上述两种测试场景,分别实现单一命令数据生成和多种命令数据生成两种方式,支持按指定批量大小异步提交写入。

4.2 写入数据

  1. 客户端

采用Java语言基于Clickhouse Client Api开发客户端程序,以流式方式接收并写入构造数据,指定写入格式为 RowBinary(ClickHouse 最高效写入格式)。

  1. 并发写入模型

基于线程池实现并发写入以提升性能,采用固定大小线程池(线程数依据服务器 CPU 核心数设定),并行提交多个二进制数据流;通过 CountDownLatch 同步控制,等待所有写入任务执行完成后结束测试。

4.3 测试指标

1. 写入耗时

统计从程序启动至所有数据完全写入成功的总耗时。。

2. 查询耗时

通过 clickhouse-client 执行标准测试 SQL,统计查询执行耗时。

3.数据总空间、压缩空间和压缩比

通过查询 ClickHouse 系统表 system.parts 获取数据原始大小、压缩后占用空间,并计算压缩比。

4.4 配置优化

针对机器的72CPU,135G内存,配置项做了如下优化:

配置项 说明

|----------------------------------------|-------------|--------------------------|
| 配置项 | 建议值 | 说明 |
| max_threads | 60 | 单个查询最大线程数 |
| max_insert_threads | 60 | 写入最大线程数 |
| max_memory_usage | 42949672960 | 最大使用内存量40G |
| background_pool_size | 5 | 后台合并任务线程池大小,CPU资源优先供写入使用 |
| max_insert_block_size_rows | 100000 | 写入数据时每个块的最大行数,官方建议配置 |
| max_insert_block_size_bytes | 1073741824 | 写入缓冲区大小1G |
| async_insert | 1 | 启用异步落盘 |
| allow_suspicious_low_cardinality_types | 1 | 允许使用LowCardinary数据类型 |

5. 测试结果与分析

5.1 资源利用率分析

测试环境服务器配置为CPU72核,内存135GB,性能测试之前,系统空闲内存约100G左右。测试程序的JVM参数为-Xms30G -Xmx70G,最大使用内存为70G,既保障数据写入过程内存充足,避免 OOM,同时为 clickhouse-server 及系统其他进程预留足够内存资源。当写入线程数设置为60 且全部运行时,服务器 CPU 利用率可达90% 以上 ,CPU 资源已接近性能瓶颈。60 线程并发条件下,内存占用随单次写入批量大小变化:批量 50 万、100 万时内存资源充足;批量增至 1000 万时,内存使用率约83.3% ;批量提升至 2000 万时,程序出现 Java heap space 堆内存溢出异常。可见,当前服务器环境下,数据写入程序60 线程 + 1000 万批量已接近资源上限。

5.2 瓶颈分析

CPU决定数据写入线程的并行度,内存决定数据单次处理量。数据量在1亿的时候,写入无明显瓶颈,CPU 与内存资源充裕;数据量达到 10 亿及以上时,写入线程数超过 60 则 CPU 出现瓶颈,内存占用随单次写入量递增,1000 万批量下达到内存上限。综上,写入性能可随节点资源扩容进一步提升;另外,由于Clickhouse-server和写入客户端在同个节点上,资源有一定的争抢,在一定程序上降低了数据写入性能。

5.3 压缩效果分析

在显式声明使用ZSTD的压缩算法之前,Clickhouse数据的压缩率大概在6~9之间,压缩效果一般。建表的时候声明某些字段使用ZSTD压缩算法,压缩率可达30左右,压缩效果良好。

5.4 查询性能分析

性能分析该查询的性能跟检索的数据条目数直接相关。检索2万条的时候,对于总数据量在1000万、1亿、十亿、百亿的情况下,耗时在0.03秒左右。表明查询性能与实际检索的数据条目数直接相关,总数量对性能几乎无影响。

5.5 结论与建议

在 72核、135GB 内存的单节点环境下,ClickHouse 借助多线程并发,在10 亿级数据写入 时仍保持良好性能,可在 30~40 秒内完成;数据量达到百亿级 时,CPU 与内存均达到瓶颈,总耗时约 6 分钟。测试结果表明,单节点 ClickHouse 写入性能优异,且可通过扩容系统资源进一步提升,适用于生产环境中10 亿级(约 50GB)秒级写入百亿级(约 300GB)分钟级写入 场景。实际应用中,合理配置并发线程数、批量大小及写入块大小等参数,可进一步优化写入性能。对于 MergeTree 引擎,按 ORDER BY 排序后,查询性能主要取决于实际检索数据量 。2 万条数据的分组统计查询耗时仅 20~30 毫秒,性能满足业务需求。实际部署建议:ClickHouse Server 与写入客户端尽量分离部署,避免资源竞争;同时可适当增加服务端与客户端可用资源,进一步提升写入性能。

相关推荐
程序员杰哥1 小时前
接口自动化测试:多环境配置实战
自动化测试·软件测试·python·测试工具·职场和发展·测试用例·接口测试
Reisentyan1 小时前
[Pro]GoLang Learn Data Day 5
开发语言·后端·golang
zhangfeng11331 小时前
华为昇腾910A NPU 的模型加密方案 ASCEND-CC
开发语言·人工智能·神经网络·transformer
zh路西法1 小时前
【OpenCV无人机光流速度估计】基于Farneback稠密光流方法的无人机速度估计
人工智能·python·opencv·计算机视觉·无人机
聆风吟º1 小时前
【Python编程日志】Python基础语法:常量 | 表达式 | 变量
开发语言·python·变量·常量·表达式
weixin_468466851 小时前
Airtable 零基础快速上手与实战指南
数据库·人工智能·python·深度学习·ai·大模型
凯瑟琳.奥古斯特1 小时前
10道数据库原理精选题
开发语言·数据库·职场和发展·数据库开发
z落落1 小时前
C# Stack栈 / Queue队列+所有集合 终极一页汇总(全覆盖、零遗漏)
java·开发语言·c#
skywalk81631 小时前
设计和实现一门中文编程语言,有什么工具可以使用吗?是不是ANTLR 和LLVM都可以使用?Racket恐怕不适用吧
开发语言·编程