一、基础概念
Clickhouse由俄罗斯Yandex公司开源的数据库,专为OLAP而设计。 Yandex是俄罗斯最大的搜索引擎公司,官方宣称ClickHouse 日处理记录数”十亿级”。
发布之初跑分要超过很多流行的商业MPP数据库软件,对标老东家HP的Vertica和GP 官方的性能测试显示比vertica快5倍,比GP快10倍。
但是:
clickhouse直接可以安在各种版本的Linux系统上,macos可以通过docker来安装 官方没有提供设计和架构文档,只有开源的C++源码 不理睬Hadoop生态,走自己的路
目前国内社区火热,各个大厂纷纷跟进大规模使用:
- 今日头条 内部用ClickHouse来做用户行为分析,内部一共几千个ClickHouse节点,单集群最大1200节点,总数据量几十PB,日增原始数据300TB左右。
- 腾讯 内部用ClickHouse做游戏数据分析,并且为之建立了一整套监控运维体系。
- 携程 内部从18年7月份开始接入试用,目前80%的业务都跑在ClickHouse上。每天数据增量十多亿,近百万次查询请求。
- 快手 内部也在使用ClickHouse,存储总量大约10PB, 每天新增200TB, 90%查询小于3S。
ClickHouse 是一个用于联机分析(OLAP)的列式数据库管理系统(DBMS)。
两个概念:
1)OLTP与OLAP:
- OLTP:是传统的关系型数据库,主要操作增删改查,强调事务一致性,比如银行系统、电商系统。
- OLAP:是仓库型数据库,主要是读取数据,做复杂数据分析,侧重技术决策支持,提供直观简单的结果。
2)DBMS:
- 具有DDL(数据定义语言):可以动态地创建、修改或删除数据库、表和视图,而无须重启服务。
- ·具有DML(数据操作语言):可以动态查询、插入、修改或删除数据。 ·
- 权限控制:可以按照用户粒度设置数据库或者表的操作权限,保障数据的安全性。 ·
- 数据备份与恢复:提供了数据备份导出与导入恢复机制,满足生产环境的要求。
- ·分布式管理:提供集群模式,能够自动管理多个数据库节点。
以上表明为什么 Click House 称得上是 DBMS 。
二、架构与安装
目前ClickHouse公开的资料相对匮乏,比如在架构设计层面就很难找到完整的资料,甚至连一张整体的架构图都没有。我想这就是它为何身为一款开源软件,但又显得如此神秘的原因之一吧。即便如此,我们还是能从一些零散的材料中找到一些蛛丝马迹。接下来会说明ClickHouse底层设计中的一些概念,这些概念可以帮助我们了解ClickHouse。
安装
ubuntu安装指南: ubuntu安装ck指南
网页版查询工具TABIX:ui.tabix.io
客户端查询工具:DBeaver
Tips: 客户端和网页版查询ClickHouse时,需要开启远程登录。在安装guide有具体步骤。clickhouse的jdbc connector包需要编译,比较麻烦,建议使用dbeaver,第一次连接的时候会自动编译最新的jar包。
三、clickhouse引擎
4.1 数据库引擎
-
延时引擎Lazy
在距最近一次访问间隔
expiration_time_in_seconds
时间段内,将表保存在内存中,仅适用于 *Log引擎表由于针对这类表的访问间隔较长,对保存大量小的 *Log引擎表进行了优化,
CREATE DATABASE testlazy ENGINE = Lazy(expiration_time_in_seconds);
-
MySQL引擎
MySQL引擎用于将远程的MySQL服务器中的表映射到ClickHouse中,并允许对表进行
INSERT
和SELECT
查询,以方便在ClickHouse与MySQL之间进行数据交换。MySQL
数据库引擎会将对其的查询转换为MySQL语法并发送到MySQL服务器中,因此可以执行诸如SHOW TABLES
或SHOW CREATE TABLE
之类的操作。但是不能进行删除更新操作。CREATE DATABASE [IF NOT EXISTS] db_name [ON CLUSTER cluster] ENGINE = MySQL('host:port', ['database' | database], 'user', 'password')
-
默认的数据库引擎
默认情况下,ClickHouse使用自己的数据库引擎,该引擎提供可配置的表引擎和所有支持的SQL语法.
4.2 数据表引擎
表引擎(即表的类型)决定了:
- 数据的存储方式和位置,写到哪里以及从哪里读取数据
- 支持哪些查询以及如何支持。
- 并发数据访问。
- 索引的使用(如果存在)。
- 是否可以执行多线程请求。
- 数据复制参数。
表引擎种类:
-
MergeTree
适用于高负载任务的最通用和功能最强大的表引擎。这些引擎的共同特点是可以快速插入数据并进行后续的后台数据处理。 MergeTree系列引擎支持数据复制(使用Replicated* 的引擎版本),分区和一些其他引擎不支持的其他功能。
这个引擎是 ClickHouse 的重头戏,它支持一个日期和一组主键的两层式索引,还可以实时更新数据。同时,索引的粒度可以自定义,外加直接支持采样功能。
而且,以这个引擎为基础,后面几种引擎都是在其基础之上附加某种特定功能而实现的“变种”。
使用这个引擎的形式如下:
MergeTree(EventDate, (CounterID, EventDate), 8192)
MergeTree(EventDate, intHash32(UserID), (CounterID, EventDate, intHash32(UserID)), 8192)
含义:
1) EventDate
一个日期的列名。
2) intHash32(UserID)
采样表达式。
3) (CounterID, EventDate)
主键组(里面除了列名,也支持表达式),也可以是一个表达式。
4) 8123
主键索引的粒度。
这个引擎是在 MergeTree 的基础上,添加了“处理重复数据”的功能,简直就是在多维数据加工流程中,为“最新值”,“实时数据”场景量身打造的一个引擎啊。这些场景下,如果重复数据不处理,你自己当然可以通过时间倒排,取最新的一条数据来达到目的,但是,至少这样会浪费很多的存储空间。
相比 MergeTree , ReplacingMergeTree 在最后加一个“版本列”,它跟时间列配合一起,用以区分哪条数据是“新的”,并把旧的丢掉(这个过程是在 merge
时处理,不是数据写入时就处理了的,平时重复的数据还是保存着的,并且查也是跟平常一样会查出来的,所以在 SQL 上排序过滤 Limit
什么的该写还是要写的)。同时,主键列组用于区分重复的行。
create table t (gmt Date, id UInt16, name String, point UInt16) ENGINE=ReplacingMergeTree(gmt, (name), 10, point);
像上面一样,“版本列”允许的类型是, UInt
一族的整数,或 Date
或 DateTime
。
insert into t (gmt, id, name, point) values ('2017-07-10', 1, 'a', 20);
insert into t (gmt, id, name, point) values ('2017-07-10', 1, 'a', 30);
insert into t (gmt, id, name, point) values ('2017-07-11', 1, 'a', 20);
insert into t (gmt, id, name, point) values ('2017-07-11', 1, 'a', 30);
insert into t (gmt, id, name, point) values ('2017-07-11', 1, 'a', 10);
插入这些数据,用 optimize table t
手动触发一下 merge
行为,然后查询:
select * from t;
\3. SummingMergeTree
ReplacingMergeTree 是替换数据, SummingMergeTree 就是在 merge 阶段把数据加起来了,当然,哪些列要加(一般是针对可加的指标)可以配置,不可加的列,会取一个最先出现的值。
建表:
create table ttt (gmt Date, name String, a UInt16, b UInt16) ENGINE=SummingMergeTree(gmt, (gmt, name), 8192, (a));
插入数据:
insert into ttt (gmt, name, a, b) values ('2017-07-10', 'a', 1, 2),
('2017-07-10', 'b', 2, 1),('2017-07-11', 'b', 3, 8),('2017-07-11', 'b', 3, 8),
('2017-07-11', 'a', 3, 1),('2017-07-12', 'c', 1, 3);
OPTIMIZE TABLE ttt 后查询的结果为:
\6. VersionedCollapsingMergeTree
-
日志
具有最小功能的轻量级引擎。当需要快速写入许多小表(最多约100万行)并在以后整体读取它们时,该类型的引擎是最有效的。
1.TinyLog
最简单的一种引擎,每一列保存为一个文件,里面的内容是压缩过的,不支持索引。
这种引擎没有并发控制,所以,当你需要在读,又在写时,读会出错。并发写,内容都会坏掉。
所以,它的应用场景,基本上就是那种只写一次,然后就是只读的场景。同时,它也不适用于处理量大的数据,官方推荐,使用这种引擎的表最多 100 万行的数据。
因为这种引擎的实现非常简单,所以当你有很多很多的小表数据要处理时,使用它是比较合适的,最基本的,它在磁盘上的文件量很少,读一列数据只需要打开一个文件就好了。
在 Yandex.Metrica 产品中,这种引擎用于小批量的中间数据处理上。
\2. StripeLog
\3. Log
这种引擎跟 TinyLog 基本一致,它的改进点,是加了一个 __marks.mrk
文件,里面记录了每个数据块的偏移,这种做的一个用处,就是可以准确地切分读的范围,从而使用并发读取成为可能。
但是,它是不能支持并发写的,一个写操作会阻塞其它读写操作。
Log 不支持索引,同时因为有一个 __marks.mrk
的冗余数据,所以在写入数据时,一旦出现问题,这个表就废了。
同 TinyLog 差不多,它适用的场景也是那种写一次之后,后面就是只读的场景,临时数据用它保存也可以。
-
集成引擎
用于与其他的数据存储与处理系统集成的引擎。
1.Kafka
\2. MySQL
\3. ODBC
\4. JDBC
\5. HDFS
- 用于其他特定功能的引擎
Merge 可以看成是单机版的 Distributed ,而真正的 Distributed 具备跨服务器能力,当然,机器地址的配置依赖配置文件中的信息。
与 Merge 类似, Distributed 也是通过一个逻辑表,去访问各个物理表,设置引擎时的样子是:
Distributed(remote_group, database, table [