Clickhouse
简介
clickhouse是俄罗斯搜索公司 Yandex开源的一款分析型数据库,主要用于OLAP场景。clickhouse不兼容大数据领域的hadoop生态,但是以高性能,功能支持完备而有众多拥趸。广泛应用于商业智能,电信行业,以及电商商务,社交等场景。
clickhouse一直以性能出色著称,在10亿条数据量的情况下,clickhouse的单表聚合查询性能可以达到MySQL的将近1000倍。
clickhouse不支持事务,对行维度数据的查询,删除,更新能力支持一般。
clickhouse数据存储的基本单元和关系型数据库一致,都是表存储,其拥有完备的DBMS功能:
DDL:可以动态的创建,修改或者删除数据库、表以及视图
DML:可以动态的查询,插入,修改或者删除数据
权限控制,可以按照用户纬度设置数据库的库/表操作权限。
提供数据备份,恢复以及分布式集群管理模式。
原理
clickhouse的性能在同类型的MPP数据库中属于翘楚,得益于以下的设计。
列式存储
列式存储相较于行式存储,更方便数据压缩,而且对系统缓存也能更加高效的利用。Clickhouse默认采用LZ4压缩算法,该算法的压缩比可以得到8:1,但是性能高于一般的压缩算法。
列式存储也能够有效减少查询时候的扫描的数据量。
列式存储不支持select *等查询语法
向量化执行引擎
数据库查询执行最著名的是火山模型,也是在各种数据库系统中应用最广泛的模型。SQL查询在数据库中经过解析,会生成一棵查询树,查询数的每个节点为代数运算符(Operator)。火山模型把Operator看成迭代器,每个迭代器都会提供一个next() 接口。
一般Operator的next() 接口实现分为三步,
1.调用子节点Operator的next() 接口获取一行数据(tuple)
2.对tuple进行Operator特定的处理(如filter 或project 等)
3.返回处理后的tuple。
因此,查询执行时会由查询树自顶向下的调用next() 接口,数据则自底向上的被拉取处理。火山模型的这种处理方式也称为拉取执行模型(Pull Based)。
向量化执行依然采用类似火山模型的拉取式模型,唯一的区别是其Operator的next()函数每次返回的是一批数据(如1000行)(一般向量化特指列式存储系统中,按列聚合的一组数据;在行式系统中称为RowSet迭代)。列式存储的数据聚集性也可以更好的支撑向量化执行。
向量化执行执行需要SIMD指令集的支持。
SIMD (Single Instruction Multiple Data) 即单条指令操作多条数据——原理即在CPU 寄存器层面实现数据的并行操作。常用的SIMD指令集包括MMX、SSE、AVX等。
clickhouse使用的SIMD指令集主要用于:
- 加速 Array Filter
- 加速 Array Div
- 计算 Byte Array 尾部多少个 0
- 计算 Byte Array 中,有多少项不为 0
- 判断 IPv6 地址是否在一个子网下
- 字符串子串搜索
- 计算 UTF 字符串可见长度时,快速跳过 ASCII 字符
- 比较两个内存块的大小
- 将程序(.text/.data ELF) remap 到 Huge Page 以提升性能
- CRC Hash
- Round 函数
- 大小写转换
ClickHouse 目前主要使用SSE4.2 指令集实现向量化执行。
并行处理的机制决定了一个查询也会使用大量CPU,所以CK不支持高并发场景。
数据表引擎
MergeTree是clickhouse最核心的表引擎,其余的表引擎都基于MergeTree。
MergeTree中基本存储单位是Block,Block作为CK进行磁盘IO的基本单位和文件压缩/解压缩的单位。Granule内存扫描的最小单位
Block的结构
索引三级结构
MergeTree中每次提交不经过内存,直接存储在硬盘上,每次存储产生的文件为一个part,因为直接存储的原因,所以clickhouse需要用户自己限制插入的频率,如果插入太快,生成过多的数据part会导致inode耗尽的问题。
part没有经过内存合并,所以容易出现较多文件,MergeTree会定期将part合并。
MergeTree和LSM的区别如下:
概念 | 元数据 | 合并方式 | |
---|---|---|---|
LSM | WAL(写入日志)
MemTable(内存存储) SSTable(硬盘存储) |
存储在manifest文件 | |
MergeTree | part(磁盘存储)
对应一次写入提交 因为直接存储在持久化存储,所以不需要日志) |
文件名
{partition}_{minBlockNum}_{maxBlockNum}_{level} 包含了元数据信息 |
集群机制
CK的集群机制由以下几个部分组成:
- 副本机制
ReplicatedMergeTree引擎实现了CK的副本机制。Clickhouse的副本机制是基于表实现的,用户在创建每张表的时候,决定是否使用副本。
- 分片机制
Distributed引擎实现了分布式表的功能,分布式表的本质并不是一张表,而是一些本地物理表(分片)的分布式视图,本身并不存储数据。分片机制可以指定分片健,分片健决定了查询时候的路由机制。
- 配置信息
ReplicatedMergeTree引擎依赖zookeeper作为配置中心,在zookeeper中存储了大量的数据:
表结构信息、元数据、操作日志、副本状态、数据块校验值、数据part merge过程中的选主信息。
除了配置功能之外, zookeeper又在复制表引擎还作为元数据存储、日志框架、分布式协调服务等身份。
join机制
CK的单机join可以采用Merge Join或者Hash Join,因为Merge Join过程中,数据会溢出到磁盘,性能较差,所以默认采用Hash join。
ClickHouse 的 Hash Join算法实现比较简单:
- 从right_table 读取该表全量数据,在内存中构建Hash Map;
- 从left_table 分批读取数据,根据Join Key在右表构建的Hash Map中查找,如果命中,则该数据作为JOIN的输出;
CK单表查询速度非快,但是CK的多表join查询每次只能join一个表,所以join性能较差。