ClickHouse 实时分析(九)- ClickHouse 常规优化方案
1. 数据类型优化
1.1 时间字段的类型
建表时能用数值型或日期时间型表示的字段就不要用字符串,全 String 类型在以 Hive 为中心的数仓建设中常见,但 ClickHouse 环境不应受此影响。
虽然 ClickHouse 底层将 DateTime 存储为时间戳 Long 类型,但不建议存储 Long 类型,因为DateTime不需要经过函数转换处理,执行效率高、可读性好
。
1 | create table t_type( |
1.2 空值存储类型
官方已经指出 Nullable 类型几乎总是会拖累性能,因为存储 Nullable 列时需要创建一个额外的文件来存储 NULL 的标记,并且 Nullable 列无法被索引。因此除非极特殊情况,应直接使用字段默认值表示空,或者自行指定一个在业务中无意义的值
(例如用 -1 表示没有商品 ID)。
1 | CREATE TABLE t_null |
查看存储的文件:
官方说明:https://clickhouse.com/docs/zh/sql-reference/data-types/nullable/
2. 分区和索引
分区粒度根据业务特点决定,不宜过粗或过细。一般选择按天分区
,也可以指定为 Tuple(),以单表一亿数据为例,分区大小控制在 10-30 个为最佳。
必须指定索引列,ClickHouse 中的索引列即排序列
,通过order by
指定,一般在查询条件中经常被用来充当筛选条件的属性被纳入进来;可以是单一维度,也可以是组合维度的索引;通常需要满足高级列在前、查询频率大的在前
原则;还有基数特别大的不适合做索引列,如用户表的 userid 字段;通常筛选后的数据满足在百万以内为最佳。
3. 表参数
Index_granularity 是用来控制索引粒度的,默认是 8192,如非必须不建议调整。
如果表中不是必须保留全量历史数据,建议指定 TTL(生存时间值),可以免去手动过期历史数据的麻烦,TTL 也可以通过 alter table 语句随时修改(TTL 可参考《ClickHouse实时分析(四)- ClickHouse表引擎详解》)。
4. 写入和删除优化
尽量不要执行单条或小批量删除和插入操作,这样会产生小分区文件,给后台 Merge 任务带来巨大压力。
不要一次写入太多分区,或数据写入太快,数据写入太快会导致 Merge 速度跟不上而报错,一般建议每秒钟发起 2-3 次写入操作,每次操作写入 2w~5w 条数据(依服务器性能而定)。
写入过快,报错信息如下:
1 | Code: 252, e.displayText() = DB::Exception: Too many parts(304). Merges are processing significantly slower than inserts |
处理方式:
“ Too many parts 处理 ” :使用 WAL 预写日志,提高写入性能,in_memory_parts_enable_wal
默认为 true。
在服务器内存充裕的情况下增加内存配额,一般通过max_memory_usage
来实现在服务器内存不充裕的情况下,建议将超出部分内容分配到系统硬盘上,但会降低执行速度,一般通过 max_bytes_before_external_group_by
、max_bytes_before_external_sort
参数来实现。
5. 常见配置
ClickHouse 极简化的设计方式,使得这些配置项相比其他数据库是得到非常多的精简的。并且大部分的配置信息,ClickHouse 也都给出了默认值,大部分场景下,这些默认值都是最优化的。例如,对于内存,ClickHouse 并不像 Flink 这类框架一样, 设定框架内存、任务内存等等各种各样的内存参数。只在users.xml
中设定了单个任务使用的内存上限,设置的值也是简单粗暴的10000000000 ,10G。具体配置在users.xml
中的<max_memory_usage>
参数。
ClickHouse 的配置项主要在 config.xml 或 users.xml 中:
- config.xml 的配置项
- users.xml 的配置项
其中config.xml
主要是服务端参数,主要包含一些在 session 和 query 级别无法修改的参数,例如服务的集群配置,zookeeper 配置等。而users.xml
则是运行时参数,大部分可能对 session 和 query 产生影响。当然,这种拆分方式在 ClickHouse 中其实并不是很严格。
对于运行时参数,有几个地方可以配置,读取的优先级依次如下:
users.xml配置文件
。主要配置在标签中,以不同配置文件的方式进行配置。默认提供了一个 default 的 profile。另外,ClickHouse 也可以自行指定外部的配置文件,具体参考https://clickhouse.com/docs/zh/operations/configuration-files/#configuration_files;Session配置
。在一个客户端中执行SET [settings] = [value]
语句的方式指定。只对当前会话生效;查询时指定
。查询时可以有多个方式指定参数。HTTP 接口可以直接在后面添加参数。使用clickhouse-client
脚本的--settings=value
参数方式指定,或者在 select 语句中直接指定;
5.1 CPU资源
对于 ClickHouse 的配置优化,最为重要的,也就是对服务资源分配的优化。而对于 ClickHouse 来说,消耗最多的系统资源其实就是 CPU,CPU 使用率也是对 ClickHouse 服务进行监控的一个很重要的指标。CPU 使用率一般达到 50% 左右会出现查询波动,达到 70% 会出现大范围的查询超时。所以通常建议 ClickHouse 服务要进行单独的部署,尽量不要跟其他服务共用服务器。
相比而言,对于内存和磁盘, 由于 ClickHouse 的数据压缩效率是非常高的,所以通常不会形成性能瓶颈。
配置 | 描述 |
---|---|
background_pool_size | 后台线程池的大小,merge 线程就是在该线程池中执行,该线程池不仅仅是给 merge 线程用的,默认值 16,允许的前提下建议改成cpu个数的2倍(线程数) |
background_schedule_pool_size | 执行后台任务(复制表、Kafka 流、DNS 缓存更新)的线程数。默认 128,建议改成 cpu 个数的 2 倍(线程数) |
background_distributed_schedule_pool_size | 设置为分布式发送执行后台任务的线程数,默认 16,建议改成cpu个数的2倍(线程数) 。 |
max_concurrent_queries | 最大并发处理的请求数(包含 select,insert 等),默认值 100,推荐150(不够再加)~300 。 |
max_threads | 设置单个查询所能使用的最大 cpu 个数,默认是 cpu 核数 |
5.2 内存资源
配置 | 描述 |
---|---|
max_memory_usage | 此参数在 users.xml 中,表示单次 Query 占用内存最大值,该值可以设置的比较大,这样可以提升集群查询的上限。 保留一点给 OS,比如 128G内存的机器,设置为100GB |
max_bytes_before_external_group_by | 一般按照 max_memory_usage 的一半设置内存,当 group 使用内存超过阈值后会刷新到磁盘进行。 因为 clickhouse 聚合分两个阶段:查询并及建立中间数据、合并中间数据, 结合上一项,建议 50GB |
max_bytes_before_external_sort | 当 order by 已使用 max_bytes_before_external_sort 内存就进行溢写磁盘(基于磁盘排序),如果不设置该值,那么当内存不够时直接抛错,设置了该值 order by 可以正常完成,但是速度相对存内存来说肯定要慢点(实测慢的非常多,无法接受) |
max_table_size_to_drop | 此参数在 config.xml 中,应用于需要删除表或分区的情况,默认是50GB,意思是如果删除 50GB 以上的分区表会失败。建议修改为0 ,这样不管多大的分区表都可以删除 |
5.3 存储
ClickHouse 不支持设置多数据目录,为了提升数据 IO 性能,可以挂载虚拟券组,一个券组绑定多块物理磁盘提升读写性能,多数据查询场景 SSD 会比普通机械硬盘快 2-3 倍。
参考文献
【1】https://clickhouse.com/docs/zh/
【2】https://www.bilibili.com/video/BV1Yh411z7os?from=search&seid=4579023877699743987&spm_id_from=333.337.0.0
【3】https://clickhouse.com/docs/zh/