ClickHouse(二)-工作原理

1 MergeTree表引擎

1.1关于MergeTree表引擎区别

  • 第一 : MergeTree表引擎主要用于海量数据的分析,支持数据分区、存储有序、主键索引(是稀疏索引)、稀疏索引、数据TTL等.MergeTree支持Ck的所有SQL语法,但是有些功能和MySQL是并不一致,比如在MergeTree中主键并不用于去去重

  • 第二:为了解决MergeTree相同注解无法去重问题,ck提供了ReplacingMergeTree引擎,用于做去重.ReplacingMergeTree确保数据最终被去重,但是无法保证查询过程中主键不重复.因为相同主键的数据可能被shared到不同的节点,但是compaction只能在一个节点进行(是否意味着针对需要折叠的多节点存储的数据分区必须为业务的唯一键?),而且optimize的时机也不确定

  • 第三: CollapsingMergeTree引擎要求在建表语句中指定一个标记列sign(插入时候指定为1,删除时指定为-1),后台compaction时会将主键相同、sing相反的数据进行折叠,完成ReplacingMergeTree在去重时无法删除数据操作(说明完全可以将RDS库的binlog放到此引擎表中,还原出最新的数据,个人简称binlog还原)

  • 第四:为了解决CollapsingMergeTree乱序写入情况下无法完成正常折叠的问题,VersionedCollapsingMergeTree表引擎在建表语句中新增一列Version,用于在乱序情况下记录状态行与取消行的对应关系,主键相同且Version相同、sing相反的行,在compaction时会被删除

  • 第五:ClickHouse通过SummingMergeTree来支持对主键列进行sum预先聚合,在后台Compaction时,会将主键相同的多行进行SUM求和,然后使用一行数据取而代之,从而大幅度降低存储空间的占用,提升聚合计算的性能.

  • 第六:AggregatingMergeTree也是预聚合引擎的一种,用于提升聚合计算的性能,与SummingMergeTree的区别在于:SummingMergeTree对主见列进行Sum聚合,而AggregatingMergeTree则可以指定各种聚合函数。

1.2 建表语句剖析

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
    name1 [type1] [NULL|NOT NULL] [DEFAULT|MATERIALIZED|ALIAS expr1] [compression_codec] [TTL expr1],
    name2 [type2] [NULL|NOT NULL] [DEFAULT|MATERIALIZED|ALIAS expr2] [compression_codec] [TTL expr2],
    ...
) ENGINE = engine
	[PARTITION BY expr]
	[ORDER BY expr]
	[PARIMARY KEY expr]
	[SAMPLE BY expr]
	[SETTINGS name=value,省略...]
  • PARTITION BY :分区建.指定表数据以何种标准进行分区,分区键既可以是单个列字段,也可以通过元组的形式使用多个列字段,同时它也支持使用列表达式,如果我们可以可用某个时间字段的天作为分区键
  • ORDER BY:排序键,用于指定在一个数据片段内,数据以何种标准排序,默认情况下主键(PARIMARY KEY)与排序键相同
  • PARIMARY KEY:主键,申明后会依照主键生成一级索引,默认情况下,主键与排序键相同,所以通常直接使用ORDEY BY代为指定主键
  • SETTINGS:表的配置字段,可以配置如 :index_granularity
  • SAMPLE BY: 抽样表达式,用于申明数据以何种标准进行采样

注意setting中的重要参数

1 index_granularity:索引的粒度,默认值是8192,即MergeTree在默认情况下,每隔8192行生成一条索引
2 index_granularity_bytes:索引的粒度,默认是10M,未开启,通过将设置enable_index_granularity_parts为1开启

2 ClickHouse工作原理

ck从OLAP场景需求出发,定制开发列一套全新的高效列式存储引擎,并实现了数据有序存储主键索引稀疏索引数据Sharding数据PartitioningTTL主备复制等丰富功能.这些功能为ClickHouse极速的分析性能奠定了基础。

2.1 数据分区

数据分区最大目的是查询时分区裁剪,减少数据量的读取.

**MergeTree表的分区目录物理结构:**存储了数据以及元数据信息

cE5EJU.jpg
  • 分区目录: 20190710_20190711_1_5_1一个分区可能会有多 个不同的目录,该目录下存储该分区的数据及其他各种形式的数据。后台在执行合并时,会把相同分区的多个目录合并到一个分区。

  • 校验文件: checksums.text,使用二进制格式存储,它保存了余下各类文件(等)的size大小以及size的哈希值,用于快速校验文件的完整性以及正确性

  • 列信息文件:columns.txt,使用明文格式存储,用于保存此数据分区下的列字段信息

  • 计数文件:count. txt,使用明文格式存储,用于记录当前数据分区目承下数据的总行数

  • 一级索引文件:primary.idx ,主键索引文件

  • 数据文件:xxx.bin,使用压缩格式存储,默认为LZ压缩格式,用于存储某列的数据, 每列都对应一个文件,如列date为date.bin

  • 列字段标记文件:xxx.mrk2,如果使用了自适应大小的索引间隔,则标记文件以.mrk2命名,它建立primary. idx稀疏索引与xxx.bin数据文件之间的映射关系,先通过主键索引在mrk2文件中找到数据的偏移量(要找的数据块在xxx.bin中的位置),然后去xxx.bin数据文件中找到真实的数据

  • 其它文件:还有二级索引和分区键相关信息文件等等

分区目录的命名规则:partitionId_mixblockNum_maxblocknum_level

cVeujS.jpg

分区目录的合并规则:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jq8AwzHU-1617692160961)(https://z3.ax1x.com/2021/04/01/cVmwxf.jpg)]

由上述文件合并过程可知道ck并不适合点查以及小数据量的实时写入,内部都是通过文件的复制完成数据的更新合并.注意:分区在合并过程中并不影响ck的查询效率,合并分区的目的是为了后续提高查询的效率

6.3.2 列式存储

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WMAolIk4-1617692160962)(https://z3.ax1x.com/2021/04/01/cVKEqS.jpg)]

相比于行式存储,列式存储在分析场下有着许多优良的特性:

  • 分析场中往往需要读大量行但是少数几个列,在行存模式下,数据按行连续存储,所有列的数据都存储在一个 block中,不参与计算的列在IO时也要全部出,读取操作被严重放大。而列存模式下,只需要读取参与计算的列即可,极大的低了IO cost,加速了查询.

  • 同一列中的数据属于同一类型,压缩效果显著。列存往往有着高达十倍甚至更高的压缩比,节省了大量的存储空间,降低了存储成本

  • 更高的压缩比意味着更小的 data size,从盘中读取相应数据耗时更短,

  • 自由的压缩算法选择。不同列的数据具有不同的数据类型,适用的压缩算法也就不尽相同,可以针对不同列类型,选泽最合适的压缩算法

  • 高压比,意味着同等大小的内存能够存放更多数据,系统 cache效果更好

6.3.3一级索引(主键索引)

关于一级引: Mergetree的主健使用 PRIMARY KEY定义,待主键定义之后, Mergetree会依据 index_granularity间隔(默认8192行),为数据表生成一级索引并保存至 primary.idx文件内,一级索引是稀疏索引,意思就是说:每一段数据生成一条引记录,而不是每一条数据都生成索引,如果是每一条数据都生成索引,则是稠密索引。稀疏索引的好处就是通过较少的索引量记录大量的数据区间位置信息,比如不到24414条标记信息,就能为2E条数据提供索引(算法200000000*8192)。在 Clickhouse中,一级索引常駐内存。总的来说一级素引和标记文件一一对齐,两个索引标记之间的数据,就是一个数据区间,在数据文件中,这个数据区间的所有数据,生成一个压缩数据块(并不准确)

cV1lY4.jpg

cV3duq.jpg]

6.3.4 二级索引

二级索引:又称之为跳数索引(在一级索引基础上进行的操作)。目的和一级引一样,是为了减少待搜寻的数据的范围。跳数素引的默认是关闭的,需要通过set allow_ experimental_data_ skipping_ indices=1来开启,索引生成粒度由 granularity控制,如果生成了二级素引,则会在分区目录下生成额外的 skp_idx_[Column).idxskp_dx_ [Column). mrk文件。跳数素引的生成规则:按照特定规则每隔 granularity个 index_granularity(一级索引),就会生成一条跳数索引.比如 minmax跳数索引,生成的是: granularity个 index_granularity条数据内的最大值最小值生成一条素引,如果将来需要针对构建二级素引的这个字段求最大值最小值,则可以帮助提高效率。跳数素引一共支持四种类型: minmax(最大最小)、set(去重集合)、 ngrambf_v( ngram分词布索引)和 tokens_v1(标点符号分词布降素引),一张数据表支持同时声明多个跳数素引比如:

create table skip_test( 
	ID string,
	URL String, 
	Code string, 
	Eventtime Date,
	INDEX a ID type minmax GRANULARITY 5, 
	INDEX b (length(ID)*8)type set(2) GRANULARITY 5 ,
	INDEX c (ID, Code) type ngrambf_v1(3,256,2,o) GRANULARITY 5 ,
	INDEX d ID type tokenbf-vl(256,2,0) GRANULARITY 5 
) ENGINE = MergeTree()
	ordert by id

关于跳数索引支持的多种类型的区别:

1、minmax:以index_granularity为单位,存储指定表达式计算后的min、 max值;在等值和范围查询中能够帮助快速跳过不满足要求的块,减少IO。
2、set(max_ rows): 以index_granularity为单位,存储指定表达式的distinct value集合,用于快速判断等值查询是否命中该块,减少IO。
3、ngrambf_v1(n,size_of_b1oom_filter_in_bytes,number_of_hash_functions,random_seed): 将string进行ngram分词后构建bloomfilter,能够优化等值、like、in等查询条件。
4、tokenbf_v1(size_of_bloom_fiter_in_bytes, number_of_hash_functions, random_seed):与ngrambf.n类似,区别是不使用ngran进行分间,而是通过标点符号进行词语分割。
5. b1oom_fiter([false_positive]): 对指定列构建b1ooom fiter.用于加速等值、like. in等查询条件的执行。

6.3.5 数据压缩

ClickHouse 的数据存偖文件column.bin中存偖是一列的数据,由于一列是相同类型的数据,所以方便高效圧縮。在迸行压缩的吋候,请注意:1个圧縮数据快头部信息和圧縮数据块两部分組成,头部信息固定使用9位字节表示,具体由1个UInt8 (1字芍)整型和2个Ulnt32 (4字节)整型組成,分別代表使用的圧縮算法类型圧縮后的数据大小和圧縮前的数据大小。毎个压缩数据快的体积,按照其圧縮前的数据字节大小,都被严格控制在64KB~1MB,其上下限分別由min_ compress _block size (默圦65536=64KB) 与max compress. block. size (默人1048576=1M) 参数指定。具体圧縮規則:

原理的说法:毎8192条记录,其实就是一条一級索引(准确) 一个索引区间压缩成一个数据抉(并不准确)。 自适应压缩

1、単个批次数据size < 64KB: 如果単个批次数据小于64KB, 则继续茯取下一批数据, 直至累釈到size >= 64KB吋,生成下-个圧縮数据快。如果平均毎条記汞小于8byte,多个数据批次圧縮成一个数据快

2、単个批次数据64KB<= size <=1MB: 如果単个批次数据大小恰好在64KB 与1MB之向,則直接生成下一个圧縮数据抉。

3、単个批次数据size > 1MB: 如果単个批次数据直接超辻1MB.則首先按照1MB 大小截断并生成下一个圧縮数据快。剰余数据继续依照上述规则执行。此肘,会出現一个批次数据生成多个圧縮数据抉的情况。如果平均毎条记录的大小超辻128byte,則会把当前込一个批次的数据医縮成多个数据央

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-t6v7jVDO-1617692160963)(https://z3.ax1x.com/2021/04/06/clGHfA.jpg)]

**总结1:**在一个xxx.bin字段存储文件中,并不是一个压缩块对应一条一级索引
总结2:在一个xxx.bin其实是由一个个的连续存储的压缩数据块组成的,每个压缩块压缩前的大小在64K-1M之间
总结3:基于压缩块的连续存储以及头文件的标记信息,我们在读取数据时非常方便的定位压缩数据块在文件中中的起始起始偏移量

6.3.6 数据标记

数据标记文件也与.bin 文件一一对应。 即每一个列字段[Column].bin 文件都有一个与之对应的[Column].mrk2数据标记文件,用于记录数据在.bin文件中的偏移量信息。一行标记数据使用一个元组表示,元组内包含两个整型数值的偏移量信息。它们分别表示在此段数据区间内,在对应的.bin 压缩文件中,压缩数据块的起始偏移量以及将该数据压缩块解压后,其解 压缩数据的起始偏移量。每一行标记数据都表示了一个片段的数据(默认8192行)在.bin压缩文件中的读取位置信息。标记数据与一级索引数据不同,它并不能常驻内存,而是使用LRU (最近最少使用)缓存策略加快其取用速度。

总结数据读取流程: 先根据一级索引,找到标记文件中的对应数据压缩块信息 (压缩块在.bin文件中的起始偏移量和未压缩之前该条数据的是偏移量)然后从.bin文件中,把压缩块加载到内存,解压缩之后,执行读取。数据标记文件建立了主键索引到数据文件间的映射关系!

6.3.7 查询数据

ck如何做到快速加载数据?

select name from student where date = 201905;

指定分区(date为分区字段)、分区裁剪==>指定字段(xxx.bin primary.idx)、读取对应列 > 根据一级索引定位到标记文件中的那一条记录> 扫描对应字段的mark标记文件获取两个偏移量信息 > 根据第一个偏移量去.bin文件中定位到一个压缩数据快>读取数据到内存执行解压缩==>根据第二个偏移量去内存解压缩数据中找到对应的数据

分区、列式存储、 一级索引、二级索引、数据压缩、数据标记等多样的辅助动作决定了ck能高效的从磁盘中加载我们想要的数据,即使是使用机械硬盘。

提高数据查询效率的核心原则只有一个:通过辅助动作能快速的降低待搜寻的数据范围

分布式系统的核心思想:分而治之,必须提供一套架构方便用户的请求被快速的定位到某 个单台服务器去处理。一般来说, 这个服务器处理这个请求,都是很快的!

扩展1: ck的join效果很差,最佳方式是通过spark、flink离线计算生成宽表写入ck,ck是世界上单表分析最优秀的引擎
扩展2:ck不适合kv、单点查询,最适合场景就是单表分析
扩展3: 分布式部署新增节点后,ck会自动进行数据平衡
扩展4:ck并不适合做join,但是雾化视图确实是其实现的一种折中方案,个人觉得并不具备广泛的推广性,过于复杂
扩展5: 维度固定、查询请求高,首选kylin
扩展6:在大数据场景绝大数无upsert场景需求,若使用到upsert则脱离了OLAP场景需求,建议用kudu+impala。对于upsert场景无论是ck、doris、kylin虽然支持但是支持的都是很差的,都是象征性支持。
扩展7:ck二级索引构建分词索引有时并不满足需求,业界推荐ES+HBase,先查ES获取匹配到的数据的rowkey,然后查询HBase获取最终数据。
扩展8: ck在双表通过位图方式join也有很高的性能,但是相较于doris,doris的大表、多表join查询性能更加的优秀
扩展9:ck的insert into语法是异步操作的。通常分布式存储组件HBase等导入都是异步的
扩展10:几TB以下数据量级别的分析,ck直接使用默认配置即可,当超过几十TB时就需要就一步配置调优了
扩展11:若出现分区目录长时间未合并,可通过手动运行命令促进分区目录合并
扩展12:mysql单表上2千万后,统计分析性能呈现指数级别下降,同理es、lucence、solr当单索引量超过20亿时,性能也是会指数级别下降,业界生产环境es集群很少超过三十台,相对来说ck集群规模能过千

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值