Hi,我是王知无,一个大数据领域的原创作者。 

放心关注我,获取更多行业的一手消息。


在阅读本文之前你一定要先看看这个:

Clickhouse - Replication机制

1. Replication引擎族

​Replication​​​仅对于​​MergeTree​​引擎族提供支持, 两者是正交的:

  • ReplicatedMergeTree
  • ReplicatedSummingMergeTree
  • ReplicatedReplacingMergeTree
  • ReplicatedAggregatingMergeTree
  • ReplicatedCollapsingMergeTree
  • ReplicatedVersionedCollapsingMergeTree
  • ReplicatedGraphiteMergeTree

「ClickHouse系列」Replication机制详解_hadoop

2. 工作机制

在Clickhouse中, Replication的机制工作在表级别, 而不是库, 或者是节点层级. 一个节点可以同时存储使用Replication引擎的表以及不使用Replication引擎的表.

Replication机制不依赖于分片(shard), 每个分片有自己独立的Replication机制. 夸分片的话, 就算是表名一致, 表引擎一致, 数据也不会进行同步.

在同一个节点上, ​​Create​​​,​​Drop​​​, ​​Attach​​​, ​​Detach​​​以及​​Rename​​等查询并不会触发Replication机制.

  • 当创建表语句(​​CREATE TABLE​​)在一个节点上被执行时, 会创建一个新的Replication表. 如果在该集群中其他节点上已经存在该表, 那会添加一个新的副本.
  • 删除表语句(​​DROP TABLE​​)会删除当前节点上的副本表.
  • 重命名表语句(​​RENAME TABLE​​)会重命名当前节点的表名, 但不会修改该集群其他节点的表名. 即Replicated表在不同的副本上可以有不同的名字.

2.1. 依赖Zookeeper

Clickhouse使用​​zookeeper​​来存储副本的元数据信息(zk版本要求3.4.5或者更高). 当表引擎被指定为Replication引擎族时, Clickhouse将使用设定zk集群的一个目录作为自己元数据的存储地点(这个目录可以通过具体的表引擎语句来指定).

需要注意的是, 如果在clickhouse的配置文件中没有配置zk集群信息, 将不能创建使用Replication引擎族的表, 并且已存在的使用Replication引擎族的表将会被锁定在只读状态(read-only).

当查询表引擎为Replication引擎族的本地表时, Zookeeper集群并不会工作, ​​SELECT​​​查询语句的执行性能和不使用Replication引擎族的表是一样快的. 当查询表引擎为Replication引擎族的分布式表时, ​​SELECT​​​查询语句的执行由​​max_replica_delay_for_distributed_queries​​​和​​fallback_to_stale_replicas_for_distributed_queries​​这两个参数控制, 合理的设置这两个参数可以有效提升查询分布式的速度.

对于​​INSERT​​​插入语句而言, 所有被插入的数据会根据一定的规则划分为几个数据块Block, 每个数据块的相关元数据信息会通过事务来被提交到Zookeeper(一个数据块具体可以最多容纳多少条数据是由参数​​max_insert_block_size​​决定的). 这个机制导致了数据插入使用了Replication引擎的表的延迟会比使用了其他引擎的表稍高一些, 合理的数据写入机制能缓解这个延迟的影响.

如果Clickhouse集群的规模非常大, 可以为不同的分片(shard)使用不同的Zookeeper集群, 即一套Clickhouse集群搭配多套Zookeeper集群.

2.2. 数据同步

Replication副本机制是异步且多Master的(多Master指在同一个集群上, 随意节点都可以, 无需在master节点上).​​INSERT​​​查询(​​ALTER​​​查询也是)可以被发送到当前集群的所有正常工作的节点上. 数据会被插入到运行​​INSERT​​​语句的节点上, 然后被同步到同一分片的其他节点上. 因为这个数据同步操作是异步执行的, 其他节点上的数据会存在一定的延迟时间(这个时间由不同节点间传输压缩数据块的时间决定). 同步时如果遇到部分节点不可用(挂掉了), 会当这些节点重新可用时, 再写入. 对复制表进行数据同步时所使用的线程数可以通过​​background_schedule_pool_size​​参数来设置.

默认情况下, ​​INSERT​​​查询会等待写入当前副本的结果. 如果数据成功写入到当前副本但是这个副本所在的服务挂掉了, 那么写入的数据将会丢失. 如果​​INSERT​​​查询想要确认写入该分片的所有副本的结果, 可以使用​​insert_quorum​​选项.

  • INSERT的原子性

一个​​INSERT​​​插入不一定是原子性的, 这需要考虑到这个​​ISNERT​​​查询被分成了多少个数据块, 但对于数据块来说, 是可以保证原子性的. 换句话说, 如果一个INSERT插入的条数小于​​max_insert_block_size​​​设定的值, 那么这个​​INSERT​​查询就是原子性的.

  • INSERT的幂等性

数据块是遵循重复删除原则的, 对于同一数据块(大小相同, 条数相同, 数据的顺序相同)的多次写入, 实际只会被写入一次, 多余的次数会被丢弃. 这样做的原因是当由于网络故障, 客户端不知道数据是否成功被写入到Clickhouse中, 可以不考虑其他, 直接重复执行​​INSERT​​​操作(就算多写了一次, 也会因为相同数据块而实际上没有写入到CK中). 这样做就保证了多次​​INSERT​​操作的幂等性.

2.3. 数据保障

在replication机制执行过程中, 只有被插入的源数据在各个节点间传输. 进一步的数据转换(Merge操作)是以同样的方式在所有的副本上协调和执行的. 这最大限度的降低了对于网络传输的压力, 意味着当Clickhouse集群跨越了多个数据中心时, 可以最大程度的提升replication机制的执行效率.

您可以对同一数据进行任意数量的复制。Yandex.Metrica在生产中使用双重复制。每台服务器使用RAID-5或RAID-6,在某些情况下使用RAID-10。这是一个相对可靠和方便的解决方案。

Clickhouse系统会监控每个副本上的数据一致性, 在发生故障后能够自动回复. 在不同副本数据差异较小的情况下, 故障转移是自动或半自动的, 但如果数据差异过大(例如表结构不同), 那么就需要去手动处理了.

如果这个文章对你有帮助,不要忘记  「点赞」 「收藏」