Clickhouse: 从探索到应用

本文详细介绍了Clickhouse的探索与应用,重点讨论了其在OLAP场景中的技术验证,包括数据同步、批量写入、临时文件管理和性能测试,以及如何在实际环境中搭建和优化集群。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Clickhouse: 从探索到应用

前言

2019年到现在,忙忙碌碌,终于有了一些空闲,开始梳理做的事情,也开始思索职业生涯,记录下一些探索和尝试。前作 使用docker搭建zookeeper集群使用docker搭建clickhouse 实际为本文探索时的记录,如您需要快捷搭建对应的服务,请移步查看。

背景

截止到本文发表的时间,Cloudera CDH 依然是公司技术架构中最繁重的组件,无论是从部署的角度,亦或维护的复杂度上来说。由于在后期维护项目时,占用了过多的人力成本,经过多方探讨,公司下定决心寻找一个在项目中最节省成本的替代品。近两年 Clickhouse 的应用越来越广,呼声也越来越高,于是初步选定使用 Clickhouse 作为替代品,而由于在公司工作的大部分时间忙于在各个产品之间救火,所以对各个产品的业务都有所了解,于是受命开始探索 Clickhouse 在公司落地的可行性。

准备

盲干不是一个合格的探索者,需要要结合公司整体业务情况,确认好研究方向,以及期望输出的调研结果。由于业务属于敏感信息,此处略过,仅做技术交流。

本文的应用场景基本符合 Clickhouse OLAP场景的关键特征 ,如您也对 Clickhouse感兴趣,请结合业务要求和 Clickhouse 数据库的优缺点,来决定是否应该在此问题上做一些尝试。

搭建 zookeeper 集群

参考 使用 docker 搭建 zookeeper 集群

搭建 clickhosue 集群

参考 使用 docker 搭建 clickhouse集群

技术验证

此部分内容有较多通过阅读 Clickhouse源码 得到结论,如有谬误,还请指正

深入挖掘 ReplicatedMergeTree 引擎

一句话总结:不适合少量多次写入数据库,需要结合业务来选择合适的批量插入条数和频率

Clickouse 在执行 INSERT 语句时,会先将数据写入临时文件,同时有任务会自动将临时文件转储到数据目录。请注意每次执行 INSERT 语句,会生成 字段数量 * 2 + 3 个临时文件,每个字段在临时目录中对应一个 字段.bin和一个 字段.mrk2 文件,同时还有 checksums.txtcolumns.txtcount.txt三个文件。因此请批量写入数据,否则磁盘寿命将大大降低,同时如果生成的临时文件过多,在转储时,会占用大量的系统资源。因此,建议在数据写入的时效性,和性能之间做个取舍。

字段名称.bin : 数据文件

字段.mrk2 : 索引文件

checksums.txt : 数据完整性验证

columns.txt : 表字段信息

count.txt : 插入的数据条数

批量写入

单个临时文件的大小默认被限制为 10M,如果单次插入的数据量比较大,将会被拆分为多个临时文件,因此需要根据实际数据情况选择合适的插入数量。

数据同步

采用 ReplicatedMergeTree 引擎的表,每个replica 节点都会去检测其他节点的数据状态,如果发生数据缺失,会尝试从其他节点恢复,并且每隔 3至30秒 将自身的状态同步至 zookeeper,否则将开始 数据恢复 ,直至数据状态和其他节点一致。

临时文件

由于 Clickhouse 没有事务,所以在临时文件转储时,使用 共享锁 (通过 zokeeper 进行状态交换),临时文件转储任务的优先级低于数据写入任务。每个 replica 节点都会去检测其他节点的数据状态,当状态一致时,才会开始转储临时文件,所以如果单次插入的数据量较小,会积压非常多的临时文件,因此也需要根据数据写入的频率,预留足够的磁盘空间。

写入测试

创建表
-- 创建数据库
CREATE DATABASE IF NOT EXISTS test;
-- 创建表
CREATE TABLE IF NOT EXISTS test.test_table (
  ts UInt64 , day Date ,
  field_1 Float64 , field_2 Float64 , field_3 Float64 , 
  field_4 Float64 , field_5 Float64 , field_6 Float64 ,
  field_7 Float64 , field_8 Float64 , field_9 Float64 ,
  field_10 Float64 , field_11 String , field_12 String , 
  field_13 String , field_14 String , field_15 String , 
  field_16 String , field_17 String , field_18 String , 
  field_19 String , field_20 String 
) ENGINE = ReplicatedMergeTree('/clickhouse/cluster/tables/{shard}/test_table', '{replica}')
  PARTITION BY day
  ORDER BY  (ts, day)
  SETTINGS index_granularity = 8192;
插入数据

准备一个 100W 行数据的 test_data.csv,字段和此前创建的表一致。

导入csv

可以利用 clickhouse-client 导入 csv 数据文件。

请注意 单次 SQL 执行默认有 3600s 超时限制,对应 /etc/clickhouse-server/config.xmlmax_session_timeout 的配置

# test_data.csv 包含表头
# 如文件过大,可以使用 --max_insert_block_size=100000 参数来限制单次插入的大小
clickhouse-client --user=root --password=123456 --query "INSERT INTO test.test_table FORMAT CSVWithNames" < test_data.csv

system.query_log 表中记录每次 SQL 执行的记录(此功能默认开启,不建议关闭)

select databases, tables, written_rows, query_duration_ms 
from query_log 
where query_kind ilike 'INSERT' 
order by event_time desc 
limit 10;

查询结果如下,从结果中可以看到,插入 100W 条数据,合计耗时 299782ms

彩蛋:插入性能会随磁盘性能和机器配置的提高而大幅提高

┌─databases─┬─tables──────────────┬─written_rows─┬─query_duration_ms─┐
│ ['test']  │ ['test.test_table'] │      1000000 │            299782 │
└───────────┴─────────────────────┴──────────────┴───────────────────┘
clickhouse-benchmark

可以使用 clickhouse-benchmark 测试 clickhouse 数据库的性能

请注意:在 SQL 语句中无筛选条件时,Clickhouse 中 count(*)count(固定值) 不会扫描数据文件,而是返回对应数据表目录下 count.txt 中的值

# 在 SQL 语句中无筛选条件时,返回对应数据表目录下 count.txt 中的值,如下
echo "select count(*) from test.test_table" | clickhouse-benchmark -i 10
# 调整后的 SQL 语句
echo "select count(*) from test.test_table where day = '2021-03-29' " | clickhouse-benchmark -i 10

示例输出如下

Loaded 1 queries.

Queries executed: 10.

localhost:9000, queries 10, QPS: 224.143, RPS: 224.143, MiB/s: 0.877, result RPS: 224.143, result MiB/s: 0.002.

0.000%		0.004 sec.
10.000%		0.004 sec.
20.000%		0.004 sec.
30.000%		0.004 sec.
40.000%		0.004 sec.
50.000%		0.005 sec.
60.000%		0.005 sec.
70.000%		0.005 sec.
80.000%		0.005 sec.
90.000%		0.005 sec.
95.000%		0.006 sec.
99.000%		0.006 sec.
99.900%		0.006 sec.
99.990%		0.006 sec.

负载均衡

可以使用 nginx 实现负载均衡,在 nginx.conf 中添加如下配置,更多关于 upstream 的说明请参考 Module ngx_http_upstream_module

个人认为在 Clickhouse 的应用场景中,使用 轮询模式 来实现负载均衡是一个比较好的选择,可以避免单节点负载较高的场景出现

# 请自行添加 hosts 配置
stream {
    upstream clickhouse-9000 {
        # 可以根据服务器配置设置不同的权重
        server ch-server1:9000 weight=1 max_fails=3 fail_timeout=30s;
        server ch-server2:9000 weight=1 max_fails=3 fail_timeout=30s;
        server ch-server3:9000 weight=1 max_fails=3 fail_timeout=30s;
        server ch-server4:9000 weight=1 max_fails=3 fail_timeout=30s;
    }
            
    server{
        listen 9000;
        server_name localhost;
        proxy_pass clickhouse-9000;
    }

    upstream clickhouse-8123 {
        # 可以根据服务器配置设置不同的权重
        server ch-server1:8123 weight=1 max_fails=3 fail_timeout=30s;
        server ch-server2:8123 weight=1 max_fails=3 fail_timeout=30s;
        server ch-server3:8123 weight=1 max_fails=3 fail_timeout=30s;
        server ch-server4:8123 weight=1 max_fails=3 fail_timeout=30s;
    }

    server{
        listen 8123;
        server_name localhost;
        proxy_pass clickhouse-8123;
    }
}

总结

彩蛋:使用4台 2Core 8G 云服务器,写入 100W 条数据仅需 3 秒,请多做尝试。

综上,Clickhouse 是一个性能优异的适用于 OLAP场景 的数据库,但其由于无事务机制,在集群模式下采用共享锁来实现数据同步,从而限制了其在集群模式下的应用场景不适合实时写入,在写入时生成的临时文件也是一个不可忽略的细节。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值