烟台百度网站推广,300个吉祥公司取名大全,自己做的网站加载慢,西安百度竞价开户简介#xff1a; 本文尝试解读ClickHouse存储层的设计与实现#xff0c;剖析它的性能奥妙
作者#xff1a;和君 引言 ClickHouse是近年来备受关注的开源列式数据库#xff0c;主要用于数据分析#xff08;OLAP#xff09;领域。目前国内各个大厂纷纷跟进大规模使用…简介 本文尝试解读ClickHouse存储层的设计与实现剖析它的性能奥妙
作者和君 引言 ClickHouse是近年来备受关注的开源列式数据库主要用于数据分析OLAP领域。目前国内各个大厂纷纷跟进大规模使用 今日头条内部用ClickHouse来做用户行为分析内部一共几千个ClickHouse节点单集群最大1200节点总数据量几十PB日增原始数据300TB左右。腾讯内部用ClickHouse做游戏数据分析并且为之建立了一整套监控运维体系。携程内部从18年7月份开始接入试用目前80%的业务都跑在ClickHouse上。每天数据增量十多亿近百万次查询请求。快手内部也在使用ClickHouse存储总量大约10PB 每天新增200TB 90%查询小于3S。阿里内部专门孵化了相应的云数据库ClickHouse并且在包括手机淘宝流量分析在内的众多业务被广泛使用。在国外Yandex内部有数百节点用于做用户点击行为分析CloudFlare、Spotify等头部公司也在使用。 在开源的短短几年时间内ClickHouse就俘获了诸多大厂的“芳心”并且在Github上的活跃度超越了众多老牌的经典开源项目如Presto、Druid、Impala、Geenplum等其受欢迎程度和社区火热程度可见一斑。 而这些现象背后的重要原因之一就是它的极致性能极大地加速了业务开发速度本文尝试解读ClickHouse存储层的设计与实现剖析它的性能奥妙。 ClickHouse的组件架构 下图是一个典型的ClickHouse集群部署结构图符合经典的share-nothing架构。 整个集群分为多个shard分片不同shard之间数据彼此隔离在一个shard内部可配置一个或多个replica副本互为副本的2个replica之间通过专有复制协议保持最终一致性。 ClickHouse根据表引擎将表分为本地表和分布式表两种表在建表时都需要在所有节点上分别建立。其中本地表只负责当前所在server上的写入、查询请求而分布式表则会按照特定规则将写入请求和查询请求进行拆解分发给所有server并且最终汇总请求结果。 ClickHouse写入链路 ClickHouse提供2种写入方法1写本地表2写分布式表。 写本地表方式需要业务层感知底层所有server的IP并且自行处理数据的分片操作。由于每个节点都可以分别直接写入这种方式使得集群的整体写入能力与节点数完全成正比提供了非常高的吞吐能力和定制灵活性。但是相对而言也增加了业务层的依赖引入了更多复杂性尤其是节点failover容错处理、扩缩容数据re-balance、写入和查询需要分别使用不同表引擎等都要在业务上自行处理。 而写分布式表则相对简单业务层只需要将数据写入单一endpoint及单一一张分布式表即可不需要感知底层server拓扑结构等实现细节。写分布式表也有很好的性能表现在不需要极高写入吞吐能力的业务场景中建议直接写入分布式表降低业务复杂度。 以下阐述分布式表的写入实现原理。 ClickHouse使用Block作为数据处理的核心抽象表示在内存中的多个列的数据其中列的数据在内存中也采用列存格式进行存储。示意图如下其中header部分包含block相关元信息而id UInt8、name String、_date Date则是三个不同类型列的数据表示。 在Block之上封装了能够进行流式IO的stream接口分别是IBlockInputStream、IBlockOutputStream接口的不同对应实现不同功能。 当收到INSERT INTO请求时ClickHouse会构造一个完整的stream pipeline每一个stream实现相应的逻辑 InputStreamFromASTInsertQuery #将insert into请求封装为InputStream作为数据源
- CountingBlockOutputStream #统计写入block count
- SquashingBlockOutputStream #积攒写入block直到达到特定内存阈值提升写入吞吐
- AddingDefaultBlockOutputStream #用default值补全缺失列
- CheckConstraintsBlockOutputStream #检查各种限制约束是否满足
- PushingToViewsBlockOutputStream #如有物化视图则将数据写入到物化视图中
- DistributedBlockOutputStream #将block写入到分布式表中
注*左右滑动阅览 在以上过程中ClickHouse非常注重细节优化处处为性能考虑。在SQL解析时ClickHouse并不会一次性将完整的INSERT INTO table(cols) values(rows)解析完毕而是先读取insert into table(cols)这些短小的头部信息来构建block结构values部分的大量数据则采用流式解析降低内存开销。在多个stream之间传递block时实现了copy-on-write机制尽最大可能减少内存拷贝。在内存中采用列存存储结构为后续在磁盘上直接落盘为列存格式做好准备。 SquashingBlockOutputStream将客户端的若干小写转化为大batch提升写盘吞吐、降低写入放大、加速数据Compaction。 默认情况下分布式表写入是异步转发的。DistributedBlockOutputStream将Block按照建表DDL中指定的规则如hash或random切分为多个分片每个分片对应本地的一个子目录将对应数据落盘为子目录下的.bin文件写入完成后就返回client成功。随后分布式表的后台线程扫描这些文件夹并将.bin文件推送给相应的分片server。.bin文件的存储格式示意如下 ClickHouse存储格式 ClickHouse采用列存格式作为单机存储并且采用了类LSM tree的结构来进行组织与合并。一张MergeTree本地表从磁盘文件构成如下图所示。 本地表的数据被划分为多个Data PART每个Data PART对应一个磁盘目录。Data PART在落盘后就是immutable的不再变化。ClickHouse后台会调度MergerThread将多个小的Data PART不断合并起来形成更大的Data PART从而获得更高的压缩率、更快的查询速度。当每次向本地表中进行一次insert请求时就会产生一个新的Data PART也即新增一个目录。如果insert的batch size太小且insert频率很高可能会导致目录数过多进而耗尽inode也会降低后台数据合并的性能这也是为什么ClickHouse推荐使用大batch进行写入且每秒不超过1次的原因。 在Data PART内部存储着各个列的数据由于采用了列存格式所以不同列使用完全独立的物理文件。每个列至少有2个文件构成分别是.bin 和 .mrk文件。其中.bin是数据文件保存着实际的data而.mrk是元数据文件保存着数据的metadata。此外ClickHouse还支持primary index、skip index等索引机制所以也可能存在着对应的pk.idxskip_idx.idx文件。 在数据写入过程中数据被按照index_granularity切分为多个颗粒granularity默认值为8192行对应一个颗粒。多个颗粒在内存buffer中积攒到了一定大小由参数min_compress_block_size控制默认64KB会触发数据的压缩、落盘等操作形成一个block。每个颗粒会对应一个mark该mark主要存储着2项信息1当前block在压缩后的物理文件中的offset2当前granularity在解压后block中的offset。所以Block是ClickHouse与磁盘进行IO交互、压缩/解压缩的最小单位而granularity是ClickHouse在内存中进行数据扫描的最小单位。 如果有ORDER BY key或Primary key则ClickHouse在Block数据落盘前会将数据按照ORDER BY key进行排序。主键索引pk.idx中存储着每个mark对应的第一行数据也即在每个颗粒中各个列的最小值。 当存在其他类型的稀疏索引时会额外增加一个col_type.idx文件用来记录对应颗粒的统计信息。比如 minmax会记录各个颗粒的最小、最大值set会记录各个颗粒中的distinct值bloomfilter会使用近似算法记录对应颗粒中某个值是否存在在查找时如果query包含主键索引条件则首先在pk.idx中进行二分查找找到符合条件的颗粒mark并从mark文件中获取block offset、granularity offset等元数据信息进而将数据从磁盘读入内存进行查找操作。类似的如果条件命中skip index则借助于index中的minmax、set等信心定位出符合条件的颗粒mark进而执行IO操作。借助于mark文件ClickHouse在定位出符合条件的颗粒之后可以将颗粒平均分派给多个线程进行并行处理最大化利用磁盘的IO吞吐和CPU的多核处理能力。 总结 本文主要从整体架构、写入链路、存储格式等几个方面介绍了ClickHouse存储层的设计ClickHouse巧妙地结合了列式存储、稀疏索引、多核并行扫描等技术最大化压榨硬件能力在OLAP场景中性能优势非常明显。
原文链接
本文为阿里云原创内容未经允许不得转载。