ClickHouse
是一款 MPP
架构的数据库,它没有采用 Hadoop
生态中的主从架构,而是使用了多主对等网络结果,同时它也是基于关系模型的 ROLAP
方案。官网 docs 地址:https://clickhouse.com/docs/en/intro
MMP
:Massively Parallel Processing(大规模并行处理),是将任务并行的分散到多个服务器和节点上,在每个节点上计算完成后,将各自部分的结果汇总在一起得到最终的结果。采用 MPP 架构的数据库称为 MPP 数据库。
MPP架构的特点:
MPPDB 与 Hadoop 都是将运算分布到节点中独立运算后进行结果合并(分布式计算),但由于依据的理论和采用的技术路线不同而有各自的优缺点和适用范围。两种技术以及传统数据库技术的对比如下:
综合而言,Hadoop 和 MPP 两种技术的特定和适用场景为:
● Hadoop 在处理非结构化和半结构化数据上具备优势,尤其适合海量数据批处理等应用要求。
● MPP 适合替代现有关系数据机构下的大数据处理,具有较高的效率。
向量化执行引擎
(Vectorized execution engine),对内存中的列式数据,一个batch调用一次SIMD指令(而非每一行调用一次),不仅减少了函数调用次数、降低了cache miss,而且可以充分发挥SIMD指令的并行能力,大幅缩短了计算耗时。向量执行引擎,通常能够带来数倍的性能提升。
简单理解为就是消除程序 循环的优化,堆机器加快速度,实现向量化执行,需要利用 CPU 的 SIMD 指令。
SIMD
(Single Instruction Multiple Data),用单指令流多数据流,也就是说一次运算指令可以执行多个数据流,一个简单的例子就是向量的加减,不适合用于带有较多分支判断的场景。
OLTP
:On-line Transaction Processing 翻译为联机事务处理 。要求 实时性高、稳定性强、确保数据及时更新成功。从数据库角度来看 OLTP 主要是对数据的增删改。
OLAP
:On-line Analytical Processing 翻译为联机分析处理。需要将业务数据集中统一分析,一般是将数据存储在数据仓库中统一提供 OLAP 分析。OLAP 主要是数据仓库的应用,是对数据的查询。
ROLAP
:Relational OLAP,关系型联机分析处理。顾名思义,它直接使用关系型构建,数据模型常使用星型模型或者雪花模型(星型模型和雪花模型)。以 ROLAP 为代表的有传统关系型数据库、MPP 分布式数据库以及基于 Hadoop 的 Spark/Impala,特点是能同时连接明细数据和汇总数据,实时根据用户提出的需求对数据进行计算后返回给用户。正因为采用的实时计算技术,所以 ROLAP 的缺点也比较明显——当计算的数量达到一定级别或者并发数达到一定级别的时候,一定会出现性能问题。
以传统关系型数据库为代表的如Teradata、Oracle等,由于传统架构可扩展性较差,所以对硬件的要求非常高,当计算的数据量达到千万,亿级别时,数据库的计算就会出现延时,使得用户不能及时得到响应,更别提高并发了。
MPP分布式数据库(GreenPlum/GBase/Vertica)则解决了一部分可扩展性问题,对硬件设备的要求也稍稍下降了(还是有一定的硬件要求),在支持的数据体量(GB,TB级别)上有了很大的提升。当集群有几百、上千节点时,会出现性能瓶颈(增加再多节点,性能提升也不会很明显),扩容成本同样不菲。
基于Hadoop的Spark/Impala,则对部署硬件的要求很低(常见服务器即可,只是其主要依靠内存计算来缩短响应时间,所以对内存要求较高),在节点扩容上成本上相对较低,但当计算量达到一定级别或并发达到一定级别后,无法秒级响应,且容易出现内存溢出等问题。
MOLAP
:Multidimensional OLAP,多维联机分析处理。以 MOLAP 分析为代表的有Cognos,SSAS,Kylin 等,设计理念是预先将客户的需求计算好以结果的形式存下来(比如一张表分为 10 个维度, 5 个度量,那客户提出的需求会有 2 的 10 次方种可能,然后将这么多种可能提前计算好存储下来),当客户提出需求后,找到对应结果返回即可。特点是当命中需求后返回非常快(所以 MOLAP 非常适合常见固定的分析场景),同等资源下支持的数据体量更大,支持的并发更多,不足则是当表的维度越多,越复杂,其所需的磁盘存储空间则越大,构建 cube 也需要一定的时间。
HOLAP
:Hybird OLAP,混合架构的 OLAP。这种思路可以理解成 ROLAP 和 MOLAP 两者的集成。
适用场景:
- 绝大多数请求都是用于读访问的
- 数据需要以大批次(大于1000行)进行更新,而不是单行更新;或者根本没有更新操作
- 数据只是添加到数据库,没有必要修改
- 读取数据时,会从数据库中提取出大量的行,但只用到一小部分列
- 表很“宽”,即表中包含大量的列
- 查询频率相对较低(通常每台服务器每秒查询数百次或更少)
- 对于简单查询,允许大约50毫秒的延迟
- 列的值是比较小的数值和短字符串(例如,每个URL只有60个字节)
- 在处理单个查询时需要高吞吐量(每台服务器每秒高达数十亿行)
- 不需要事务
- 数据一致性要求较低
- 每次查询中只会查询一个大表。除了一个大表,其余都是小表
- 查询结果显著小于数据源。即数据有过滤或聚合。返回结果不超过单个服务器内存大小
不适用场景:
- 不支持真正的删除/更新支持 不支持事务(期待后续版本支持)
- 不支持二级索引
- 有限的SQL支持,join实现与众不同
- 不支持窗口功能
- 元数据管理需要人工干预维护
ClickHouse 拥有完备的管理功能,而不仅是一个数据库。作为一个 DBMS,它具备了一些基本功能。
DDL
:Data Definition Language,数据定义语言,可以动态地创建、修改或删除数据库、表和视图,无须重启服务。
DML
:Data Manipulation Language,数据操作语言,可以动态增删改查数据。
权限控制
:可以按照用户粒度设置数据库或者表的操作权限,保障数据的安全性。
数据备份与恢复
:提供了数据备份导出与导入恢复机制,满足生产环境的要求。
分布式管理
:提供集群模式,自助管理多个数据库节点。
如果,你想让查询变得更快,最简单且有效的方法是减少数据扫描范围和数据传输时的大小,列式存储和数据压缩可以帮我们实现上述两点。
列式存储:在扫描指定列时,避免多余的数据扫描。
数据压缩:按照一定步长对数据进行匹配扫描,当发现重复部分的时候就进行编码转换,降低IO和存储的压力。
举例说明:
压缩前:abcdefghi_bcdefghi
压缩后:abcdefghi_(9,8)
压缩的本质是按照一定步长对数据进行匹配扫描,当发现重复部分的时候就进行编码转换。例如上面示例中的(9,8),表示如果从下划线开始向前移动9个字节会匹配到 8 个字节长度的重复项,即 bcdefghi。
当然真实的压缩算法比我们的示例中的复杂,数据默认使用 LZ4 算法压缩
,数据总体的压缩比达到 8:1 (为压缩前 17PB,压缩后 2PB)。列式存储除了降低 IO 和存储 的压力之外,还为向量化执行做好了铺垫。
向量化执行引擎简单理解就是消除程序循环的优化,堆机器加快速度,数据级并行。实现向量化执行需要利用 CPU 的 SIMD 指令。SIMD 的全称是 Single Instruction Multiple Data,即用单挑指令操作多条数据
。现在计算机系统概念中,它是通过数据并行以提高性能的一种实现凡事(其他的还有指令级并行和线程级并行),它的原理是在 CPU 寄存器层面实现数据的并行操作。
在计算机系统的体系结构中,存储系统是一种层次结构。典型服务器计算机的存储层次结构如下图所示:
从上图可以看出,从左向右,距离 CPU 越远,则数据的访问速度越慢。从寄存器中访问数据的速度,是从内存访问数据速度的 300 倍,是从磁盘中访问数据速度的 3000 万倍。所以利用 CPU 向量化执行的特性,对于程序的 性能提升意义非凡。
ClinckHouse 目前利用 SSE4.2 指令级实现向量化执行
SQL 解析方面 ClickHouse 是大小写敏感的
,select a 和 select A 代表的语义是不同的。ClickHouse 最初的架构是基于 MySQL 实现的,表引擎设计就与 MySQL 类似,存储引擎作为一层独立的接口。种类繁多,根据业务场景自行选择。ClickHouse 拥有合并树、内存、文件、接口和其他6大类20多种表引擎。通过特定的表引擎支撑特定的场景,十分灵活。对于简单的场景,可直接使用简单的引擎降低成本,而复杂的场景也有合适的选择。(ClickHouse 有很多表引擎,后续留一篇专门介绍表引擎)
ClickHouse在数据存取方面,既支持分区(纵向扩展,利用多线程原理),也支持分片(横向扩展,利用分布式原理),可以说是将多线程和分布式的技术应用到了极致。
HDFS、Spark、HBase 和 Elasticsearch 这类分布式系统,都采用了 Master-Slave 主从架构,由一个管控节点作为 Leader 统筹全局。而 ClickHouse 则采用的 Multi-Master 多主架构,集群中每个节点角色对等,客户端访问任意一个节点都能得到相同的效果。它有以下优点:
有些地方翻译成了在线查询,我觉得翻译成 “实时查询” 更为妥当,对比其他的分析型数据库,例如“Vertica”、SparkSQL、Hive、Elasticsearch 等,在大数据分析场景 ClickHouse 又快又免费。
目前 ClickHouse 公开的资料相对匮乏,比如在架构涉及层面就很淡找到完整的资料,甚至连一张整体的架构图都没有。
Column 和 Field 是 ClickHouse 数据最基础的映射单元。ClickHouse 内存中改的一列数据由一个 Column 对象表示,一列中的某一行(单列中的一行数据)用 Filed 对象表示。
Column 对象:分为接口和实现两个部分。IColumn 接口定义了对数据进行各种关系运算的方法;方法的具体实现则根据数据类型的不同由相应对象实现,例如 ColumnString、ColumnArray 和 ColumnTuple 等。
Field 对象:使用了聚合的设计模式。在 Field 对象内部聚合了 Null、UInt64、String 和 Array 等 13 种数据类型及相应的处理逻辑。
负责数据的序列化和反序列化相关工作,但是并不直接负责数据的读取,而是转由Column或Field对象获取。在DataType的实现类中,聚合了相应数据类型的 Column 对象和 Field 对象。例如 DataTypeString 会引用字符串类型的 ColumnString,而 DataTypeArray 则会引用数组类型 ColumnArray ,以此类推。
ClickHouse 的数据是面向 Block 对象进行的,并且是采用流的方式。虽然 Column 与 Field 组成了数据的基本映射单元,但对应到实际操作,他们还缺少一些必要信息,例如数据的类型以及列的名称。于是设计出了 Block 对象,Block 对象可以看做数据表的子集。
Block=数据对象(Column/Feild) + DataType + 列名称字符串
流操作有两个顶层接口:IBlockInputStream 负责数据的读取和关系运算,IBlockOutputStream 负责将数据输出到下一环节。
在数据表的底层设计中并没有所谓的Table对象,它直接使用 IStorage接口指代数据表。
表引擎是ClickHouse的一个显著特性, 不同的表引擎由不同的子类实现,例如IStorageSystemOneBlock (系统表)、StorageMergeTree(合并树表引擎)和 StorageTinyLog(日志表引擎)等。
Parser分析器负责创建 AST (Abstract syntax tree,抽象语法树)对象,而Interpreter解释器则负责解释 AST ,并进一步创建查询的执行管道。它们与 IStorage 一起,串联起了整个数据查询的过程。Parser 分析器可以将一条 SQL 语句以递归下降的方法解析成 AST 语法树的形式。不同的 SQL 语句,会经由不同的 Parser 实现类解析。
普通函数,例如四则运算、日前转换、网址提取函数、IP地址脱敏函数。没有状态,函数效果作用于每行数据之上。在函数具体执行过程中,采用向量化的方式直接作用于一整列数据,而不是一行一行计算。
聚合函数,有状态的,例如 COUNT 聚合函数,AggregateFunctionCount 的状态用整型 UInt64 记录。聚合函数的状态支持序列化与反序列化,所以能够在分布式节点之间进行传 输,以实现增量计算。
集群由分片(Shard)组成,分片由副本(Replica)组成。ClickHouse 的1个节点只能拥有一个分片,如果要实现1分片、1副本,至少需要部署两个服务节点。分片是逻辑概念,物理承载由副本承担。
上图示例是 2 分片 2 副本,需要 4 个物理节点。