ClickHouse为何如此之快

针对ClickHouse为什么很快的问题,基于对ClickHouse的基础概念之上,一般会回答是因为是列式存储数据库,同时也会说是使用了向量化引擎,所以快。上面两方面的解释也都能够站得住脚,但是依然不能够解释真正核心的原因。因为这些技术并不是秘密,市面上很多数据库同样使用了这些技术,但是依然没有ClickHouse这么快。我们可以从另外一个角度来探讨一番ClickHouse的快的秘密。

对于一般软件设计架构的时候,一般采用自上而下的设计模式,ClickHouse的原型系统在2008年就诞生了,在诞生之初它并没有宏伟的规划。相反它的目的很简单,就是希望能以最快的速度进行GROUP BY查询和过滤,它是采用自下而上的设计方式。那么ClickHouse是如何实现自下而上的设计的呢?

1、着眼硬件,先想后做

首先从硬件功能层面着手设计,在设计之初就至少需要详情粗如下几个问题。

  • 我们将要使用的硬件水平是怎样的?包括CPU、内存、硬件、网络等。
  • 在这样的硬件上,我们需要达到怎样的性能?包括延迟、吞吐量等。
  • 我们准备使用怎样的数据结构?包括String 、HashTable、Vector等。
  • 选择的这些数据肌结构,在我们的硬件上会如何工作?

如果能想清楚上面这些问题,那么在动手实现功能之前,就已经能够计算出粗略的性能了。所以,基于将硬件功效最大化的目的,ClickHouse会在内存中进行GROUP BY,并且使用HashTable装载数据。与此同时,他们非常在意CPU L3级别的缓存,因为一次L3 的缓存失效会带来70~100ns的延迟。这意味着单核CPU上,它会浪费4000万次/秒的运算;而在一个32线程的CPU上,则可能会浪费5亿次/秒的运算。所以别小看这些细节,一点一滴的将它们累加起来,数据是非常可观的。正因为注意了这些细节,所以ClickHouse在基准查询中能做到1.75亿次/秒的数据扫描性能。

2、算法在前,抽象在后

俗话说”选择比努力更重要。“确实,好多时候,路线选错了再努力也是白搭。在ClickHouse的底层实现中,经常会面对一些重复的场景,例如字符串字串查询、数组排序等。如何才能实现性能的最大化呢?算法的选择是重中之重。clickHouse并没有选择字符串搜索算法书籍《Handbook of Exact String Matching Algorithms》中的35种常见的字符串搜索算法,因为这些性能不够快。在字符串搜索方面,针对不同的场景,ClickHouse最终选择了这些算法:对于常量,使用Volnisky算法;对于非常量,使用CPU的向量化执行SIMD,暴力优化;正则匹配使用了re2和hyperscan算法。性能是算法选择的首要考量指标。

3 、勇于尝鲜,不行就换

除了字符串之外,其余的场景也与它类似,ClickHouse会使用最合适、最快的算法。如果效果不错,就保留使用;如果性能不尽人意,就将其抛弃。

4、特定场景,特殊优化

针对同一个场景的不同状况,选择使用不同的实现方式,尽可能将性能最大化。关于这一点,其实在前面第二项介绍字符串查询时,针对不同场景选择不同算法的思路就有体现了。类似的例子还有很多,例如去重计数uniqCombined 函数,会根据数据量的不同选择不同的算法:当数据量较小的时候,会选择Array保存;当数据量中等的时候,会选择HashSet;而当数据量很大的时候,则使用HyperLogLog算法。

对于数据结构比较清晰的场景,会通过代码生成技术实现循环展开,以减少循环次数。接着就是大家熟知的大杀器—向量化执行了。SIMD被广泛地应用于文本转换、数据过滤、数据解压和JSON转换等场景。相较于单纯地使用CPU,利用寄存器暴力优化也算是一种降维打击了。

5、 持续测试,持续改进

如果只是单纯地在上述细节上下功夫,还不足以构建出如此强大的ClickHouse,还需要拥有一个能够持续验证、持续改进的机制。由于Yandex的天然优势,ClickHouse经常会使用真实的数据进行测试,这一点很好地保证了测试场景的真实性。与此同时,ClickHouse也是我见过的发版速度最快的开源软件了,差不多每个月都能发布一个版本。没有一个可靠的持续集成环境,这一点是做不到的。正因为拥有这样的发版频率,ClickHouse才能够快速迭代、快速改进。

所以ClickHouse的黑魔法并不是一项单一的技术,而是一种自底向上的、追求极致性能的设计思路。这就是它如此之快的秘诀。

你可能感兴趣的:(clickhouse)