当前位置: 首页 > news >正文

Clickhouse数据副本和分片

Clickhouse数据副本与分区

为什么会存在集群呢?

随着业务量的增长,单节点的压力会随着增大,如果单节点挂掉,那么该CK就无法使用,存在单点故障的问题,所以引申出集群的概念

分片和副本:

简而言之,分片之间的数据完全不同,副本之间的数据完全相同,副本是防止数据丢失,增加数据冗余;分片的主要目的是数据的水平切分。

在这里插入图片描述

演进的过程:

单表单副本->存在单点压力,数据无法保障高可用

单表多副本->解决单点压力和数据高可用问题,但数据存储容量有限,无法做到横向扩展

单表多副本多分片->解决数据横向扩展问题,数据根据某个规则划分存储到不同的实例上

在这里插入图片描述

一、数据副本

简而言之,对于MergeTree系列的引擎在前面加上Replicated建表,说明该表是一个具备数据副本能力的。

在这里插入图片描述

只有使用了ReplicatedMergeTree复制表系列引擎,才能应用副本的能力。ReplicatedMergeTree是MergeTree的派生引擎,它在MergeTree的基础上加入了分布式协同的能力

在这里插入图片描述

示意图:

在MergeTree中,一个数据分区由开始创建到创建完成,会经历两个不同的存储。

  1. 内存:数据首先会被写入到内存的缓冲区中
  2. 本地磁盘:数据接着会被写入tmp临时目录分区,待全部完成后再将临时目录重命名为正式分区。

ReplicatedMergeTree在上述基础之上增加了ZooKeeper的部分,它会进一步在ZooKeeper内创建一系列的监听节点,并以此实现多个实例之间的通信。在整个通信过程中,ZooKeeper并不会涉及表数据的传输。

副本的特点(Replicated*)

  1. 依赖zookeeper,在执行Insert、Alter时,ReplicatedMergeTree需要依托zookeeper的分布式协同能力,以实现多个副本之间的同步
  2. 表级别的副本,副本是在表级别的,针对每张表的副本配置,可以设置不同的副本数以及副本其他信息,包括副本的数量,以及副本在集群内的分布位置等
  3. 多主架构,不管操作哪个副本,效果都是相同的,借助ZooKeeper的协同能力被分发至每个副本以本地形式执行。
  4. Block数据块,在执行INSERT命令写入数据时,会依据max_insert_block_size的大小(默认1048576行)将数据切分成若干个Block数据块。所以Block数据块是数据写入的基本单元,并且具有写入的原子性和唯一性。
  5. 原子性,在数据写入时,一个Block块内的数据要么全部写入成功,要么全部失败
  6. 唯一性,在写入一个Block数据块的时候,会按照当前Block数据块的数据顺序、数据行和数据大小等指标,计算Hash信息摘要并记录在案。在此之后,如果某个待写入的Block数据块与先前已被写入的Block数据块拥有相同的Hash摘要(Block数据块内数据顺序、数据大小和数据行均相同),则该Block数据块会被忽略,预防由异常原因引起的Block数据块重复写入的问题。

zookeeper的配置方式

zookeeper或者keeper配置

1.在config.d目录下面创建metrika.xml文件

<yandex><zookeeper-servers><!--节点配置,可以配置多个地址--><node index="1"><host>hb1</host><port>2181</port></node><node index="2"><host>hb2</host><port>2181</port></node><node index="3"><host>hb3</host><port>2181</port></node></zookeeper-servers>
</yandex>

2.在config.xml配置文件引入即可

 <include_from>/etc/clickhouse-server/config.d/metrika.xml</include_from>
<zookeeper incl="zookeeper-servers" optional="false" />  该名称与metrika.xml定义的一致。

clickhouse的系统表提供了访问keeper路径的方式,system.zookeeper。

二、ReplicatedMergeTree原理解析

ReplicatedMergeTree是复制表最为基础表引擎。

数据结构

在ReplicatedMergeTree的核心逻辑中,大量运用keeper的能力,实现多个ReplicatedMergeTree副本实例之间的协同,包括主副本的选举、副本状态感知、操作日志分发、任务队列和BlockId去重等。

在执行INSERT数据写入、MERGE分区和MUTATION操作的时候,都会涉及与ZooKeeper的通信。但是在通信的过程中,并不会涉及任何表数据的传输,在查询数据的时候也不会访问ZooKeeper。

keeper节点的结构

ReplicatedMergeTree需要依靠ZooKeeper的事件监听机制以实现各个副本之间的协同。所以,在每张ReplicatedMergeTree表的创建过程中,它会以zk_path为根路径,在Zoo-Keeper中为这张表创建一组监听节点。

测试表建表语句,注意使用on cluster创建表是一次性动作,如果因为网络或者节点异常原因导致某个节点创建失败,那么再次使用默认指定path的方式创建表的uuid时,两次操作的uuid不一致,可能导致数据同步异常

create table  test.rep_tab_local on cluster perftest_2shards_1replicas
(uid Int32,uname String)
engine=ReplicatedMergeTree() order by uid#查询元数据
select * from system.zookeeper where 
path='/clickhouse/tables/01ed8af1-b5d6-4a88-8960-42b5946fbaec/02' \G
  1. 元数据
  • metadata:保存元数据信息,包括主键、分区键、采样表达式等
    在这里插入图片描述
  • /columns:保存列字段信息,包括列名称和数据类型。
    在这里插入图片描述
  • /replicas:保存副本名称,对应设置参数中的replica_name。,不同副本名称的value是不一样的。
    在这里插入图片描述
  1. 判断标识
  • /leader_election:用于主副本的选举工作,主副本会主导MERGE和MUTATION操作(ALTER DELETE和ALTER UPDATE)。这些任务在主副本完成之后再借助ZooKeeper将消息事件分发至其他副本。
    在这里插入图片描述
  • /blocks:记录Block数据块的Hash信息摘要,以及对应的partition_id。通过Hash摘要能够判断Block数据块是否重复;通过partition_id,则能够找到需要同步的数据分区
    在这里插入图片描述
  • /block_numbers:按照分区的写入顺序,以相同的顺序记录partition_id。各个副本在本地进行MERGE时,都会依照相同的block_numbers顺序进行。
    在这里插入图片描述
  • /quorum:记录quorum的数量,当至少有quorum数量的副本写入成功后,整个写操作才算成功。quorum的数量由insert_quorum参数控制,默认值为0
  1. 操作日志
  • log:常规操作日志节点(INSERT、MERGE和DROP PARTITION),它是整个工作机制中最为重要的一环,保存了副本需要执行的任务指令。log使用了ZooKeeper的持久顺序型节点,每条指令的名称以log-为前缀递增,例如log-0000000000、log-0000000001等。每一个副本实例都会监听/log节点,当有新的指令加入时,它们会把指令加入副本各自的任务队列,并执行任务。
    在这里插入图片描述

  • /mutations:MUTATION操作日志节点,作用与log日志类似,当执行ALERT DELETE和ALERT UPDATE查询时,操作指令会被添加到这个节点。mutations同样使用了ZooKeeper的持久顺序型节点,但是它的命名没有前缀,每条指令直接以递增数字的形式保存,例如0000000000、0000000001等
    在这里插入图片描述

  • /replicas/{replica_name}/*:每个副本各自的节点下的一组监听节点,用于指导副本在本地执行具体的任务指令,其中较为重要的节点有如下几个:
    (1)/queue:任务队列节点,用于执行具体的操作任务。当副本从/log或/mutations节点监听到操作指令时,会将执行任务添加至该节点下,并基于队列执行。
    (2)log_pointer:log日志指针节点,记录了最后一次执行的log日志下标信息,例如log_pointer:4对应了/log/log-0000000003(从0开始计数)
    (3)/mutation_pointer:mutations日志指针节点,记录了最后一次执行的mutations日志名称,例如mutation_pointer:0000000000对应了/mutations/000000000。

在这里插入图片描述
LogEntry结构:
LogEntry用于封装/log的子节点信息,它拥有如下几个核心属性:

  • source replica:发送这条Log指令的副本来源,对应replica_name。
  • type:操作指令类型,主要有get、merge和mutate三种,分别对应从远程副本下载分区、合并分区和MUTATION操作。
  • block_id:当前分区的BlockID,对应/blocks路径下子节点的名称。
  • partition_name:当前分区目录的名称。
    在这里插入图片描述
    合并的log子节点信息
    在这里插入图片描述
    MutationEntry结构:
    MutationEntry用于封装/mutations的子节点信息,它同样拥有如下几个核心属性:
  • source replica:发送这条MUTATION指令的副本来源,对应replica_name。
  • commands:操作指令,主要有ALTER DELETE和ALTER UPDATE。
  • mutation_id:MUTATION操作的版本号。
  • partition_id:当前分区目录的ID。
    在这里插入图片描述

三、副本协调的流程

副本协同的核心流程主要有INSERT、MERGE、MUTATION和ALTER四种,分别对应了数据写入、分区合并、数据修改和元数据修改。INSERT和ALTER查询是分布式执行的。借助ZooKeeper的事件通知机制,多个副本之间会自动进行有效协同,但是它们不会使用ZooKeeper存储任何分区数据。
而其他查询并不支持分布式执行,包括SELECT、CREATE、DROP、RENAME和ATTACH。
注意:alter增加表字段和删除表字段,可以进行副本之间同步

1、Insert执行流程

示意图如下:
步骤1:创建表create
由于该CREATE语句没有分布式协同,需要每个实例节点执行
a.初始化表节点,根据创建表时指定的zk_path初始化,默认是/clickhouse/tables/{uuid}/{shard} {副本名称replicas}
b.注册副本节点/replicas/副本名称
c.监听/log,实时操作日志,持续监听
d.选举主副本,默认第第一个将会是主副本/leader_election
e.第二个节点创建,注册副本节点/replicas、监听/log、选举/leader_election
步骤2:数据写入
a.客户端执行insert
b.本地创建新分区(2025_0_0_0),写入/block_id(/block_id/2025_0_0_0)
c.由执行insert的副本发生日志,推送logEntry(/log/log-0000000)
d.其他副本监听/log有新操作日志,拉取logEntry,创建task任务放进副本执行队列/replicas/副本名称/queue
e.基于/queue队列,执行task任务
f.选择远端副本下载数据,
选择算法:
从/replicas所有副本列表查找
规则(/log_pointer最大,/queue队列最小副本)log_pointer下标最大,意味着该副本执行的日志最多,数据应该更加完整;而/queue最小,则意味着该副本目前的任务执行负担较小
g.选择完成后发起下载请求,默认请求5次。如果失败就会更换副本发起请求,max_fetch_partition_retries_count参数控制
h.由目标副本接到下载请求后主动send数据到该副本进行数据持久化。
i.(首先先写到临时目录,数据接收完成后,将临时路径改成正式路径)完成数据持久化后,发生ack应答确保数据一致性。

在这里插入图片描述

副本监听到/log最新的操作日志后并不会立马执行,而是将其转换成task写入/queue队列中,因为在某些时刻会同时多个操作日志,这时候用队列的作用就是缓存操作日志异步执行。

可以看到,在INSERT的写入过程中,ZooKeeper不会进行任何实质性的数据传输。本着谁执行谁负责的原则,在这个案例中由A节点首先在本地写入了分区数据。之后,也由这个副本负责发送Log日志,通知其他副本下载数据。如果设置了insert_quorum并且insert_quorum>=2,则还会由该副本监控完成写入的副本数量。其他副本在接收到Log日志之后,会选择一个最合适的远端副本,点对点地下载分区数据。

2、Merge执行流程

当ReplicatedMergeTree触发分区合并动作时,也会通过keeper分布式协调组件进行状态同步。

无论哪个副本发起merge操作,其合并的计划都会交给主副本来定制,在创建副本表时就已经选举出主副本节点。
1.从副本创建远程连接
从副本执行OPTIMIZE,强制触发MERGE合并,从副本通过/replicas找到主副本,并尝试与之建立连接。
2.主副本接收连接
主副本接收来着从副本的连接,并由主副本制定merge合并计划,判断哪些分区需要合并,确认后会生产LogEntry推送至/log下,用于通知/replicas副本集下面所有副本进行merge操作。
此时主副本会监控所有副本执行情况。
监听行为由replication_alter_partitions_sync参数控制 默认是1:
1:等待主副本合并操作完成
0:不等待
2:等待所有副本合并操作完成
3.各个副本监听/log
当副本监听到/log有操作日志后,分别拉取日志到本地并转换成task推送到/queue任务队列。
4.各个副本本地执行merge操作
副本在本地执行merge操作。
在MERGE的合并过程中,ZooKeeper也不会进行任何实质性的数据传输,所有的合并操作,最终都是由各个副本在本地完成的。而无论合并动作在哪个副本被触发,都会首先被转交至主副本,再由主副本负责合并计划的制定、消息日志的推送以及对日志接收情况的监控。

注意新版本所有副本都可以设置成主副本,目的在于谁负责谁执行,避免过多的远程建立连接的动作。
在这里插入图片描述

3、Mutation执行流程

当对ReplicatedMergeTree表执行ALTER UPDATE、ALTER DELETE时会执行mutation流程
mutation执行流程与merge类型,无论是哪个副本发起mutation操作,都会将请求转发到主副本,由主副本制定执行计划、推送log日志、监控log日志拉取情况。
在这里插入图片描述

4、Alter执行流程

Alter针对表字段的增加和删除。该执行流程不会远程连接主副本节点生成执行计划,推送/log进行分发。遵循谁负责谁执行
执行流程:

  1. 在某个节点执行修复表字段类型操作,执行之后,该节点会修改keeper共享元数据,/metadata、/columns,节点版本信息会增加,
  2. 其他副本监听到/metadata的版本变化后,会各自执行本地元数据变更(本地的元数据版本号与共享版本号进行对比,会发现本地版本号低于共享版本号,于是它们开始在各自的本地执行更新操作)
  3. 发起执行的副本会监听所有副本执行完成后返回响应

在这里插入图片描述
在ALTER整个的执行过程中,ZooKeeper不会进行任何实质性的数据传输。所有的ALTER操作,最终都是由各个副本在本地完成的。本着谁执行谁负责的原则,在这个案例中由CH6负责对共享元数据的修改以及对各个副本修改进度的监控。

四、分布式表查询的核心流程

面向集群数据查询时,只能通过Distributed表引擎实现,当Distributed表接收到SELECT查询的时候,它会依次查询每个分片的数据,再合并汇总返回。

多副本路由规则

在查询数据的时候,如果集群中的一个shard,拥有多个replica,那么Distributed表引擎需要面临副本选择的问题。它会使用负载均衡算法从众多replica中选择一个,而具体使用何种负载均衡算法,则由load_balancing参数控制。

  1. random:random是默认的负载均衡算法,CK的服务节点,拥有一个全局计数器errors_count,当服务发生异常时,该计数器累积+1,而random算法会选择errors_count错误数最少的replica。如果errors_count错误数一样,将随机选择一个。
  2. nearest_hostname:nearest_hostname可以看作random算法的变种,首先它会选择errors_count错误数量最少的replica,如果多个replica的errors_count计数相同,则选择集群配置中host名称与当前host最相似的一个。而相似的规则是以当前host名称为基准按字节逐位比较,找出不同字节数最少的一个。
  3. in_order:策略同样与random类似,维护每个replica的errors_count值,选择错误数量最少的一个副本,如果错误数相同,按照集群配置定义的顺序进行选择。
  4. first_or_random:first_or_random可以看作in_order算法的变种,首先它会选择errors_count错误数量最少的replica,如果多个replica的errors_count计数相同,它首先会选择集群配置中第一个定义的replica,如果该replica不可用,则进一步随机选择一个其他的replica。

多分片查询的核心流程

分布式查询与分布式写入类似,同样本着谁执行谁负责的原则,它会由接收SELECT查询的Distributed表,并负责串联起整个过程。首先它会将针对分布式表的SQL语句,按照分片数量将查询拆分成若干个针对本地表的子查询,然后向各个分片发起查询,最后再汇总各个分片的返回结果。


后续将持续更新,文中的流程图借鉴《ClickHouse原理解析与应用实践》电子书,如有问题可交流沟通

http://www.dtcms.com/a/594336.html

相关文章:

  • 最长回文子序列
  • 数据库知识整理——关系数据库SQL简介
  • 自己做的网站怎样赚钱东兴网站建设
  • 山东网站营销推广费用百度域名解析
  • 2026助力发刊:人工智能电磁超材料专题学习
  • 作者自己建立的网站网站设计外包合同
  • 零基础入门C语言之C语言实现数据结构之顺序表经典算法
  • 织梦配置手机网站怎样用虚拟主机建网站
  • Kimi 入驻 GitCode|Kimi K2 Thinking 模型发布并开源,全面提升 Agent 和推理能力
  • 2025模拟设备和单片机(移远EC800M模块)用MQTT协议接入ONENET记录
  • 个人网站设计规划怎么做百度里面自己的网站
  • 简单理解:WWDG窗口看门狗
  • 爬取数据存入SQLite:轻量级数据库实战指南
  • 找个会做网站的 一起做网站互联网开发技术
  • 如何利用R语言 进行生物多样性测定、生物量模型构建、生物完整性指数(IBI)筛选与生态环境状况综合指数(EI)计算
  • 前端开发做网站吗wordpress禁止加载头部
  • 建设网站的基础知识六年级做的网站的软件下载
  • SQL中的NULL陷阱:为何=永远查不到空值
  • 厦门市网站建设软件开发公司营销网站seo推广
  • JDBC模板技术
  • 万网网站后台登陆做网站哪个部分
  • 11月10日学习总结--numpy的基本操作
  • 快速搭建一个 GitHub 开源项目导航网站,提供便捷的信息抓取、智能摘要、分类管理功能
  • 网站数据表怎么做网络推广引流方式
  • 【Rocky基础】——用户管理
  • 免费下载建筑图纸的网站wordpress子分页
  • 数据结构简明教程(李春葆版)课后习题答案
  • 做app网站公司名称如何网络推广新产品
  • CSGHub v1.12.0开源版本更新
  • 上海网站建设报价自建网站怎么做推广