设计 | ClickHouse 分布式表实现数据同步[通俗易懂]

设计 | ClickHouse 分布式表实现数据同步[通俗易懂]作者:吴帆 青云数据库团队成员 主要负责维护 MySQL 及 ClickHouse 产品开发,擅长故障分析,性能优化。 在多副本分布式 ClickHouse 集群中,通常需要使用 Distribute

设计 | ClickHouse 分布式表实现数据同步

作者:吴帆 青云数据库团队成员

主要负责维护 MySQL 及 ClickHouse 产品开发,擅长故障分析,性能优化。

在多副本分布式 ClickHouse 集群中,通常需要使用 Distributed 表写入或读取数据,Distributed 表引擎自身不存储任何数据,它能够作为分布式表的一层透明代理,在集群内部自动开展数据的写入、分发、查询、路由等工作。

Distributed 表实现副本数据同步有两种方案:

  1. Distributed + MergeTree
  2. Distributed + ReplicateMergeTree

| Distributed + MergeTree

在使用这种方案时 internal_replication 需要设为 false,向 Distributed 表写入数据,Distributed 表会将数据写入集群内的每个副本。Distributed 节点需要负责所有分片和副本的数据写入工作。

file

1. 集群配置

<logical_consistency_cluster>
    <shard>
        <internal_replication>false</internal_replication>
        <replica>
            <host>shard1-repl1</host>
            <port>9000</port>
        </replica>
        <replica>
            <host>shard1-repl2</host>
            <port>9000</port>
        </replica>
    </shard>
</logical_consistency_cluster>

2. 数据写入

CREATE TABLE test.t_local  on cluster logical_consistency_cluster
(
    EventDate DateTime,
    CounterID UInt32,
    UserID UInt32
) ENGINE MergeTree() PARTITION BY toYYYYMM(EventDate) ORDER BY (CounterID, EventDate) ;

CREATE TABLE test.t_logical_Distributed on cluster logical_consistency_cluster
(
    EventDate DateTime,
    CounterID UInt32,
    UserID UInt32
)
ENGINE = Distributed(logical_consistency_cluster, test, t_local, CounterID) ;

INSERT INTO test.t_logical_Distributed VALUES ("2019-01-16 00:00:00", 1, 1),("2019-02-10 00:00:00",2, 2),("2019-03-10 00:00:00",3, 3)

3. 数据查询

# shard1-repl1

SELECT *
FROM test.t_local

Query id: bd031554-b1e0-4fda-9ff8-1145ffae5b02

┌───────────EventDate──┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │         3 │      3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │         2 │      2 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │         1 │      1 │
└─────────────────────┴───────────┴────────┘

3 rows in set. Elapsed: 0.004 sec. 

------------------------------------------

# shard1-repl2

SELECT *
FROM test.t_local

Query id: 636f7580-02e0-4279-bc9b-1f153c0473dc

┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │         1 │      1 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │         3 │      3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │         2 │      2 │
└─────────────────────┴───────────┴────────┘

3 rows in set. Elapsed: 0.005 sec. 

通过写入测试我们可以看到每个副本数据是一致的。

即使本地表不使用 ReplicatedMergeTree 表引擎,也能实现数据副本的功能。但每个副本的数据是通过 Distributed 表独立写入,文件存储格式不会完全一致,可以理解这种方式为逻辑一致性。

Distributed 需要同时负责分片和副本的数据写入工作,单点写入很有可能会成为系统性能的瓶颈,所有有接下来的第二种方案。

| Distributed + ReplicateMergeTree

在使用这种方案时 internal_replication 需要设为 true,向 Distributed 表写入数据。Distributed 表在每个分片中选择一个合适的副本并对其写入数据。

分片内多个副本之间的数据复制会由 ReplicatedMergeTree 自己处理,不再由 Distributed 负责。

file

1. 配置文件

<physical_consistency_cluster>
    <shard>
        <internal_replication>true</internal_replication>
        <replica>
            <host>shard1-repl1</host>
            <port>9000</port>
        </replica>
        <replica>
            <host>shard1-repl2</host>
            <port>9000</port>
        </replica>
    </shard>
</physical_consistency_cluster>

2. 数据写入

CREATE TABLE test.t_local on cluster  physical_consistency_cluster 
(
    EventDate DateTime,
    CounterID UInt32,
    UserID UInt32
)
ENGINE = ReplicatedMergeTree("{namespace}/test/t_local", "{replica}")
PARTITION BY toYYYYMM(EventDate)
ORDER BY (CounterID, EventDate, intHash32(UserID))
SAMPLE BY intHash32(UserID);



CREATE TABLE test.t_physical_Distributed on cluster physical_consistency_cluster
(
    EventDate DateTime,
    CounterID UInt32,
    UserID UInt32
)
ENGINE = Distributed(physical_consistency_cluster, test, t_local, CounterID);

INSERT INTO test.t_physical_Distributed VALUES ("2019-01-16 00:00:00", 1, 1),("2019-02-10 00:00:00",2, 2),("2019-03-10 00:00:00",3, 3)

3. 数据查询

# shard1-repl1

SELECT *
FROM test.t_local

Query id: d2bafd2d-d0a8-41b4-8d79-ece37e8159e5

┌───────────EventDate──┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │         3 │      3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │         2 │      2 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │         1 │      1 │
└─────────────────────┴───────────┴────────┘

3 rows in set. Elapsed: 0.004 sec. 

------------------------------------------

# shard1-repl2

SELECT *
FROM test.t_local

Query id: b5f0dc80-f73f-427e-b04e-e5b787876462

┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-01-16 00:00:00 │         1 │      1 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-03-10 00:00:00 │         3 │      3 │
└─────────────────────┴───────────┴────────┘
┌───────────EventDate─┬─CounterID─┬─UserID─┐
│ 2019-02-10 00:00:00 │         2 │      2 │
└─────────────────────┴───────────┴────────┘

3 rows in set. Elapsed: 0.005 sec. 

ReplicatedMergeTree 需要依靠 ZooKeeper 的事件监听机制以实现各个副本之间的协同,副本协同的核心流程主要有:INSERT、MERGE、MUTATION 和 ALTER 四种。

通过写入测试我们可以看到每个副本数据也是一致的,副本之间依靠 ZooKeeper 同步元数据,保证文件存储格式完全一致,可以理解这种方式是物理一致。

ReplicatedMergeTree 也是在分布式集群中最常用的一种方案,但数据同步需要依赖 ZooKeeper,在一些 DDL 比较频繁的业务中 Zookeeper 往往会成为系统性能的瓶颈,甚至会导致服务不可用。

我们需要考虑为 ZooKeeper 减负,使用第一种方案 + 负载均衡轮询的方式可以降低单节点写入的压力。

总结

  • internal_replication = false

使用 Distributed + MergeTree 可实现逻辑一致分布式。

数据内容完全一致,数据存储格式不完全一致,数据同步不依赖 ZooKeeper,副本的数据可能会不一致,单点写入压力较大。

  • internal_replication = true

使用 Distributed + ReplicateMergeTree 可实现物理一致分布式。

数据内容完全一致,数据存储格式完全一致。数据同步需要依赖 ZooKeeper,ZooKeeper 会成为系统瓶颈。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
转载请注明出处: https://daima100.com/5823.html

(0)
上一篇 2023-04-23
下一篇 2023-04-23

相关推荐

  • Python工程师:解析tempstr

    Python工程师:解析tempstr作为一名Python工程师,我们时常需要处理大量的数据,其中常用的一种数据格式就是字符串。而在字符串处理中,使用正则表达式是一种非常高效和灵活的方式,而正则表达式的一个关键就是:解析字符串。在这篇文章中,我们将会介绍如何使用Python来解析字符串,并针对不同场景进行实例演示。

    2024-04-16
    81
  • java calendar 月份_java编写日历

    java calendar 月份_java编写日历在此博客文章中,我们将使用调度程序库在Java Swing中构建每月日历。我们将使用日历的每月视图,但将使其仅在当前月份之后的3个月呈现。默认情况下,没有限制,用户可以在“单月”视图中前后滚动月份。…

    2023-03-31
    166
  • 你应该知道的数仓安全:都是同名Schema惹的祸

    你应该知道的数仓安全:都是同名Schema惹的祸摘要:我是管理员账号,怎么还没有权限?当小伙伴询问的时候,我第一时间就会想到都是用户同名Schema惹的祸 本文分享自华为云社区《你应该知道的数仓安全——都是同名Schema惹的祸》,作者: zhan

    2023-06-11
    129
  • docker启动mysql 自定义配置文件「建议收藏」

    docker启动mysql 自定义配置文件「建议收藏」命令行如下: 说明:

    2022-12-28
    162
  • 综合脚手架工程量怎么算_脚手架工程资质

    综合脚手架工程量怎么算_脚手架工程资质高日耀 资深数据库内核研发 毕业于华中科技大学,喜欢研究主流数据库架构和源码,并长期从事分布式数据库内核研发。曾参与分布式 MPP 数据库 CirroData 内核开发(东方国信),现主要负责 MyS

    2023-04-27
    156
  • Python List:数据结构中的重要概念

    Python List:数据结构中的重要概念在Python中,List是一个重要的数据结构,它是一组有序、可变、可重复的元素集合。List在Python编程中使用广泛,它的功能非常强大,可以完成很多的操作,包括添加、删除、修改、遍历等。

    2023-12-13
    103
  • 使用Python创建List

    使用Python创建List在Python编程中,List是一种常用的数据类型。List是一种有序的集合,也就是说,List中的每个元素都有对应的下标,可以根据下标来访问和修改List中的元素。List可以包含不同类型的元素,例如整型、浮点型、字符串、甚至是另外一个List。

    2024-05-02
    114
  • mysql整理_MySQL架构

    mysql整理_MySQL架构1.在 数据库内如何让自动增加字段从0开始 2.表中有A B C三列时,用SQL语句实现:当A列大于B列时选择A列,否则选择B列,当B列大于C列时选择B,否则选择C列 3. 是一个 存储系统。支持五种

    2023-02-10
    185

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注