clickHouse接入指南和排坑日记
clickHouse分区和分片详解
1. clickhouse简介和特点
ClickHouse是一个面向联机分析处理(OLAP)的开源的面向列式存储的DBMS,简称CK, 与Hadoop, Spark相比,ClickHouse很轻量级,由俄罗斯第一大搜索引擎Yandex于2016年6月发布, 开发语言为C++。
ClickHouse的特点:
- 开源的列存储数据库管理系统,支持线性扩展,简单方便,高可靠性
- 容错跑分快:比Vertica快5倍,比Hive快279倍,比MySQL快800倍,其可处理的数据级别已达到10亿级别;
- 功能多:支持数据统计分析各种场景,支持类SQL查询,异地复制部署
2. clickhouse表引擎
- MergeTree系列引擎,最常用也是最建议使用的,MergeTree在写入一批数据时,数据总会以数据片段的形式写入磁盘,且数据片段不可修改。为了避免片段过多,ClickHouse会通过后台线程,定期合并这些数据片段,属于相同分区的数据片段会被合成一个新的片段。这种数据片段往复合并的特点,也正是合并树名称的由来。MergeTree作为家族系列最基础的表引擎,主要有以下特点:
- 存储的数据按照主键排序:允许创建稀疏索引,从而加快数据查询速度;
- 支持分区,可以通过PRIMARY KEY语句指定分区字段;
- 支持数据副本
- 支持数据采样
- Log系列表引擎功能相对简单,主要用于快速写入小表(1百万行左右的表),然后全部读出的场景。即一次写入多次查询。其特点是数据存储在磁盘上,当写数据时,将数据追加到文件的末尾;
- 外部集成表引擎,ClickHouse提供了许多与外部系统集成的方法,包括一些表引擎。这些表引擎与其他类型的表引擎类似,可以用于将外部数据导入到ClickHouse中,或者在ClickHouse中直接操作外部数据源。目前ClickHouse提供了下面的外部集成表引擎:
- ODBC:通过指定odbc连接读取数据源
- JDBC:通过指定jdbc连接读取数据源;
- MySQL:将MySQL作为数据存储,直接查询其数据
- HDFS:直接读取HDFS上的特定格式的数据文件;
- Kafka:将Kafka数据导入ClickHouse
HDFS
使用方式
ENGINE = HDFS(URI, format)
URI:HDFS文件路径
format:文件格式,比如CSV、JSON、TSV等
使用示例
-- 建表
CREATE TABLE hdfs_engine_table(
emp_id UInt16 COMMENT '员工id',
name String COMMENT '员工姓名',
work_place String COMMENT '工作地点',
age UInt8 COMMENT '员工年龄',
depart String COMMENT '部门',
salary Decimal32(2) COMMENT '工资'
) ENGINE=HDFS('hdfs://cdh03:8020/user/hive/hdfs_engine_table', 'CSV');
3. 本地表
本地(local)表是实际存储数据的表,建表语句可以参考下面:
CREATE TABLE IF NOT EXISTS ka_10002538_f83b454416104dbfa083369f35759549.tmc_sms_url_click_local on cluster clickhouse_csig_smartretail_2_replica (`kaId` String, `create_time` String, `os` String, `ipCity` String, `ip` String, `dataType` String, `receive_time` Int64, `mobile` String, `contentId` String, `ipCountry` String, `batchId` String, `import_date` String, `path` String, `osVersion` String, `report_time` Int64, `domain` String, `browserVersion` String, `browser` String, `customerId` String, `ipProvince` String, `model` String, `tmcTenantId` String, `timestamp` Float64, `campaign` String, `campaignName` String) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/ka_10002538_f83b454416104dbfa083369f35759549/tmc_sms_url_click_local', '{replica}') PARTITION BY import_date ORDER BY import_date
主要就是注意ENGINE的选择,然后需要加上on cluster 方便后续和分布式表进行关联,这样只需要在集群内任何一个节点上执行ddl,集群内所有机器都会创建这张表。
4. 分布式表
分布式(Distributed)表引擎是分布式表的代名词,它⾃身不存储任何数据,⽽是作为数据分⽚的透明代理,能够⾃动的路由数据⾄集群中的各个节点,即分布式表需要和其他数据表⼀起协同⼯作。分布式表会将接收到的读写任务,分发到各个本地表,而实际上数据的存储也是保存在各个节点的本地表中。可以把分布式表当作分布式集群中各个分片间的nginx代理。分布式表创建方式如下:
CREATE TABLE IF NOT EXISTS ka_10002538_f83b454416104dbfa083369f35759549.tmc_sms_url_click
on cluster clickhouse_csig_smartretail_2_replica (`kaId` String,)
ENGINE = Distributed('clickhouse_csig_smartretail_2_replica',
'ka_10002538_f83b454416104dbfa083369f35759549',
'tmc_sms_url_click_local', rand())
主要使用ENGINE = Distributed(cluster, database, table, [sharding_key]);
-
cluster:集群名称,在对分布式表执⾏读写的过程中,它会使⽤集群的配置信息来找到相应的host节点;
-
database,table:数据库和本地表名称,用于将分布式表映射到本地表上;
-
sharding_key: 分⽚键,分布式表会按照这个规则,将数据分发到各个本地表中。
5. 写分布式表问题
- 写分布式表,会先分发到一个实例上,然后先先写到这个实例中并缓存起来,再逐渐分发到各个分片上去,实际是双写了数据(写入放大),浪费资源;
- 数据写入默认是异步的,短时间内可能造成不一致;
- 分布式表会进行数据的再次拆分,会产生较多的小parts,使merge(即compaction)过程压力增大,影响写入性能。
6.分布式表和本地表的使用
总结起来,最安全最方便的用法应该是查询的时候走分布式表,写入的时候通过一定的路由策略去写本地表。当然,如果涉及到复杂的join查询和性能升级,读的方式可能也要进行一定的优化,具体可以参考 clickHouse分区和分片详解