0.背景
在公司为验证是否满足使用需求,我测试了单节点clickhouse的性能表现。文章内容屏蔽了公司业务相关内容,不涉及商业秘密,只为学术分享、交流。
1.测试目标
本次测试是对Clickhouse在内存测试数据读写场景开展性能的验证与评估,通过采集写入耗时、查询耗时、数据压缩比等指标,确认单节点Clickhouse在TB级别的数据读写场景下的最优性能是否满足要求,并输出该性能场景下的最优配置方案。
2.测试用例设计
2.1测试场景
- 场景一:单表独立写入
各测试用例采用固定批量大小写入单个表。
- 场景二:模拟真实业务多表混合写入
各测试用例采用多类型结构化数据混合写入多个不同的表,不同表数据写入分别使用 100 万、200 万、300 万、400 万的批量大小提交。
-
数据总量:选择1000 万、1 亿、10 亿、100 亿几种数量级;
-
批量数:测试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 写入数据
- 客户端
采用Java语言基于Clickhouse Client Api开发客户端程序,以流式方式接收并写入构造数据,指定写入格式为 RowBinary(ClickHouse 最高效写入格式)。
- 并发写入模型
基于线程池实现并发写入以提升性能,采用固定大小线程池(线程数依据服务器 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 与写入客户端尽量分离部署,避免资源竞争;同时可适当增加服务端与客户端可用资源,进一步提升写入性能。