关于clickhouse:Clickhouse系列第二节基本原理

11次阅读

共计 2416 个字符,预计需要花费 7 分钟才能阅读完成。

在正式开始 clickhouse 探秘前,咱们先抛出一个问题:影响 OLAP 查问速度的是什么?是优良的算法么?不可否认,算法对查问性能的影响十分大,但到了现阶段通用的算法基本上曾经可能达到很高的性能了。因而,在现阶段,制约着大数据 OLAP 查问速度的曾经不再是算法了。那么这个问题的答案就跃然纸上了——磁盘 io。上面咱们从定性和定量两个层面来剖析一下。

定性

古代计算机体系结构中,将存储系统依照层次结构顺序排列,称为存储器层次结构(Memory Hierarchy)。由此,从磁盘上读取数据的工夫远大于 CPU 计算的工夫。能够做个粗略的计算比照:

假如一台 2.4GHz 的 CPU+7200 转的机械硬盘。那么 CPU 执行一条指令的工夫是 1 /2.4G≈0.41ns。7200 转机械硬盘的读取约为 100MB 每秒。也就是说 CPU 执行一条指令的工夫硬盘实践上只能读取约 0.041 个字节。而实际上 0.41ns 都不足以使得磁盘开始转动。

由此咱们能够晓得,CPU 参加运算的工夫远小于磁盘 IO 的工夫。这种状况下,应用算法优化 CPU 执行的指令,会显得很不划算。

定量

咱们写一段代码来模仿数据库执行 SELECT max(id) From tbl_a 这句语句。如果不思考后面的 sql 解析过程,能够简略形象成两个步骤:

  1. 从磁盘中读取数据文件,载入内存
  2. 解析数据并找出最大的 id
// 从磁盘将文件载入内存
long s = System.nanoTime();
List<String> lines = FileUtils.readLines(file,"utf8");
long e1 = System.nanoTime();
System.out.println("文件读取实现,耗时:"+((e1-s)/1e6)+"ms, 开始找最大值");
// 解析并求出最大值
String maxId = lines.parallelStream()
         .map(e -> e.substring(0,e.indexOf(" ")).trim())
         .max(Comparator.comparingInt(Integer::parseInt)).orElse("未找到");
long e2 = System.nanoTime();
// 计算每个阶段的耗时
System.out.println("计算实现,耗时:"+((e2-e1)/1e6)+"ms");
System.out.println("程序运行实现,总耗时:"+((e2-s)/1e6)+"ms(不计算生成数据文件文件的工夫)");

代码如上所示,应用下表的构造模仿数据表:

id 姓名 部门名称 岗位名称
1 Amy 大数据部 部门经理
2 Tom 大数据部 部门经理
3 John 大数据部 部门经理

表 1 模仿表构造

应用 3000 万条数据作为测试,数据集大小为 1.1G。最终执行后果为:

 文件读取实现,耗时:4971.683747 ms
计算实现,耗时:432.261263 ms 

能够看出,两者差距靠近了 11 倍。并且,这个试验的第二步,其实 CPU 也有很长时间是在读取内存的。不过这个试验曾经足够阐明问题了。

很显著,古代 OLAP 须要想方法升高磁盘 IO 的工夫。

升高磁盘 IO 的伎俩

如表 2 所示,古代 OLAP 数据库个别应用两种伎俩升高磁盘 IO 工夫对查问性能的影响。

伎俩 原理 代表数据库 缺点
分布式 并行读取数据,升高单台服务器须要读取的数据量 Hive(textfile),greenplum 独自应用实质上仍然须要读取所有数据,消耗资源
行变列(列存数据库) 行存数据库即便只须要某一列的数据,也必须读取所有数据(如定量中的例子)列存通过将每一列独自存储,做到按需读取 hbase 适宜应用列比拟繁多的业务。

表 2 升高磁盘 IO 工夫的伎俩

分布式是大数据晚期时代应用的计划,他的原理和思维非常简单粗犷,单机解决慢,我就分成 N 台服务器进行计算,每一台只须要计算一小部分,最初将后果汇总。例如最晚期的 Hive。这种架构的长处是简略粗犷,但也有显著的缺点,就是尽管等待时间变少了,然而整体上看,将多台机器的计算工夫汇总,总耗时是大于单机解决工夫的。而且也很容易产生数据歪斜问题和减少网络传输工夫。其实是节约了资源。因而随着技术的倒退,基本上大家都应用了分布式和行变列混用的架构。hive 在前期也减少了列存引擎。

列存数据库的原理将每一列独自存储,升高每次载入的数据量。还是以定量分析节中的例子为例,数据文件 data.bin 大小为 1.1G,载入工夫 4.9s。如果将每一列独自写入一个文件,那么如果只须要计算出最大 id,那就只须要载入 id.bin 文件,这个文件约为 247MB,实践上能将读取工夫缩小 75% 左右。同样,列存也有一个很大缺点,思考一个极其状况,如果查问语句非常复杂,从而用到了所有的列,那么列存也无奈升高读取工夫。所以,OLAP 适宜解决大宽表,列越多,其性能比照行式数据库的晋升越大。

这里插个题外话,理解了列存数据库的原理后,读者要明确,将数据从行式数据库导入到列式数据库进行剖析时,请肯定记得将行式数据库的星型表转换成列式数据库的大宽表。否则性能晋升有可能会不显著。在我的职业生涯中,我就遇到过数仓工程师将数据从 MySQL 导入 adb 后,间接进行查问,而后嗔怪 adb 性能为什么这么差!这也是为什么数仓模型要分层的起因。另外有些读者可能会有纳闷,为什么行式数据库不搞成大宽表?这外面的起因不在本系列的领域内,后续笔者会另外写一篇独自的文章,为读者讲透这外面的起因,敬请期待,也能够在评论区说出你的想法。

clickhouse 就是应用了列存的数据库,相似的还有前期的 hive、greenplum。那么,同样都是列存数据库,凭什么 clickhouse 就能比这些数据库快呢?本系列的后续局部将持续探讨 clickhouse 的巧思。再次强调,clickhouse 并没有提出新的计算实践,只是在列存的根底上进行了多项优化。从而提现了 clickhouse 工程师的令人惊叹而着迷的奇思妙想。

正文完
 0