问题:使用ReplicatedMergeTree表引擎,该引擎逻辑上是不会对于主键相同的数据,进行去重合并操作。如果想要去重,可以使用ReplacingReplicatedMergeTree表引擎。然后使用ReplicatedMergeTree表引擎进行数据insert 插入数据,插入相同主键的数据,数据去重了。排查原因。
副本表引擎:ReplicatedMergeTree
副本去重引擎:ReplacingReplicatedMergeTree
insert_deduplicate (官网没找到,可能已经不在用了。用下面两个参数实现)
replicated_deduplication_window
non_replicated_deduplication_window
问题:clickhouse使用ReplicatedMergeTree引擎,为什么插入数据进行去重了?
当使用ReplicatedMergeTree引擎时,如果观察到数据去重的效果,这可能是由于其他因素导致的,而不是引擎本身提供的功能。
问题:数据写入表引擎为ReplicatedMergeTree的时候,过程是什么样的,副本间的数据如何同步的?是先插入一个节点,之后再同步呢?还是再插入数据的时候,同时向两个节点进行插入呢?
数据写入过程
- 本地写入:
- 当客户端向ClickHouse集群发送写入请求时,该请求首先被发送到集群中的一个节点(可以称为“主节点”或“接收节点”)。
- 在该节点上,数据首先被写入到本地的临时目录中。
- 记录日志:
- 写入操作完成后,主节点会向ZooKeeper(ZK)的/log目录发送一个LogEntry,记录这次写入操作的相关信息,包括新数据分区的名称、类型等。
- 这个LogEntry是数据同步的关键,因为它包含了所有副本节点需要知道的信息,以便它们能够获取并应用这些变更。
- 副本同步:
- 集群中的其他副本节点(从节点)会监听ZooKeeper中/log目录的变化。
- 一旦检测到新的LogEntry,从节点会按照ZooKeeper中记录的顺序拉取这些变更日志。
- 从节点根据拉取到的LogEntry信息,从主节点或其他已同步的节点上下载相应的数据分区。
- 下载完成后,从节点将这些数据分区写入到本地的存储中,从而完成数据的同步。
副本间的数据同步机制
-
基于ZooKeeper的同步:
- ReplicatedMergeTree引擎通过ZooKeeper来协调不同副本节点之间的数据同步。
- ZooKeeper作为一个分布式协调服务,负责存储和分发数据同步的元数据(如LogEntry)
- 通过监听ZooKeeper的变更通知,副本节点能够实时地感知到数据的变化,并进行相应的同步操作
-
数据一致性的保证:
- 在同步过程中,如果某个副本节点因为故障而无法及时同步数据,那么当该节点恢复后,它会从ZooKeeper中拉取错过的变更日志,并重新进行同步。
- 这种方式确保了即使在节点故障的情况下,数据的一致性也能够得到保持。
插入操作的细节
写入操作通常是由单个节点接收并处理的,同步操作是异步进行的,因此,数据并不是在插入时同时向两个节点进行插入的。而是首先写入到一个节点(接收节点),然后由该节点负责将数据同步到其他副本节点。这种方式既保证了数据的可靠性,又提高了写入操作的性能。
问题: replicated_deduplication_window这个参数默认值为100,作用在哪个过程呢?
- 控制ZooKeeper中保留的hash值数量。数据写入会划分一个个数据块block,对数据块进行校验,即生成hash值即block_id。(数据顺序,数据行,数据大小等信息生成的hash值)。100表示记录100个block数据块的hash值
- 防止数据块重复插入数据。
- 在数据同步过程中,如果副本节点检测到新写入的数据块与ZooKeeper中已记录的某个数据块的校验和相同,那么它将认为这是一个重复的数据块,并可能选择忽略该数据块的插入。
- 通过设置replicated_deduplication_window,可以限制这种去重机制回溯检查的数据块数量,从而在一定程度上控制去重操作的性能和资源消耗。
问题: replicated_deduplication_window 参数,是记录数据块hash值个数存储在zookeeper中,用于数据块校验,副本节点同步数据时,拉取信息。那对于主节点而言呢,数据直接写入主节点,那么主节点根据什么进行数据块校验并确认数据块是否重复了呢?
replicated_deduplication_window参数主要是作用于副本同步数据过程中保证数据块block的唯一性,避免块级别的数据重复插入。对于主节点插入数据而言,参数无作用,主要根据merger合并操作实现数据块block级别的数据不重复。
需要注意的是,由于ClickHouse的ReplicatedMergeTree引擎并不保证严格的数据唯一性(特别是在高并发写入场景下),因此在需要严格保证数据唯一性的应用场景中,可能需要结合其他机制(如应用层面的唯一性约束、使用具有唯一性约束的表引擎等)来实现。
数据插入主节点过程
- 数据写入。首先数据写入到本地存储临时位置,并被切分为多个数据块block,数据块包含多条数据。
- 计算校验和。每个block计算hash值,用于后续数据同步数据块校验,以及数据完成性。
- 写入zookeeper。主节点将block校验值hash以及相关元数据(数据块名称,时间戳)记录到zookeeper指定目录,用于数据同步和数据块级别的去重。
- 主节点中数据合并去重。后台会定期进行数据合并merge操作。在合并过程中,如果存在具有相同排序键(ORDER BY子句指定的列)的数据块,并且这些数据块的内容也相同(通过校验和验证),则它们可能会被合并成一个数据块,从而间接实现了去重的效果。注意不是单条记录级别的。如果单条记录重复但分布在不同的数据块中,则可能不会被合并去重。
- 同步到副本节点。主节点在zookeeper记录后,开始进行副本同步。副本节点通过监听ZooKeeper中的变更来拉取新的数据块,并使用校验和来验证数据块的完整性和唯一性。
问题: ReplicatedMergeTree表引擎中,主节点(以及副本节点)在后台会定期执行数据合并(Merge)操作。这个实现数据去重。那这个引擎去重逻辑不就和ReplacingReplicatedMergeTree表引擎去重逻辑一样了吗?
- 去重级别:ReplicatedMergeTree的去重是基于数据块级别的,而ReplacingMergeTree的去重是基于数据行级别的。
- 触发时机:ReplicatedMergeTree的去重是在数据同步过程中通过校验和来避免的,而ReplacingMergeTree的去重是在数据合并期间触发的。
- 应用场景:ReplicatedMergeTree更适用于需要高可用性和容错性的场景,而ReplacingMergeTree则更适用于需要去除重复数据以节省空间的场景。
问题: placingReplicatedMergeTree和ReplicatedMergeTree表引擎都会在后台进行merge操作吗?区别?
- 两者都会在后台进行merge操作,但目的和去重机制不同。
- ReplicatedMergeTree侧重于数据的高可用性和容错性,通过多个副本节点来确保数据的持久性和一致性;而ReplacingMergeTree则侧重于解决数据重复问题,提供基于主键或排序键的数据去重功能。
- 在选择表引擎时,应根据具体的应用场景和需求来进行选择。如果需要高可用性和容错性,可以选择ReplicatedMergeTree;如果需要去除重复数据以节省空间,可以选择ReplacingMergeTree。
问题: clickhouse中,在插入MergeTree表时候,如何将数据分为多个block块?
数据插入是block的生成
- 数据写入
- 当数据被插入MergeTree表时,数据首先以片段(fragment)的形式写入到磁盘的临时位置。
- 这些片段在写入时并不是直接形成最终的block,而是作为合并(merge)过程的输入。
- 合并过程
- ClickHouse的后台合并线程会定期选择一批片段进行合并操作。
- 合并过程中,属于相同分区的多个片段会被合并成一个新的、更大的片段(也就是block)。
- 合并后的block在物理存储上会更加紧凑,同时会重建索引,优化查询性能。
影响block划分的因素
-
数据插入频率和量。
- 插入数据的频率和量会影响后台合并线程的工作量。频繁且大量的插入会导致更多的片段生成,进而触发更多的合并操作。
-
MergeTree的配置
- 通过调整MergeTree的配置参数,如merge_with_ttl_timeout、background_pool_size等,可以间接影响合并过程的执行频率和效果,从而影响block的划分。
- 但需要注意的是,这些配置通常不是直接用来控制block的大小的,而是用来优化合并过程的性能和行为。
-
分区策略
- 使用PARTITION BY子句可以为MergeTree表指定分区策略。不同的分区策略会影响数据的物理分布,但并不会直接影响block的划分。
- 分区策略主要用于优化查询性能,减少查询时需要扫描的数据量。
-
数据特性
- 数据的特性(如数据类型、分布情况等)也会对合并过程产生影响,进而影响block的划分。
- 数据中存在大量的重复记录,那么在合并过程中可能会通过去重操作减少block的大小