什么是ClickHouse?
ClickHouse 是面向 OLAP 的分布式列式 DBMS.
在“正常”的面向行的DBMS中,数据按顺序进行存储:
5123456789123456789 1 Eurobasket - Greece - Bosnia and Herzegovina - example.com 1 2011-09-01 01:03:02 6274717 1294101174 11409 612345678912345678 0 33 6 http://www.example.com/basketball/team/123/match/456789.html http://www.example.com/basketball/team/123/match/987654.html 0 1366 768 32 10 3183 0 0 13 0\0 1 1 0 0 2011142 -1 0 0 01321 613 660 2011-09-01 08:01:17 0 0 0 0 utf-8 1466 0 0 0 5678901234567890123 277789954 0 0 0 0 0
5234985259563631958 0 Consulting, Tax assessment, Accounting, Law 1 2011-09-01 01:03:02 6320881 2111222333 213 6458937489576391093 0 3 2 http://www.example.ru/ 0 800 600 16 10 2 153.1 0 0 10 63 1 1 0 0 2111678 000 0 588 368 240 2011-09-01 01:03:17 4 0 60310 0 windows-1251 1466 0 000 778899001 0 0 0 0 0
...
换句话说,与一行相关的所有值都被存储在一起。面向行的DBMS主要有MySQL,Postgres,MS SQL Server等等。
在面向列的DBMS中,数据存储如下:
WatchID:5385521489354350662 5385521490329509958 5385521489953706054 5385521490476781638 5385521490583269446 5385521490218868806 5385521491437850694 5385521491090174022 5385521490792669254 5385521490420695110 5385521491532181574 5385521491559694406 5385521491459625030 5385521492275175494 5385521492781318214 5385521492710027334 5385521492955615302 5385521493708759110 5385521494506434630 5385521493104611398
JavaEnable:1 0 1 0 0 0 1 0 1 1 1 1 1 1 0 1 0 0 1 1
Title:Yandex Announcements - Investor Relations - Yandex Yandex — Contact us — Moscow Yandex — Mission Ru Yandex — History — History of Yandex Yandex Financial Releases - Investor Relations - Yandex Yandex — Locations Yandex Board of Directors - Corporate Governance - Yandex Yandex — Technologies
GoodEvent:1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
EventTime:2016-05-18 05:19:20 2016-05-18 08:10:20 2016-05-18 07:38:00 2016-05-18 01:13:08 2016-05-18 00:04:06 2016-05-18 04:21:30 2016-05-18 00:34:16 2016-05-18 07:35:49 2016-05-18 11:41:59 2016-05-18 01:13:32...
这些示例仅显示数据排列的顺序。不同列的值分开存储,同一列的数据一起存储。例如,面向列的DBMS:Vertica,Paraccel(Actian Matrix)(Amazon Redshift),Sybase IQ,Exasol,Infobright,InfiniDB,MonetDB(VectorWise)(Actian Vector),LucidDB,SAP HANA,Google Dremel,Google PowerDrill,Druid ,kdb +等。
存储数据的不同存储顺序更适合于不同的应用场景。数据访问场景指的是执行什么查询,多长时间查询,每种类型的查询读取多少数据 - 行,列和字节;写取和更新数据之间的关系;数据的大小以及它在本地的使用情况;是否使用交易处理,以及它们是如何隔离的;数据同步和逻辑完整性的要求;每类查询的延迟和吞吐量要求等等。
系统上的负载越高,场景化的系统定制就越重要,定制化就越具体。没有一个系统能够适用于截然不同的应用场景。如果一个系统可以适应多种场景,那么在高负载情况下,系统处理所有场景表现都会很差,或者仅其中一种场景表现良好。
对于OLAP(联机分析处理)方案,将会有如下几种应用场景:
- 绝大多数请求是以读为主。
- 数据以相当大的批次(> 1000行)进行更新,而不是单行更新;或者根本不更新。
- 数据被添加到数据库,基本不怎么修改。
- 对于读取,大量的数据从数据库中抽取出来,但只有列的一个子集。
- 表是“宽的”,这意味着它们包含大量的列。
- 查询相对较少(通常每台服务器数百个查询或更少)。
- 对于简单的查询,允许大约50 ms的延迟。
- 列值相当小 - 数字和短字符串(例如,每个URL 60个字节)。
- 处理单个查询时需要高吞吐量(每台服务器每秒高达数十亿行)。
- 无事务处理。
- 数据一致性要求低- 每个查询有一个大表,其他所有的表都是小表。
- 查询结果显著小于源数据。也就是说,数据被过滤或聚合。结果可以放在单个服务器的内存中。
很容易看出,OLAP方案与其他常见方案(如OLTP或Key-Value访问)有很大不同。所以,如果你想获得不错的表现,尝试使用OLTP或Key-Value DB来处理分析查询是没有意义的。例如,如果您尝试使用MongoDB或Elliptics进行分析,与OLAP数据库相比,您的性能会很差。
面向列的数据库更适合于OLAP方案(对于大多数查询,处理速度至少提高了100倍),原因如下:
1.对于I/O
1.1 对于分析查询,只需要读取少量的列。在面向列的数据库中,您只能读取所需的数据。例如,如果您需要100列中的5列,则I/O可能会减少20倍。
1.2 由于数据是以数据包的形式读取的,因此压缩比较容易。列中的数据也更容易压缩。这进一步减少了I/O量。
1.3 由于减少的I/O,更多的数据适合在系统缓存中。
例如,查询“统计每个广告平台的记录数量”需要读取一个“广告平台ID”列,其占用1个未压缩字节。如果大多数流量不是来自广告平台,那么您可以期望至少有10倍的压缩比。当使用快速压缩算法时,数据解压缩速度可以达到每秒至少几千兆字节的未压缩数据。换句话说,这个查询可以在一台服务器上以每秒大约几十亿行的速度处理。这个速度实际上是在实践中是容易实现的。
milovidov@████████.yandex.ru:~$ clickhouse-client
ClickHouse client version 0.0.52053.
Connecting to localhost:9000.
Connected to ClickHouse server version 0.0.52053.
:) SELECT CounterID, count() FROM hits GROUP BY CounterID ORDER BY count() DESC LIMIT 20
SELECT
CounterID,
count()
FROM hits
GROUP BY CounterID
ORDER BY count() DESC
LIMIT 20
┌─CounterID─┬──count()─┐
│ 114208 │ 56057344 │
│ 115080 │ 51619590 │
│ 3228 │ 44658301 │
│ 38230 │ 42045932 │
│ 145263 │ 42042158 │
│ 91244 │ 38297270 │
│ 154139 │ 26647572 │
│ 150748 │ 24112755 │
│ 242232 │ 21302571 │
│ 338158 │ 13507087 │
│ 62180 │ 12229491 │
│ 82264 │ 12187441 │
│ 232261 │ 12148031 │
│ 146272 │ 11438516 │
│ 168777 │ 11403636 │
│ 4120072 │ 11227824 │
│ 10938808 │ 10519739 │
│ 74088 │ 9047015 │
│ 115079 │ 8837972 │
│ 337234 │ 8205961 │
└───────────┴──────────┘
20 rows in set. Elapsed: 0.153 sec. Processed 1.00 billion rows, 4.00 GB (6.53 billion rows/s., 26.10 GB/s.)
:)
2.对于CPU
由于执行查询需要处理大量的行,因此它有助于为整个向量而不是单独的行指派所有操作,或者实现查询引擎,以便没有指派成本。如果你不这样做,任何半象限的磁盘子系统,查询解释器不可避免地中断CPU。将数据存储在列中并在可能的情况下按列处理是有意义的。
有两种方法可以做到这一点:
1.向量引擎。所有的操作都是为向量而写的,而不是单独的值。这意味着您不需要经常调用操作,调度成本可以忽略不计。操作代码包含一个优化的内部循环。
2.代码生成。为查询生成的代码具有所有的间接调用。
这不是在“普通”数据库中完成的,因为运行简单查询时没有意义。但是,也有例外。例如,MemSQL在处理SQL查询时使用代码生成来减少延迟。(为了比较,分析DBMS需要优化吞吐量,而不是延迟。)
请注意,为了提高CPU效率,查询语言必须是声明式的(SQL或MDX),或者至少是一个向量(J,K)。查询应该只包含隐式循环,以便优化。
ClickHouse的显著特性
1.真正的面向列的DBMS
2.数据高效压缩
3.磁盘存储的数据
4.多核并行处理
5.在多个服务器上分布式处理
6. SQL语法支持
7.向量化引擎
8.实时数据更新
9.索引
10.适合在线查询
11.支持近似预估计算
12.支持嵌套的数据结构
支持数组作为数据类型
13.支持限制查询复杂性以及配额
14.复制数据复制和对数据完整性的支持
我们来看看其中的一些功能:
1.真正的面向列的DBMS
在一个真正的面向列的DBMS中,没有任何“垃圾”存储在值中。例如,必须支持定长数值,以避免在数值旁边存储长度“数字”。例如,十亿个UInt8类型的值实际上应该消耗大约1 GB的未压缩磁盘空间,否则这将强烈影响CPU的使用。由于解压缩的速度(CPU使用率)主要取决于未压缩的数据量,所以即使在未压缩的情况下,紧凑地存储数据(没有任何“垃圾”)也是非常重要的。
因为有些系统可以单独存储单独列的值,但由于其他场景的优化,无法有效处理分析查询。例如HBase,BigTable,Cassandra和HyperTable。在这些系统中,每秒钟可以获得大约十万行的吞吐量,但是每秒不会达到数亿行。
另外,ClickHouse是一个DBMS,而不是一个单一的数据库。ClickHouse允许在运行时创建表和数据库,加载数据和运行查询,而无需重新配置和重新启动服务器。
2.数据压缩
一些面向列的DBMS(InfiniDB CE和MonetDB)不使用数据压缩。但是,数据压缩确实提高了性能。
3.磁盘存储的数据
许多面向列的DBMS(SAP HANA和Google PowerDrill)只能在内存中工作。但即使在数千台服务器上,内存也太小,无法在Yandex.Metrica中存储所有浏览量和会话。
4.多核并行处理
多核多节点并行化大型查询。
5.在多个服务器上分布式处理
上面列出的列式DBMS几乎都不支持分布式处理。在ClickHouse中,数据可以驻留在不同的分片上。每个分片可以是用于容错的一组副本。查询在所有分片上并行处理。这对用户来说是透明的。
6. SQL支持
如果你熟悉标准的SQL,我们不能真正谈论SQL的支持。
NULL不支持。
所有的函数都有不同的名字。
JOIN支持。
子查询在FROM,IN,JOIN子句中被支持;
标量子查询支持。
关联子查询不支持。
7.向量化引擎
数据不仅按列存储,而且由矢量 - 列的部分进行处理。这使我们能够实现高CPU性能。
8.实时数据更新
ClickHouse支持主键表。为了快速执行对主键范围的查询,数据使用合并树(MergeTree)进行递增排序。由于这个原因,数据可以不断地添加到表中。添加数据时无锁处理。
9.索引
例如,带有主键可以在特定的时间范围内为特定客户端(Metrica计数器)抽取数据,并且延迟时间小于几十毫秒。
10.支持在线查询
这让我们使用该系统作为Web界面的后端。低延迟意味着可以无延迟实时地处理查询,而Yandex.Metrica界面页面正在加载(在线模式)。
11.支持近似计算
1.系统包含用于近似计算各种值,中位数和分位数的集合函数。
2.支持基于部分(样本)数据运行查询并获得近似结果。在这种情况下,从磁盘检索比例较少的数据。
3.支持为有限数量的随机密钥(而不是所有密钥)运行聚合。在数据中密钥分发的特定条件下,这提供了相对准确的结果,同时使用较少的资源。
12.数据复制和对数据完整性的支持。
使用异步多主复制。写入任何可用的副本后,数据将分发到所有剩余的副本。系统在不同的副本上保持相同的数据。数据在失败后自动恢复,或对复杂情况使用“按钮”。有关更多信息,请参阅“数据复制”一节。
ClickHouse目前未实现功能
1.无事务处理。
2.对于聚合,查询结果必须适合单个服务器上的内存。但是,查询的源数据量可能无限大。
3.缺乏全面的UPDATE / DELETE实现
Yandex.Metrica任务
我们需要根据点击和会话获取自定义报告,并使用用户设置的自定义。报告数据实时更新。查询必须立即运行(在线模式)。我们必须能够在任何时间段建立报告。必须计算复杂的汇总,例如唯一访客的数量。目前(2014年4月),Yandex.Metrica每天接收约120亿次事件(浏览量和鼠标点击)。所有这些事件都必须存储以建立自定义报告。单个查询可能需要几秒钟扫描数亿行,或者数百万行不超过几百毫秒。
汇总和非汇总数据
有一种流行的观点认为,为了有效地计算统计数据,您必须汇总数据,因为这会减少数据量。
但是数据聚合是一个非常有限的解决方案,原因如下:
- 您必须具有用户需要的预定义报告列表。用户不能进行自定义报告。
- 聚合大量密钥时,数据量不会减少,聚合无用。
- 对于大量的报告,聚合变化太多(组合爆炸)。
- 聚合高基数密钥(如URL)时,数据量不会减少太多(小于两倍)。出于这个原因,聚合的数据量可能会增长,而不是缩小。
- 用户不会查看我们为他们计算的所有报告。大部分的计算是无用的。
- 各种聚合可能违反数据的逻辑完整性。
如果我们不汇总任何内容并使用非汇总的数据,这实际上可能会减少计算量。
但是,通过汇总,相当一部分工作脱离了线索,相对冷静地完成了工作。相反,在线计算需要尽可能快地计算,因为用户正在等待结果。
Yandex.Metrica有一个专门的系统来汇总称为Metrage的数据,这个数据用于大多数报告。从2009年开始,Yandex.Metrica还使用专门的OLAP数据库来处理非聚合数据,称为OLAPServer,以前用于报告生成器。OLAPServer对非汇总数据运行良好,但是它有许多限制,不能根据需要用于所有报告。这些包括缺乏对数据类型(仅数字)的支持,以及无法实时增量更新数据(只能通过每天重写数据来完成)。OLAPServer不是一个DBMS,而是一个专门的DB。
为了消除OLAPServer的限制,并解决所有报告使用非汇总数据的问题,我们开发了ClickHouse DBMS。
用于Yandex.Metrica和其他Yandex服务
ClickHouse在Yandex.Metrica中用于多种用途。其主要任务是使用非聚合数据以在线模式构建报告。它使用374个服务器的集群,在数据库中存储超过8万亿行(超过四十亿个值)。压缩数据量不计复制和复制,大约是800TB。未压缩的数据量(以TSV格式)将大约为7PB。
ClickHouse还用于:
- 存储WebVisor数据。
- 处理中间数据。
- 使用Google Analytics构建全球报告。
- 运行查询以调试Metrica引擎。
- 分析来自API和用户界面的日志。
ClickHouse在其他Yandex服务中至少安装了十几个安装:搜索行业,市场,Direct,业务分析,移动开发,AdFox,个人服务等。
类似开源系统
有没有类似的ClickHouse可用。目前(2016年5月),没有任何可用的开源和免费系统具有上面列出的所有功能。但是,这些功能对于Yandex.Metrica是绝对必要的。
可能愚蠢的问题
1.为什么不使用map-reduce等系统?
像map-reduce这样的系统是分布式计算系统,其中使用分布式排序来执行缩减阶段。回顾这个方面,map-reduce与YAMR,Hadoop,YT等其他系统类似。
这些系统由于延迟而不适合在线查询,所以不能用于后台级别的网页界面。这样的系统也不适合实时更新。分布式排序并不是减少操作的最佳解决方案,如果操作的结果和所有中间结果都存在,就像通常在联机分析查询的情况下发生的那样,它们适合单个服务器的运行内存。在这种情况下,执行reduce操作的最佳方法是使用散列表。map-reduce任务的常用优化方法是在内存中使用散列表的组合操作(partial reduce)。这个优化是由用户手动完成的。分布式排序是简单的map-reduce作业长时间延迟的主要原因。
与map-reduce类似的系统可以在集群上运行任何代码。但是,对于OLAP,使用情况下的执行查询语言更为合适,因为经过调研它们可以更快地运行。例如,Hadoop有Hive和Pig。还有其他:Cloudera Impala,Shark (depricated)andSpark SQLforSpark,Presto,Apache Drill.。然而,与专门系统的性能相比,这些任务的性能是非常不理想的,相对较高的延迟不允许将这些系统用作网络接口的后端。YT允许您存储单独的一组列。但YT不是一个真正的列式存储系统,因为系统没有固定长度的数据类型(所以你可以有效地存储一个数字而不是“垃圾”),而且没有向量化引擎。YT中的任务由流模式下的任意代码执行,因此不能被充分优化(每台服务器每秒高达数亿行)。在2014-2016年,YT将开发使用合并树,强类型值和类SQL语言支持的“动态表格排序”功能。动态排序的表不适用于OLAP任务,因为数据存储在行中。YT中的查询语言开发仍处于孵化阶段,不能专注于这个功能。YT开发人员正在考虑在OLTP和Key-Value方案中使用动态排序的表。
性能
根据内部测试结果,ClickHouse在可用于测试的同类系统中显示出最佳性能。这包括长查询的最高吞吐量和短查询的最低延迟。测试结果显示在此页面上。
吞吐量为单个大型查询
吞吐量可以以每秒行数或兆字节每秒来衡量。如果数据放置在页面缓存中,则在现代硬件上处理不太复杂的查询,在单个服务器上以大约2-10 GB / s的未压缩数据的速度进行处理(对于最简单的情况,速度可能会达到30 GB / s)。如果数据不在页面缓存中,则速度取决于磁盘子系统和数据压缩率。例如,如果磁盘子系统允许以400 MB / s读取数据,并且数据压缩率为3,则速度将在1.2 GB / s左右。要获得每秒行数的速度,请将查询中使用的列的总大小除以每秒字节数。例如,如果提取10个字节的列,速度将在每秒大约1到2亿行。
处理速度对于分布式处理几乎线性地增加,但是只有在聚合或排序产生的行数不太大的情况下。
处理短的查询时延迟
如果一个查询使用一个主键,并且没有选择太多的行来处理(成千上万),并且不使用太多的列,我们可以预计到不到50毫秒的延迟(最好的情况下,单位为毫秒)if数据被放置在页面缓存中。否则,延迟是根据搜索的数量来计算的。如果使用旋转驱动器,对于没有过载的系统,延迟时间通过以下公式计算:查找时间(10 ms)*查询的列数*数据部分的数量。
处理大量的短查询时的吞吐量
在相同的条件下,ClickHouse可以在单个服务器上每秒处理几百个查询(在最好的情况下可以达到几千个)。由于这种情况对分析型DBMS并不常见,因此我们建议每秒最多可以查询100个查询。
数据插入性能
我们建议将数据插入至少1000行的数据包中,或者每秒不超过一个请求。从制表符分隔转储插入到MergeTree表时,插入速度将从50到200 MB / s。如果插入的行大小约为1Kb,速度将从每秒50,000到200,000行。如果行很小,则每秒的行数会更高(Yandex Banner System数据 - > 500,000行/秒,Graphite数据 - > 1,000,000行/秒)。为了提高性能,可以并行执行多个INSERT查询,并且性能会线性增加。