ClickHouse
2021-11-24 14:28:34 2 举报
AI智能生成
ClickHouse关键流程和原理总结
作者其他创作
大纲/内容
分区Id
PartitionId
最小数据块编号
MinBlockNum
最大数据块编号
MaxBlockNum
分区被合并的次数
Level
PartitionId_MinBlockNum_MaxBlockNum_Level
命名标准
索引文件
描述
用于存放稀疏索引
作用
primary.idx
标记文件
保存了bin文件中数据的偏移信息,用于建立primary.idx和[Column].bin之间的映射
[Column].mrk2
数据文件
存储数据,默认使用lz4压缩存储
[Column].bin
分区文件
保存分区表达式生成的值
partition.dat
minmax索引
用于记录当前分区下分区字段的最小值和最大值
minmax_[Column].idx
列信息文件
保存表的列字段信息
columns.txt
列数文件
记录当前分区目录下数据的总行数
count.txt
校验文件
存放以上各个文件的size以及hash值,用于快速校验文件的完整性
checksums.txt
目录内文件列表
目录结构
表结构示例
设置index_grandulity为2
数据插入
按照主键字段生成,用于加快表查询
小端从右往左读
大端从左往右读
id 是UInt64类型,用8字节小端模式存储,所以前8个字节是0X03
Name是String类型,变长字段,先使用1个字节存储String长度,Lisa长度是4,所以第九个字节是0X09
8 bytes
大小
代表该标记指向的压缩数据块在bin文件中的偏移量
数据
offset in compressed file
代表该标记指向的数据在解压数据块中的偏移量
offset in decompressed block
行数,通常情况下等于index_granularity
Rows count
mrk2文件格式
Id.mrk2
表达式生成的值为200002,UInt32类型,转换为16进制就是0x00030d42
分区字段的Birthday的类型为data,底层由UInt16实现,存储的是从1970年1月1日到现在所经过的天数
插入数据的最小值和最大值分别是2000-02-03和2000-02-08
转换为天数分别是10990和10995
转换为16进制分别为0X2aee和0x2af3
minmax_Birthday.idx
16 bytes
对后面的数据进行校验
功能
checksum
1 byte
默认LZ4,编号0X82
compression algorithm
4 bytes
其值等于Compression algorithm + Compressed size + Decompressed size + Compressed data的长度
compressed size
数据解压缩后的长度
decompressed size
压缩数据
长度为Compressed size - 9
compressed data
数量由min_compress_block_size控制
如果大于,则把当前block进行压缩然后写到磁盘
如果不大于,则继续等待下一个granule
每次block写完一个granule的数据时,会校验当前block size是否大于等于min_compress_block_size
Granule
由若干个Block组成
(3,4,6,12)总大小为32,大于24,所以压缩到第一个Block中,最后一个31在第二个Block
Id.bin
文件详解
文件组织
二分查找
primary.idx文件较小,可以常驻内存
确定primary.idx中的数据位置
primary.idx数据与mrk2数据是一一对应的
从逻辑上来说,可以认为两者是下标对齐的
确定id.mrk2中的位置
先根据offset in compressed file 确定在哪个block中(block起始偏移量)
再根据offset in decompressed block确定在选中block中的位置(相对偏移量,从0开始)
确定block位置
基于主键列查询
全表扫描
基于非主键列查询
过程拆分
索引过程
PartitionId,分区Id不变
MinBlockNum,取该分区中最小的MinBlockNum
MaxBlockNum,取该分区中最大的MaxBlockNum
Level,取该分区中最大的level加1
合并原则
上面的两个分区目录200002_1_1_0和200002_2_2_0在过一段时间后最终会变成一个新的分区目录200002_1_2_1
示例
分区合并
MergeTree
存储结构
数据被顺序append写到磁盘上
不支持delete,update
不支持索引
不支持原子写
插入阻塞查询
原理
不支持并发读取,性能差,格式简单,适合存储中间数据
TinyLog
支持并发读取,每个列存储在单独文件中,性能较好
Log
支持并发读取,所有列存放在一个文件中,性能较好
StripeLog
分类
Log系列
HDFS
MySQL
Kafka
RabbitMQ
JDBC
ODBC
Integration系列
目前CK处理能力最好的引擎
支持索引,同时提供数据的实时更新能力
简介
按主键移除重复记录
不保证任意时刻都不出现重复
optimize命令,耗时较大
在执行分区合并时,会触发删除重复数据,无法预测具体执行时间点,除非是手动执行
以分区为单位删除重复数据,只有在相同的数据分区内重复的数据才能够被删除
如果没有设置版本号,则保留最新插入的数据,否则保留ver字段最大的一行
ReplacingMergeTree
按主键对数值类型的列求合
其余的列会保留先插入的值,后插入的值会被丢弃
SummingMergeTree
uniq
anyif
quantiles
对主键做聚合
AggregatingMergeTree
写新state行是,异步折叠(删除)与之排序key重复的行
用于数据快速更新最新值并顺序入表的场景
CollapsingMergeTree
基本同CollapsingMergeTree
允许多线程乱序入表
通过Version列保证正确
VersionedCollapsingMergeTree
作为后端存Graphite数据
GraphiteMergeTree
MergeTree系列
数据存储在内存,重启数据丢失,读写不阻塞,不支持索引
Memory
在同一个server上吧多张相同结构的物理表合并为一张逻辑表
Merge
在不同的server上吧多张相同结构的物理表合并为一张逻辑表
Distributed
...
Special系列
表引擎
ENGINE
分区建
PARTITION BY
指定数据以何种方式进行排序
默认情况下排序建和主键相同
排序键
ORDER BY
每隔多少行数据生成一条索引
默认8192
索引粒度
index_granularity
表示最小压缩的block大小
默认65536
min_compress_block_size
限制大小生成一条索引
默认10M
为0表示不启用自适应功能
自适应索引
index_granularity_bytes
是否开启自适应索引功能
默认开启
enbale_mixed_granularity_parts
数据TTL功能
merge_with_ttl_timeout
多路径存储策略
storage_policy
配置
SETTINGS
建表要素
就是一个临时表
本质
创建语句
在源数据表有数据写入时,如果检测到有物化视图跟它关联,会针对这批写入的数据进行物化操作
只能保证最终一致性
更新机制
物化视图
节点收到用户的分布式DDL请求
struct DDLLogEntry{ String query; std::vector<HostID> hosts; String initiator; // optional static constexpr int CURRENT_VERSION = 1; ...}
LogEntry
节点校验DDL合法性
,在zookeeper任务队列中创建znode并上传DDL LogEntry
同时在LogEntry的Znode下创建active和finish两个状态同步的znode
查询节点处理请求
cluster中的节点后台消费线程消费zookeeper中的LogEntry队列执行处理逻辑
处理过程中吧自己注册到active znode下,并把结果写回到finish znode下
Cluster节点处理请求
轮询LogEntry Znode下的active和finish状态znode
当目标节点全部执行完成或者触发超时逻辑时,用户就会获得结果反馈
查询节点读取Cluster执行结果
执行过程
分布式DDL执行
写入同步
异步Merge同步
异步Mutation同步
同步类型
不是经典的主从模型(主节点执行更新,从节点同步follow),主备都可以写,同步是双向的
不是物理同步,没有基于物理文件的wal
逻辑同步日志粒度是MergeTree的DataPart级别(Data Part Log),没有单记录的同步日志
同步特征
把数据写入到本地临时Data Part中
从zookeeper上申请自增的block number序列号
检查本地表的meta版本是否已经落后于zookeeper上的状态
前置检查
上传一个GET_PART类型的Log到Shard对应的Zookeeper目录下的log znode下
其他副本通过观察zookeeper来异步拷贝写入的Data Part
commit临时Data Part
过程分解
一次Batch写入的过程和zookeeper交互的次数不下10此,要是Batch数据跨10个数据分区的话就是100次
使用Clickhouse时一定要做Batch写入并且按照数据分区提前聚合
性能问题
望Zookeeper提交GET_PART Log时Zk session断开或者超时
本地的Data Part会继续commit,并跑错给用户重试写入数据,同时把Data Part丢到一个异步检查线程的任务队列中
异步检查线程会等待重连Zookeeper,检查本地的Data Part是否注册到Zookeeper上
如果没有则会移除本地的Data Part
一致性保证
降低zookeeper压力配置
每个新写入的Data Part不再注册自己的columns信息和checksums到Zookeeper上
而是压缩成Hash值写到Data Part的Znode data中
use_minimalistic_part_header_in_zookeeper
写入链路检查数据同步的副本数达到要求才能够成功返回
写入节点在Commit Data Part时还会创建一个Shard级别的quorum/status Znode,其他节点同步完数据之后需要更新到quorum/status,写入节点这边通过Watch机制收到通知再返回客户的写入请求
insert_quorum
对每次收到的批量写入数据计算一个Hash Value,然后注册到Zookeeper上。后续如果出现完全重复的一批数据,写入链路上会出现Zookeeper创建重复节点异常,用户就会收到重复写入反馈
insert_deduplicate
优化参数
同步写入
同步Zookeeper中Shard级别下的Data Part Log任务队列数据到自己的Znode任务队列中
在自己的Znode下维护更新当前正在处理的log_pointer(当前已经拷贝过的最大log Id)和min_unprocessed_insert_time(近似评估写入的延迟时间)信息
把任务放到节点的RAM队列中
StorageReplicatedMergeTree::queueUpdatingTask
从Zookeeper的Shard级别下的Mutation任务队列同步数据到节点的RAM状态中
是依赖Zookeeper的Watch机制来通知ClickHouse的BackgroundSchedulePool调度起工作Task,包括上一个queueUpdatingTask也是相同机制被调度
StorageReplicatedMergeTree::mutationsUpdatingTask
负责从RAM任务队列中消费执行具体的操作,并且会有多个后台线程被调度起并行执行多个任务
ClickHouse在RAM状态中追踪了所有正在执行的任务即将产生和依赖的Data Part,可以保证有数据依赖关系的任务串行化执行
对于\"GET_PART\"类型的任务,Task执行逻辑会尝试从远端节点下载数据到本地,同时如果有quorum数量要求的话更新quorum统计信息
尝试从远端下载merge完成的Data Part
每次merge、mutation的开销都是非常大的,配置只选择主副本完成merge、mutation任务,而让其他副本直接从远程下载可以大幅减轻集群的负载
当一些极端场景出现,远端的结果Data Part N也无法下载时(一般是这个任务对应的远端Data Part N再次发生了数据变更变成了Data Part M),节点会把当前这个任务放回到任务队列的尾端,让它延迟执行
对于\"MERGE_PARTS\",\"MUTATE_PART\"的任务,节点首先会尝试在本地进行实际的merge或者mutation动作,但是当本地的Input Data Part存在缺失或者损坏时,ClickHouse可以采用保守策略
StorageReplicatedMergeTree::queueTask
这个Task的只有主副本节点会调度,它负责不断选择下一次要进行merge / mutation的Data Parts,把具体的merge / mutation的任务日志发布到Zookeeper的任务队列上
新写入的Data Part只有同步到全部副本节点后才可以参与merge
StorageReplicatedMergeTree::mergeSelectingTask
这个异步Task主要是配合ClickHouse的存储分层设计
当高性能(SDD)的存储空间快用满时,它会不断自动地把数据往更低级(HDD)的存储上去迁移
StorageReplicatedMergeTree::movePartsTask
这个Task的作用是异步去更新当前副本的mutation任务队列执行进度
StorageReplicatedMergeTree::mutationsFinalizingTask**
异步Task
同步过程
ReplicatedMergeTree表主备节点之间状态同步
zookeeper依赖
ReplicatedMergeTree
主从复制
ClickHouse
0 条评论
回复 删除
下一页