1、概述
- 下图中N1和N2内容不同,则N1 N2互为分片。如果内容相同,则互为副本。
2、数据副本
- 只有使用了ReplicatedMergeTree复制表系列引擎,才能应用副本能力。
- ReplicatedMergeTree增加了Zookeeper部分,会进一步在ZooKeeper内创建一系列的监听节点,并以此实现多个实例之间的通信。
- ZooKeeper不会涉及表数据传输。
2.1 副本的特定
- 副本是定义在表级别的
- 多主架构
- Block数据块是数据写入的基本定远,并且具有写入的原子性和唯一性。会计算Hash信息并记录,通过Hash摘要对比是否唯一。
2.2 副本定义形式
ENGINE = ReplicatedMergeTree('zk_path', 'replica_name')
- 通常的zk_path命名
/clickhouse/tables/{shard}/table_name
- zk_path用于指定在ZK中创建的数据表的路径
- 对于zk_path,同一张数据表的同一个分片的不同副本应该定义相同的路径。
- 对于replica_name,同一张数据表的同一个分片的不同副本应该定义不同名称。
3、ReplicatedMergeTree
3.1 数据结构
- 大量运用ZooKeeper能力,实现副本之间协同。
ZooKeeper内的节点结构
- 元数据
/metadata
/columns
/replicas - 判断标识
/leader_election
/blocks hash摘要
/block_numbers
/quorum 至少有quorum数量副本写入成功后才算写入成功 - 操作日志
/log
/mutations ALTER DELTE ALTER UPDATE等操作的记录
/replicas/{replica_name}/*
Entry日志多项数据结构
- /log /mutations 是分发操作指令的信息通道,发送指令的方式是为这些父节点添加子节点。
- 添加的子节点在Clickhouse中被统一抽象为Entry对象,具体实体由LogEntry和MutationEntry对象承载。
3.2 副本协同的核心流程
INSERT
- 由执行了INSERT操作的副本向/log节点推送操作日志。
- 副本会一直监听/log节点变化,拉取LogEntry,将其转为任务对象放至队列。
- 基于/queue队列开始执行任务,会选择一个远端副本作为数据的下载来源。选取拥有最大log_pointer的,并且/queue子节点数量最少的。然后建立起连接开始下载。
MERGE
- 无论MERGE操作从哪个副本发起,其合并计划都会交由主副本来制定。
MUTATION
- 也是由主节点来制定计划
ALTER
- 修改ZK内的共享元数据节点。
/metadata /columns
4、数据分片
- ClickHouse中的每个服务节点都称为一个shard
- ClickHouse数据分片需要结合Distributed表引擎一同使用,使得查询、写入能够进行路由。
- Distributed表引擎本身不存储任何数据,知识作为分布式表的一层透明代理。
4.1 基于集群实现分布式DDL
CREATE/DROP/RENAME/ALTER TABLE ON CLUSTER cluster_name
数据结构
- 默认分布式DDL在ZK内使用的根路径为
/clickhouse/task_queue/ddl
- /query-[seq]/active /query-[seq]/finished
- DDLLogEntry日志对象数据中包含了 query、hosts、initiator
分布式DDL执行流程
- 谁执行谁负责推送
- 拉取日志并执行
- 步骤1执行后,客户端会阻塞180秒,等待所有host执行完毕。
5、Distributed原理解析
- 由两部分组成,本地表和分布式表,分布式表以all后缀命名。
- 采用读时检查,如果它们表结构不兼容,只有在查询时才抛出错误。
5.1 定义形式
ENGINE = Distributed(cluster, database, table [,shaeding_key])
CREATE TABLE test_shard_2_all ON CLUSTER sharding_simple ()
ENGINE = Distributed(sharding_simple, defalult, test_shard_2_local, rand())
- cluster 集群名称
- sharding_key 分片键,选填参数
- Distributed表不支持任何MUTATION类型操作
5.2 分片规则
- 集群配置的分片权重,权重越大,写入数据越多
- slot 数量等于所有分片的权重之和
- 选择函数,slot = shard_value % sum_weight
5.3 写入流程
- 在第一个分片节点写入本地分片数据
- 建立远端连接,准备发送远端数据分片
- 发送数据
- 远端分片写入本地
- 第一个分片确认完成写入
副本写入
- 可以用Distributed复制,也可以依赖ReplicatedgeTree
5.4 查询过程
多副本路由:randon\nearest_hostname(错误最少)\in_order(错误最少中的按定义逐个选择)\first_or_random 四种方式
分布式查询是在本地查之后union的结果
使用Global优化分布式子查询
- 使用本地表的问题
SELECT uniq(id) FROM test_query_all WHERE repo = 100 AND id IN (SELECT id FROM test_query_local WHERE repo = 200)
- 扫的本地表里刚好没有这个数据,有希望在全局里找。
- 使用分布式表又会有查询放大的问题,每次扫all都是全局广播,就会变成指数增长
SELECT uniq(id) FROM test_query_all WEHRE repo = 100 AND id IN (SELECT id FROM test_query_all WHERE repo = 200)
- 所以有一个GLOBAL关键字,可以将中间过程缓存