7

内容大纲:

  1. 背景;
  2. Clickhouse介绍;
  3. Clickhouse架构及性能;
  4. Clickhouse在好未来的实践;
  5. 建设与规划;
  6. 参考文献。

背景

在日志中心发展早期,日志检索分析主要基于elasticsearch进行,随着日志中心接入的业务越来越多,数据量也逐渐增长,基于日志进行分析和监控告警的需求变得越来越复杂,很难用elasticsearch来满足,所以需要根据需求场景来选择合适数据库。我们需要的:

  • 数据量会很大,因此需要分布式;
  • 支持实时写入,支持快速计算,在较短时间内能完成计算;
  • 强大的sql能力,实时指标sql化;
  • 人力有限,运维需要简单;
  • 高效的压缩比存储,服务器有限,可以用更少的服务器存储更多的数据;

基于以上特点,我们选择了Clickhouse,接下来会介绍Clickhouse的特点、系统架构以及使用情况。

Clickhouse介绍

1、Clickhouse特点

===============
image

图2-1 Clickhouse特点图

可以看到,Clickhouse的特点恰是我们所需要的。接下来详细的介绍一下核心特性:

1)完备的DBMS功能:

ClickHouse拥有完备的管理功能,所以它称得上是一个DBMS ( Database Management System,数据库管理系统 ),而不仅是一个数据库。

作为一个DBMS,它具备了一些基本功能,如:

  • DDL ( 数据定义语言 ):可以动态地创建、修改或删除数据库、表和视图,而无须重启服务;
  • DML ( 数据操作语言 ):可以动态查询、插入、修改或删除数据;
  • 权限控制:可以按照用户粒度设置数据库或者表的操作权限,保障数据的安全性;
  • 数据备份与恢复:提供了数据备份导出与导入恢复机制,满足生产环境的要求;
  • 分布式管理:提供集群模式,能够自动管理多个数据库节点。

2) 列式存储与数据压缩

列式存储和数据压缩,对于一款高性能数据库来说是必不可少的特性。想让查询变得更快,最简单且有效的方法是减少数据扫描范围和数据传输时的大小,而列式存储和数据压缩就可以帮助我们实现上述两点。由于Clickhouse是真正意义上的列式存储,每一列都在不同的文件下,所以该文件数据类型一致,可以更有效的压缩。

3) 向量化执行引擎

向量化执行以列存为前提,主要思想是每次从磁盘上读取一批列,这些列以数组形式组织。每次next都通过for循环处理列数组。这么做可以大幅减少next的调用次数。相应的CPU的利用率得到了提高,另外数据被组织在一起。

可以进一步利用CPU硬件的特性,如SIMD,将所有数据加载到CPU的缓存当中去,提高缓存命中率,提升效率。在列存储与向量化执行引擎的双重优化下,查询执行的速度会有一个非常巨大的飞跃。

4) 关系模型与SQL查询

ClickHouse是一个关系型数据库。它几乎可以支持近百分之九十的sql作为查询语句,比如group by,order by等。

5) 多样化的表引擎

ClickHouse和mysql一样,也将存储部分进行了抽象,把存储引擎作为一层独立的接口。所以说Clickhouse实现了很多种表引擎,比如mergetree,log,memory等类型的引擎,每一种表引擎都有着各自的特点,用户可以根据实际业务场景的要求,选择合适的表引擎使用。

6) 多线程与分布式
ClickHouse几乎具备现代化高性能数据库的所有典型特征,对于可以提升性能的手段可谓是一一用尽,对于多线程和分布式这类被广泛使用的技术,自然更是不在话下。

7) 多主架构

HDFS、Spark、HBase和Elasticsearch这类分布式系统,都采用了Master-Slave主从架构,由一个管控节点作为Leader统筹全局。而ClickHouse则由于它的集群架构和其他数据库不同,这种架构使得它是一个多主架构。

8) 在线查询

ClickHouse采用了LSM树结构,所以使得Clickhouse的插入量可以很大。同时,Clickhouse的内部优化,使得在复杂查询的场景下,它也能够做到极快响应,且无须对数据进行任何预处理加工。达到了实时数仓的效果

9) 数据分片与分布式查询

Clickhouse拥有分布式能力,自然支持数据分片,数据分片是将数据进行横向切分,这是一种在面对海量数据的场景下,解决存储和查询瓶颈的有效手段。ClickHouse并不像其他分布式系统那样,拥有高度自动化的分片功能。ClickHouse提供了本地表 ( Local Table ) 与分布式表 ( Distributed Table ) 的概念。一张本地表等同于一份数据的分片。而分布式表本身不存储任何数据,它是本地表的访问代理,其作用类似分库中间件。借助分布式表,能够代理访问多个数据分片,从而实现分布式查询。

2、Clickhouse常见应用场景

  • 电信行业用于存储数据和统计数据使用;
  • 新浪微博用于用户行为数据记录和分析工作;
  • 用于广告网络和RTB,电子商务的用户行为分析;
  • 日志分析;
  • 检测和遥感信息的挖掘;
  • 商业智能;
  • 网络游戏以及物联网的数据处理和价值数据分析;
  • 最大的应用来自于Yandex的统计分析服务Yandex.Metri ca。

Clickhouse架构及性能

Clickhouse的集群架构是和其他的数据集群有一定的区别,他的集群能力是表级别的,而我们熟知的大数据体系,比如hadoop系列的集群都是服务级别的。例如,一个hdfs集群,所有文件都会切片、备份;而Clickhouse集群中,建表时也可以自己决定用不用,也就是说其实Clickhouse单节点就能存活。可能有其他的大数据经验的人对这种设计会有点奇怪,后面会从单机架构到集群架构,详细的去介绍。

=======================================================================================================================================================================================================

1、Clickhouse单机架构设计

官方介绍Clickhouse架构的资料比较匮乏,依据已有的经验结合外部资料,根据自己的理解还原Clickhouse的架构如下:

image
图3-1 clickhouse单机架构图

1)Parser与Interpreter

Parser和Interpreter是非常重要的两组接口:Parser分析器是将sql语句已递归的方式形成AST语法树的形式,并且不同类型的sql都会调用不同的parse实现类。而Interpreter解释器则负责解释AST,并进一步创建查询的执行管道。Interpreter解释器的作用就像Service服务层一样,起到串联整个查询过程的作用,它会根据解释器的类型,聚合它所需要的资源。首先它会解析AST对象;然后执行"业务逻辑" ( 例如分支判断、设置参数、调用接口等 );最终返回IBlock对象,以线程的形式建立起一个查询执行管道。

2)表引擎

表引擎是ClickHouse的一个显著特性,上文也有提到,clickhouse有很多种表引擎。不同的表引擎由不同的子类实现。表引擎是使用IStorage接口的,该接口定义了DDL ( 如ALTER、RENAME、OPTIMIZE和DROP等 ) 、read和write方法,它们分别负责数据的定义、查询与写入。

3)DataType

数据的序列化和反序列化工作由DataType负责。根据不同的数据类型,IDataType接口会有不同的实现类。DataType虽然会对数据进行正反序列化,但是它不会直接和内存或者磁盘做交互,而是转交给Column和Filed处理。

4)Column与Field

Column和Field是ClickHouse数据最基础的映射单元。作为一款百分之百的列式存储数据库,ClickHouse按列存储数据,内存中的一列数据由一个Column对象表示。Column对象分为接口和实现两个部分,在IColumn接口对象中,定义了对数据进行各种关系运算的方法,例如插入数据的insertRangeFrom和insertFrom方法、用于分页的cut,以及用于过滤的filter方法等。而这些方法的具体实现对象则根据数据类型的不同,由相应的对象实现,例如ColumnString、ColumnArray和ColumnTuple等。在大多数场合,ClickHouse都会以整列的方式操作数据,但凡事也有例外。如果需要操作单个具体的数值 ( 也就是单列中的一行数据 ),则需要使用Field对象,Field对象代表一个单值。与Column对象的泛化设计思路不同,Field对象使用了聚合的设计模式。在Field对象内部聚合了Null、UInt64、String和Array等13种数据类型及相应的处理逻辑。

5)Block

ClickHouse内部的数据操作是面向Block对象进行的,并且采用了流的形式。虽然Column和Filed组成了数据的基本映射单元,但对应到实际操作,它们还缺少了一些必要的信息,比如数据的类型及列的名称。于是ClickHouse设计了Block对象,Block对象可以看作数据表的子集。Block对象的本质是由数据对象、数据类型和列名称组成的三元组,即Column、DataType及列名称字符串。Column提供了数据的读取能力,而DataType知道如何正反序列化,所以Block在这些对象的基础之上实现了进一步的抽象和封装,从而简化了整个使用的过程,仅通过Block对象就能完成一系列的数据操作。在具体的实现过程中,Block并没有直接聚合Column和DataType对象,而是通过ColumnWith TypeAndName对象进行间接引用。

2、Clickhouse集群架构设计

Clickhouse是集群是通过配置clickhouse_remote_servers来管理集群的。在配置中,可以配置集群名字,集群所需要节点的信息,通过这些节点可以配置分片和副本机制。

简单的配置为例:

<yandex>
 <clickhouse_remote_servers>
 <cluster1>
 <shard>
 <internal_replication>true</internal_replication>
 <replica>
 <host>clickhouse-node1</host>
 <port>9000</port>
 </replica>
 <replica>
 <host>clickhouse-node2</host>
 <port>9001</port>
 </replica>
 </shard>
 <shard>
 <internal_replication>true</internal_replication>
 <replica>
 <host>clickhouse-node3</host>
 <port>9000</port>
 </replica>
 <replica>
 <host>clickhouse-node4</host>
 <port>9001</port>
 </replica>
 </shard>
 ...
 </cluster1>
 ...
 </clickhouse_remote_servers>
 ...
</yandex>

以上集群配置完之后,想要用到Clickhouse的集群能力,还需要使用Replicated MergeTree+Distributed引擎,该引擎是"本地表 + 分布式表"的方式,因此可以实现多分片多副本;下面具体介绍下Replicated MergeTree引擎和Distributed引擎。

1)Replicated*MergeTree引擎

首先需要介绍下MergeTree引擎,这也是Clickhouse存储数据的最核心引擎,之前所说的特点主要就是针对该引擎所描述的。MergeTree引擎则是在MergeTree基础上中扩展了一些功能引擎,包括支持ReplacingMergeTree,SummingMergeTree等等MergeTree家族引擎,详细了解可看官网mergetree引擎介绍,不带replication的MergeTree引擎都可以看成单机引擎,也就是说它们是在单节点上存在的。

而使用ReplicatedMergeTree就是将MergeTree引擎的数据通过Zookeeper调节,达到副本的效果。比如上述配置中,我们首先可以在cluster1中的每个节点上创建ReplicatedMergeTr ee表,通过配置文件,可以看到Clickhouse-node1和Clickho use-node2是在同一个shard里的,每个shard标签里的replica就代表复制节点。这时我们创建表时将两个副本指定在同一个zo okeeper目录下,那么写入到node1的数据会复制到node2,写入node2的数据会同步到node1,达到预计的复制效果。

到这里,每个节点上的本地表已经完成,但是多个分片的数据如何进行汇总,则需要下面的Distributed引擎。

2)Distributed引擎

使用Distributed引擎的表本身不存储任何数据,但允许在多个服务器上进行分布式查询处理,读取是自动并行的。在读取期间,会使用远程服务器上的表索引(也就是我们上述使用的Replicate d*MergeTree引擎)。

在读写数据时,如果使用Distributed表,可以按照配置文件配置的分片方案,从不同分片(shard)中读写数据,做到数据分片的效果。比如我们读取数据时,是通过Distributed引擎表读取,这个时候它会读取集群中的每个分片的数据做汇总计算。注意,这一块会有深度分页的情况,有些sql可以先分散在每个节点上执行完再在查询节点做结果聚合,而有些则无法做结果聚合,必须将所有数据同步到查询节点,由查询节点统一汇总,这种情况就需要根据具体的数据情况进行优化。

image
图3-2 本地表加分布式表的查询流程图

图3-2是一个2分片2副本的架构,使用的是Replicated*Merge Tree + Distributed引擎模式。红色的数字代表节点的话,也就是节点1和2互为副本,3和4互为副本。

图中events为Distributed引擎表,也叫分布式表;events_loc al为Replicated*MergeTree引擎表,也叫本地表。该图中,分布式表只在节点3中创建,线上环境一般会在每个节点上都创建一个分布式表(不会消耗资源,因为分布式表不会存储数据)。

执行查询时,会访问一个节点的分布式表,该图中访问的是节点3中分布式表。然后分布式表会分别的读取2个分片的数据,在这里,它读取了节点3和节点2的本地表数据,这两个节点加在一块就是完整的数据。汇总查询后将结果(Result Set)返回。

3、Clickhouse性能

1)插入:单机100-150M/s的插入速度;

2)查询:单字段groupby没有索引,1亿数据查询需要2.324s。有索引下,查询时间为0.101秒。可以看到Clickhouse的查询速度是及其快的,市面上常见的数据库基本都达不到这种性能;

3)其他:并发,官网默认配置为100。由于是大数据分析数据库主要适用于olap场景,对并发支持略差多个大数据查询可能会直接将cpu等资源占满,故并发实际达不到100。

Clickhouse在好未来的实践

image
图4-1 clickhouse线上架构图

1、业务场景

目前在好未来除了我们部门,在其他部门也已经有了多个业务方。

1) 本部门

使用平台:日志中心,猫头鹰,土拨鼠,grafana等。

使用方式:我们将需要的数据通过flink,spark,gohangout等工具消费kakfa,写入clickhouse,然后通过clickhouse做聚合查询,将数据展示出来。

比如,土拨鼠主要是通过网关数据做的聚合,可以看到各个域名,url或者服务器的调用次数,请求耗时等情况。再比如直播数据则是消费直播上报日志,用grafana将数据展示出来。

2) 其他部门

除了在本部门,还有其他业务方,数据研发部,数据中台等也都在使用,数据研发部主要会将hive中的热点数据通过spark/dataX同步至Clickhouse。然后将数据通过天枢天璇等平台展示给分析师使用,提高了查询速度。

image
图4-2:clickhouse使用图

2、存储现状

image
图4-3 单节点数据存储情况

以上数据第一列为库名,第二列为行数,第三列为压缩前大小,第四列为压缩后大小。

可以看到单个节点已有多个达到TB级别和百亿级别行数的数据库。目前数据节点是6个,也就是说在集群中,数据量需要再乘以6,代表有个别库库行数已达到千亿行,容量达到百T级别。

建设与规划

1、监控

Clickhouse官方目前没有提供直接的监控界面,但是所需要的监控数据在system库中都会记录下来,网上已有人通过grafana展示出来,目前的监控图如图5-1所示。
image
图5-1 clickhouse监控图

除此之外,还写了脚本,定期的对每个节点的探活及故障重启。同时也使用神树平台查看各个节点的硬件信息及告警。

2、遇到的问题

Clickhouse作为olap数据库,在使用过程中或多或少会出现一些问题,例如版本bug,使用不规范,混部出现的问题等,现在主要介绍几个需要持续优化或者业务配合的问题。其他遇到的一些问题也会在wiki上持续更新:

1) 大量查询导致服务器负载高情况,影响业务查询

分析:多个复杂查询,并且命中数据量极大的情况下。每个查询都会占用大量的cpu和内存。会导致服务器负载被打满的情况。尤其是内存被打满,会造成节点挂掉的现象。
解决:

  • 用户限制,避免内存被打满,可以配置max_memory_us age_ for_all_queries,使其低于服务器实际内存。并且还可以限制用户的并发,每次查询的数据量等;
  • 某些业务下无法限制查询数据量,可以添加缓存机制,避免大量大数据查询。

2) ddl语句卡死

分析:Clickhouse主要支持的是追加及查询,但是使用mergetr ee引擎的表,是可以做update和delete的。更新和删除操作是用alter table语句的,也就是说其实这是需要ddl的权限的。每一次这种操作,数据库都会发生加锁,更新表等操作,并且数据量大的情况下,做更新操作,整个数据都会根据索引情况重新排序,这是一个漫长的过程。Clickhouse的ddl语句底层应该是个队列,一个没执行完,也会导致其他ddl卡住。

解决:尽量减少ddl语句的执行频率以及增加执行间隔,或者尽量不要执行。

3) zookeeper失联

分析:Clickhouse集群方案很依赖zk,副本同步机制都是依赖zk的,导致每次插入数据都会和zk做交互,并且在zk中做写操作,插入并发高的情况下,可能会导致zk暂时失联。

解决:之前zookeeper是和Clickhouse混部,后期做了拆分,情况有一部分好转。但是目前依然会偶尔出现问题,后续会继续对这块优化,zookeeper的服务器性能也会去尽量完善,申请高配服务器,提高zookeeper的性能,使得不会因为zookeeper性能而影响到Clickhouse。

3、未来规划

想要打造一个高性能高稳定的大数据场景数据库,需要的是持续不断地学习以及和业务方的配合。

  • 深入了解业务,根据业务场景建表;
  • 持续学习clickhouse,根据clickhouse特性优化sql;
  • 同时也需要业务方配合,如果大查询频率较高,可以考虑使用缓存等机制,或者特定场景可以使用近似计算。同时特殊场景特殊对待,实现合适的sql;
  • 数据持续增长,查询压力也是越来越大,进行集群之间的隔离,使其重要业务之间不会互相影响;
  • 持续完善监控和告警机制;
  • clickhouse还有很多强大的功能,未来也会去尝试使用。

参考文献

[1] https://clickhouse.tech/docs
[2] https://blog.csdn.net/tzs_104...
[3] https://www.jianshu.com/p/ab8...


好未来技术团队
416 声望1.3k 粉丝

好未来作为一家科技驱动的教育企业,始终坚持“爱和科技让教育更美好”的使命。