大数据工具——ClickHouse

一、基础概念

1、什么是ClickHouse

ClickHouse是俄罗斯的Yandex于2016年开源的一个用于联机分析(OLAP:Online Analytical Processing)的列式数据库管理系统(DBMS:Database Management System),简称CH , 主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。

ClickHouse是一个完全的列式数据库管理系统,允许在运行时创建表和数据库,加载数据和运行查询,而无需重新配置和重新启动服务器,支持线性扩展,简单方便,高可靠性,容错。它在大数据领域没有走 Hadoop 生态,而是采用 Local attached storage 作为存储,这样整个 IO 可能就没有 Hadoop 那一套的局限。它的系统在生产环境中可以应用到比较大的规模,因为它的线性扩展能力和可靠性保障能够原生支持 shard + replication 这种解决方案。它还提供了一些 SQL 直接接口,有比较丰富的原生 client。

2、ChickHouse相关基础

  1. 列式存储

相比于行式存储,列式存储在分析场景下有着许多优良的特性。

1)如前所述,分析场景中往往需要读大量行但是少数几个列。在行存模式下,数据按行连续存储,所有列的数据都存储在一个bloCK中,不参与计算的列在IO时也要全部读出,读取操作被严重放大。而列存模式下,只需要读取参与计算的列即可,极大的减低了IO cost,加速了查询。

2)同一列中的数据属于同一类型,压缩效果显著。列存往往有着高达十倍甚至更高的压缩比,节省了大量的存储空间,降低了存储成本。

3)更高的压缩比意味着更小的data size,从磁盘中读取相应数据耗时更短。

4)自由的压缩算法选择。不同列的数据具有不同的数据类型,适用的压缩算法也就不尽相同。可以针对不同列类型,选择最合适的压缩算法。

5)高压缩比,意味着同等大小的内存能够存放更多数据,系统cache效果更好。

官方数据显示,通过使用列存,在某些分析场景下,能够获得100倍甚至更高的加速效应。

  1. 向量化

ClickHouse不仅将数据按列存储,而且按列进行计算。传统OLTP数据库通常采用按行计算,原因是事务处理中以点查为主,SQL计算量小,实现这些技术的收益不够明显。但是在分析场景下,单个SQL所涉及计算量可能极大,将每行作为一个基本单元进行处理会带来严重的性能损耗:

1)对每一行数据都要调用相应的函数,函数调用开销占比高;

2)存储层按列存储数据,在内存中也按列组织,但是计算层按行处理,无法充分利用CPU cache的预读能力,造成CPU Cache miss严重;

3)按行处理,无法利用高效的SIMD指令;

ClickHouse实现了向量执行引擎(Vectorized execution engine),对内存中的列式数据,一个batch调用一次SIMD指令(而非每一行调用一次),不仅减少了函数调用次数、降低了cache miss,而且可以充分发挥SIMD指令的并行能力,大幅缩短了计算耗时。向量执行引擎,通常能够带来数倍的性能提升。

  1. 分片

ClickHouse的集群由分片 ( Shard ) 组成,而每个分片又通过副本 ( Replica ) 组成。这种分层的概念,在一些流行的分布式系统中十分普遍。例如,在Elasticsearch的概念中,一个索引由分片和副本组成,副本可以看作一种特殊的分片。如果一个索引由5个分片组成,副本的基数是1,那么这个索引一共会拥有10个分片 ( 每1个分片对应1个副本 )。

如果你用同样的思路来理解ClickHouse的分片,那么很可能会在这里栽个跟头。ClickHouse的某些设计总是显得独树一帜,而集群与分片就是其中之一。这里有几个与众不同的特性。

ClickHouse的1个节点只能拥有1个分片,也就是说如果要实现1分片、1副本,则至少需要部署2个服务节点。

分片只是一个逻辑概念(类似于Hbase中的region的概念,表的范围数据),其物理承载还是由副本承担的。

二、表引擎分类

引擎分类 引擎名称
MergeTree系列 MergeTree 、ReplacingMergeTree 、SummingMergeTree 、 AggregatingMergeTree CollapsingMergeTree 、 VersionedCollapsingMergeTree 、GraphiteMergeTree
Log系列 TinyLog 、StripeLog 、Log
Integration Engines Kafka 、MySQL、ODBC 、JDBC、HDFS
Special Engines Distributed 、MaterializedView、 Dictionary 、Merge 、File、Null 、Set 、Join 、 URL View、Memory 、 Buffer

1、Log系列表引擎

Log系列表引擎的特点

共性特点

  • 数据存储在磁盘上
  • 当写数据时,将数据追加到文件的末尾
  • 不支持并发读写,当向表中写入数据时,针对这张表的查询会被阻塞,直至写入动作结束
  • 不支持索引
  • 不支持原子写:如果某些操作(异常的服务器关闭)中断了写操作,则可能会获得带有损坏数据的表
  • 不支持ALTER操作(这些操作会修改表设置或数据,比如delete、update等等)

区别

  • TinyLog

    TinyLog是Log系列引擎中功能简单、性能较低的引擎。它的存储结构由数据文件和元数据两部分组成。其中,数据文件是按列独立存储的,也就是说每一个列字段都对应一个文件。除此之外,TinyLog不支持并发数据读取。

  • StripLog支持并发读取数据文件,当读取数据时,ClickHouse会使用多线程进行读取,每个线程处理一个单独的数据块。另外,StripLog将所有列数据存储在同一个文件中,减少了文件的使用数量。

  • Log支持并发读取数据文件,当读取数据时,ClickHouse会使用多线程进行读取,每个线程处理一个单独的数据块。Log引擎会将每个列数据单独存储在一个独立文件中

TinyLog表引擎使用

该引擎适用于一次写入,多次读取的场景。对于处理小批数据的中间表可以使用该引擎。值得注意的是,使用大量的小表存储数据,性能会很低。

CREATE TABLE emp_tinylog4 (emp_id UInt16 COMMENT '员工id',name String COMMENT '员工姓名',work_place String COMMENT '工作地点',age UInt8 COMMENT '员工年龄',depart String COMMENT '部门',salary Decimal32(2) COMMENT '工资') ENGINE=TinyLog();

INSERT INTO emp_tinylog4 VALUES (1,'tom','上海',25,'技术部',20000),(2,'jack','上海',26,'人事部',10000);
INSERT INTO emp_tinylog4 VALUES (3,'bob','北京',33,'财务部',50000),(4,'tony','杭州',28,'销售事部',50000);

进入默认数据存储目录,查看底层数据存储形式,可以看出:TinyLog引擎表每一列都对应的文件:

[root@node1 ~]# ll /data/clickhouse/clickhousedata/data/default/emp_tinylog/
total 28
-rw-r----- 1 root root  56 Sep 24 00:59 age.bin
-rw-r----- 1 root root  97 Sep 24 00:59 depart.bin
-rw-r----- 1 root root  60 Sep 24 00:59 emp_id.bin
-rw-r----- 1 root root  70 Sep 24 00:59 name.bin
-rw-r----- 1 root root  68 Sep 24 00:59 salary.bin
-rw-r----- 1 root root 185 Sep 24 00:59 sizes.json
-rw-r----- 1 root root  80 Sep 24 00:59 work_place.bin

## 在sizes.json文件内使用JSON格式记录了每个.bin文件内对应的数据大小的信息
## 查看sizes.json数据
[root@node1 ~]# cat /data/clickhouse/clickhousedata/data/default/emp_tinylog/sizes.json
{"yandex":{"age%2Ebin":{"size":"56"},"depart%2Ebin":{"size":"97"},"emp_id%2Ebin":{"size":"60"},"name%2Ebin":{"size":"70"},"salary%2Ebin":{"size":"68"},"work_place%2Ebin":{"size":"80"}}}

当我们执行ALTER操作时会报错,说明该表引擎不支持ALTER操作

node1 :) ALTER TABLE emp_tinylog4 DELETE WHERE emp_id = 5;

ALTER TABLE emp_tinylog
    DELETE WHERE emp_id = 5

Received exception from server (version 20.5.2):
Code: 48. DB::Exception: Received from localhost:9009. DB::Exception: Mutations are not supported by storage TinyLog.
StripeLog表引擎

相比TinyLog而言,StripeLog拥有更高的查询性能(拥有.mrk标记文件,支持并行查询),同时其使用了更少的文件描述符(所有数据使用同一个文件保存)。

--创建StripeLog表
CREATE TABLE emp_stripelog4 (emp_id UInt16 COMMENT '员工id',name String COMMENT '员工姓名',work_place String COMMENT '工作地点',age UInt8 COMMENT '员工年龄',depart String COMMENT '部门',salary Decimal32(2) COMMENT '工资') ENGINE=StripeLog;

-- 插入数据  
INSERT INTO emp_stripelog4 VALUES (1,'tom','上海',25,'技术部',20000),(2,'jack','上海',26,'人事部',10000);
INSERT INTO emp_stripelog4 VALUES (3,'bob','北京',33,'财务部',50000),(4,'tony','杭州',28,'销售事部',50000);
-- 查询数据
-- 由于是分两次插入数据,所以查询时会有两个数据块
select * from emp_stripelog;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│      1 │ tom  │ 上海       │  25 │ 技术部 │ 20000.00 │
│      2 │ jack │ 上海       │  26 │ 人事部 │ 10000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart───┬───salary─┐
│      3 │ bob  │ 北京       │  33 │ 财务部   │ 50000.00 │
│      4 │ tony │ 杭州       │  28 │ 销售事部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴──────────┴──────────┘

进入默认数据存储目录,查看底层数据存储形式

[root@node1 ~]# ll /data/clickhouse/clickhousedata/data/default/emp_stripelog/
total 12
-rw-r----- 1 root root 673 Sep 24 01:07 data.bin
-rw-r----- 1 root root 281 Sep 24 01:07 index.mrk
-rw-r----- 1 root root  69 Sep 24 01:07 sizes.json

可以看出StripeLog表引擎对应的存储结构包括三个文件:

  • data.bin:数据文件,所有的列字段使用同一个文件保存,它们的数据都会被写入data.bin。
  • index.mrk:数据标记,保存了数据在data.bin文件中的位置信息(每个插入数据块对应列的offset),利用数据标记能够使用多个线程,以并行的方式读取data.bin内的压缩数据块,从而提升数据查询的性能。
  • sizes.json:元数据文件,记录了data.bin和index.mrk大小的信息

注:

1、StripeLog引擎将所有数据都存储在了一个文件中,对于每次的INSERT操作,ClickHouse会将数据块追加到表文件的末尾

2、StripeLog引擎同样不支持ALTER UPDATEALTER DELETE 操作

Log表引擎

Log引擎表适用于临时数据,一次性写入、测试场景。Log引擎结合了TinyLog表引擎和StripeLog表引擎的长处,是Log系列引擎中性能最高的表引擎。

CREATE TABLE emp_log4 (emp_id UInt16 COMMENT '员工id',name String COMMENT '员工姓名',work_place String COMMENT '工作地点',age UInt8 COMMENT '员工年龄',depart String COMMENT '部门',salary Decimal32(2) COMMENT '工资')ENGINE=Log;
  
INSERT INTO emp_log4 VALUES (1,'tom','上海',25,'技术部',20000),(2,'jack','上海',26,'人事部',10000);
INSERT INTO emp_log4 VALUES (3,'bob','北京',33,'财务部',50000),(4,'tony','杭州',28,'销售事部',50000);
-- 查询数据,
-- 由于是分两次插入数据,所以查询时会有两个数据块
select * from emp_log;
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart─┬───salary─┐
│      1 │ tom  │ 上海       │  25 │ 技术部 │ 20000.00 │
│      2 │ jack │ 上海       │  26 │ 人事部 │ 10000.00 │
└────────┴──────┴────────────┴─────┴────────┴──────────┘
┌─emp_id─┬─name─┬─work_place─┬─age─┬─depart───┬───salary─┐
│      3 │ bob  │ 北京       │  33 │ 财务部   │ 50000.00 │
│      4 │ tony │ 杭州       │  28 │ 销售事部 │ 50000.00 │
└────────┴──────┴────────────┴─────┴──────────┴──────────┘

进入默认数据存储目录,查看底层数据存储形式

[root@node1 ~]# ll /data/clickhouse/clickhousedata/data/default/emp_log/
total 32
-rw-r----- 1 root root  56 Sep 24 01:11 age.bin
-rw-r----- 1 root root  97 Sep 24 01:11 depart.bin
-rw-r----- 1 root root  60 Sep 24 01:11 emp_id.bin
-rw-r----- 1 root root  96 Sep 24 01:11 __marks.mrk
-rw-r----- 1 root root  70 Sep 24 01:11 name.bin
-rw-r----- 1 root root  68 Sep 24 01:11 salary.bin
-rw-r----- 1 root root 215 Sep 24 01:11 sizes.json
-rw-r----- 1 root root  80 Sep 24 01:11 work_place.bin

Log引擎的存储结构包含三部分:

  • 列.bin:数据文件,数据文件按列单独存储
  • __marks.mrk:数据标记,统一保存了数据在各个.bin文件中的位置信息。利用数据标记能够使用多个线程,以并行的方式读取。.bin内的压缩数据块,从而提升数据查询的性能。
  • sizes.json:记录了.bin和__marks.mrk大小的信息

注:

Log表引擎会将每一列都存在一个文件中,对于每一次的INSERT操作,都会对应一个数据块

你可能感兴趣的:(数据库,大数据)