副本扩容

说明

  • 副本有两种同步机制,分别为:
    • Distributed + MergeTree:
      • internal_replication=false 默认值
      • 相当于把所有语句发送到所有副本节点,但是副本节点变更、写入失败时,并不会处理失败数据,随着时间推移,会出现数据差异
    • Distributed + ReplicateMergeTree:
      • internal_replication=true
      • 分布式数据内容完全一致,数据存储格式完全一致
      • 数据同步需要依赖ZooKeeper,所以ZooKeeper会成为系统瓶颈
      • 在执行 INSERT 和 ALTER 查询的时候,ReplicatedMergeTree 需要借助 ZooKeeper 的分布式协同能力,以实现多个副本之间的同步
      • 在查询副本的时候,并不需要使用ZooKeeper
  • 针对两种不同的副本机制,有不同的副本扩容方案。

MergeTree ENGINE

说明

  • 注意,internal_replication 要为 false
  • 新增节点 ck04 ,作为 ck01 的副本
  • 新增副本节点不会从原历史副本节点同步历史数据,但是对于新增数据,集群副本之间能够正常同步
  • 操作流程:
    • 部署新节点,配置当前集群的完整信息
    • 原节点修改配置文件,在集群配置中添加新增副本节点信息,不需要停库,配置文件会自动重新加载。
    • 启动新增副本节点,并创建对应的复制本地表、分布式表
    • 在历史副本中,通过筛选导出历史数据,然后将历史数据导入新副本的本地表,以达到数据一致,期间集群的写入并不会受到影响
  • 当前数据说明:
    • 本地表:bank_user_info_local
      • 01分片行数:6206243
      • 01分片当前 max(id):2144054558
    • 全局代理表:bank_user_info_all
      • 全局表当前总行数:18615956
      • 全局表当前 max(id):2144054560

配置

部署新节点

  • 部署新节点 ck04
  • 启动 ck04 节点
1
clickhouse4/bin/clickhouse-server --config-file=/app/clickhouse/clickhouse4/etc/clickhouse-server/config.xml --daemon
  • 新节点同步创建用户
1
2
create user ckdba identified by '000000';
grant all on *.* to ckdba WITH GRANT OPTION;
  • 新节点查看集群信息
1
2
3
4
5
6
7
SELECT cluster,shard_num,host_address,port FROM system.clusters WHERE cluster = 'cluster_3S' ;
┌─cluster────┬─shard_num─┬─host_address─┬─port─┐
 cluster_3S          1  172.16.2.120  9001 
 cluster_3S          1  172.16.2.120  9004 
 cluster_3S          2  172.16.2.120  9002 
 cluster_3S          3  172.16.2.120  9003 
└────────────┴───────────┴──────────────┴──────┘

原始集群增加新节点

  • ck01/ck02/ck03 节点配置 ck04节点信息
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
    <remote_servers>
      <cluster_3S>
        <shard>
          <replica>
              <host>172.16.2.120</host>
              <port>9001</port>
              <user>default</user>
              <password>000000</password>
          </replica>
          <replica>
              <host>172.16.2.120</host>
              <port>9004</port>
              <user>default</user>
              <password>000000</password>
          </replica>
        </shard>
        <shard>
          <replica>
              <host>172.16.2.120</host>
              <port>9002</port>
              <user>default</user>
              <password>000000</password>
          </replica>
        </shard>
        <shard>
          <replica>
              <host>172.16.2.120</host>
              <port>9003</port>
              <user>default</user>
              <password>000000</password>
          </replica>
        </shard>
      </cluster_3S>
    </remote_servers>
  • 原有节点查看集群信息
1
2
3
4
5
6
7
SELECT cluster,shard_num,host_address,port FROM system.clusters WHERE cluster = 'cluster_3S' ;
┌─cluster────┬─shard_num─┬─host_address─┬─port─┐
 cluster_3S          1  172.16.2.120  9001 
 cluster_3S          1  172.16.2.120  9004 
 cluster_3S          2  172.16.2.120  9002 
 cluster_3S          3  172.16.2.120  9003 
└────────────┴───────────┴──────────────┴──────┘

新节点同步数据

  • 新节点创建要同步的 本地表/全局代理表
    • 注意:没有 ON CLUSTER
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
create database cktest;
CREATE TABLE cktest.bank_user_info_local
(
    `id` UInt32,
    `card_number` String,
    `province` String,
    `city` String,
    `user_name` String,
    `customer_no` String,
    `customer_phone` String,
    `gender` Int32 CODEC(ZSTD(1)),
    `age` Int32 CODEC(ZSTD(3)),
    `card_opening_time` Date
)
ENGINE = MergeTree
PARTITION BY toYYYYMM(card_opening_time)
PRIMARY KEY id
ORDER BY id
SETTINGS index_granularity = 8192;

CREATE TABLE cktest.bank_user_info_all
(
    `id` UInt32,
    `card_number` String,
    `province` String,
    `city` String,
    `user_name` String,
    `customer_no` String,
    `customer_phone` String,
    `gender` Int32 CODEC(ZSTD(1)),
    `age` Int32 CODEC(ZSTD(3)),
    `card_opening_time` Date
)
ENGINE = Distributed('cluster_3S', 'cktest', 'bank_user_info_local', rand());
  • 创建表后,后续写入 01 节点新写入的数据会自动写入副本节点

  • 01 节点写入部分数据测试同步是否正常

    • 写入过程:略
    • 01 节点查看写入后总条数
    1
    2
    3
    4
    
    select count(*) from bank_user_info_local;
    ┌─count()─┐
     6242906 
    └─────────┘
    
    • 04 节点查看写入后数据,04 节点本地表总行数为 01 节点新写入行数
      • 结果副本同步功能没问题
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    select count(*) from bank_user_info_local;
    ┌─count()─┐
       36663 
    └─────────┘
    
    select (6242906-6206243)
    ┌─minus(6242906, 6206243)─┐
                       36663 
    └─────────────────────────┘
    
  • 验证副本的同步功能没问题,手动写入配置同步之前 01 表已存在的数据

  • 01 节点导出未同步数据

1
2
/app/clickhouse/clickhouse1/bin/clickhouse-client -h 172.16.2.120  -u default  --port 9001 --password 000000 \
 --query="select * from cktest.bank_user_info_local where id <= 2144054558 " > sync_bank_user_info_local.tsv
  • 04 节点导入数据
1
cat sync_bank_user_info_local.tsv | /app/clickhouse/clickhouse1/bin/clickhouse-client -h 172.16.2.120  -u default  --port 9004 --password 000000  --query="insert into cktest.bank_user_info_local FORMAT TSV"
  • 04 查看当前总行数
    • 结果数据一致,新副本验证无问题
1
2
3
4
select count(*) from bank_user_info_local;
┌─count()─┐
│ 6242906 │
└─────────┘

ReplicatedMergeTree ENGINE

说明

  • ReplicatedMergeTree表引擎本身具备同步功能,所以不需要分布式表进行副本之间的数据复制(internal_replication为true),副本的数据同步交由zookeeper进行协同
  • 新增节点 ck04 ,作为 ck01 的副本
  • 操作流程:
    • 部署新节点,配置当前集群的完整信息
    • 原节点修改配置文件,在集群配置中添加新增副本节点信息,不需要停库,配置文件会自动重新加载。
    • 启动新增副本节点,并创建对应的复制本地表、分布式表
    • zookeeper 会自动将历史副本中的数据信息同步至新增副本节点中,进行数据的同步

配置

部署新节点

  • 部署新节点 ck04
  • 启动 ck04 节点
1
clickhouse4/bin/clickhouse-server --config-file=/app/clickhouse/clickhouse4/etc/clickhouse-server/config.xml --daemon
  • 新节点同步创建用户
1
2
create user ckdba identified by '000000';
grant all on *.* to ckdba WITH GRANT OPTION;
  • 新节点查看集群信息
1
2
3
4
5
6
7
SELECT cluster,shard_num,host_address,port FROM system.clusters WHERE cluster = 'cluster_3S' ;
┌─cluster────┬─shard_num─┬─host_address─┬─port─┐
 cluster_3S          1  172.16.2.120  9001 
 cluster_3S          1  172.16.2.120  9004 
 cluster_3S          2  172.16.2.120  9002 
 cluster_3S          3  172.16.2.120  9003 
└────────────┴───────────┴──────────────┴──────┘

原始集群增加新节点

  • ck01/ck02/ck03 节点配置 ck04节点信息
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
    <remote_servers>
      <cluster_3S>
        <shard>
          <internal_replication>true</internal_replication>
          <replica>
              <host>172.16.2.120</host>
              <port>9001</port>
              <user>default</user>
              <password>000000</password>
          </replica>
          <replica>
              <host>172.16.2.120</host>
              <port>9004</port>
              <user>default</user>
              <password>000000</password>
          </replica>
        </shard>
        <shard>
          <internal_replication>true</internal_replication>
          <replica>
              <host>172.16.2.120</host>
              <port>9002</port>
              <user>default</user>
              <password>000000</password>
          </replica>
        </shard>
        <shard>
          <internal_replication>true</internal_replication>
          <replica>
              <host>172.16.2.120</host>
              <port>9003</port>
              <user>default</user>
              <password>000000</password>
          </replica>
        </shard>
      </cluster_3S>
    </remote_servers>
  • 原有节点查看集群信息
1
2
3
4
5
6
7
SELECT cluster,shard_num,host_address,port FROM system.clusters WHERE cluster = 'cluster_3S' ;
┌─cluster────┬─shard_num─┬─host_address─┬─port─┐
 cluster_3S          1  172.16.2.120  9001 
 cluster_3S          1  172.16.2.120  9004 
 cluster_3S          2  172.16.2.120  9002 
 cluster_3S          3  172.16.2.120  9003 
└────────────┴───────────┴──────────────┴──────┘

各个节点配置节点变量

  • 各个节点配置节点信息的变量,这样建表时不用没个节点使用独立的建标语句
  • 01/02/03 分别是第1/2/3个分片的第1个副本
  • 04 为 01 节点的副本,即第1个分片的第2个副本
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
$ cat clickhouse[1-4]/etc/clickhouse-server/config.d/host.xml
# 01 节点配置
<yandex>
    <macros>
        <cluster>cluster_3S</cluster>
        <shard>1</shard>
        <replica>1</replica>
    </macros>
</yandex>

# 02 节点配置
<yandex>
    <macros>
        <cluster>cluster_3S</cluster>
        <shard>2</shard>
        <replica>1</replica>
    </macros>
</yandex>

# 03 节点配置
<yandex>
    <macros>
        <cluster>cluster_3S</cluster>
        <shard>3</shard>
        <replica>1</replica>
    </macros>
</yandex>

# 04 节点配置
<yandex>
    <macros>
        <cluster>cluster_3S</cluster>
        <shard>1</shard>
        <replica>2</replica>
    </macros>
</yandex>
  • 验证:各节点可执行sql查看当前节点已配置变量
1
2
3
4
5
6
select * from system.macros;
┌─macro───┬─substitution─┐
 cluster  cluster_3S   
 replica  2            
 shard    1            
└─────────┴──────────────┘

新节点同步数据

  • 查看 01 节点当前本地表和全局代理表总行数
1
2
3
4
5
6
7
8
9
select count(*) from bank_user_info_replica_all;
┌──count()─┐
 18726189 
└──────────┘

select count(*) from bank_user_info_replica_local;
┌─count()─┐
 6241631 
└─────────┘
  • 新节点(04)创建要同步的 本地表/全局代理表
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
CREATE TABLE cktest.bank_user_info_replica_local
(
    `id` UInt32,
    `card_number` String,
    `province` String,
    `city` String,
    `user_name` String,
    `customer_no` String,
    `customer_phone` String,
    `gender` Int32 CODEC(ZSTD(1)),
    `age` Int32 CODEC(ZSTD(3)),
    `card_opening_time` Date
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/bank_user_info_replica_local', '{replica}')
PARTITION BY toYYYYMM(card_opening_time)
PRIMARY KEY id
ORDER BY id
SETTINGS index_granularity = 8192;


CREATE TABLE cktest.bank_user_info_replica_all
(
    `id` UInt32,
    `card_number` String,
    `province` String,
    `city` String,
    `user_name` String,
    `customer_no` String,
    `customer_phone` String,
    `gender` Int32 CODEC(ZSTD(1)),
    `age` Int32 CODEC(ZSTD(3)),
    `card_opening_time` Date
)
ENGINE = Distributed('cluster_3S', 'cktest', 'bank_user_info_replica_local', rand());
  • 查看新增节点同步到的数据
1
2
3
4
select count(*) from bank_user_info_replica_local;
┌─count()─┐
 6241631 
└─────────┘
  • 01 节点再写入部分数据,查看写入数据后行数
    • 写入数据:略
1
2
3
4
5
6
7
8
9
select count(*) from bank_user_info_replica_all;
┌──count()─┐
 39800152 
└──────────┘

select count(*) from bank_user_info_replica_local;
┌──count()─┐
 13266975 
└──────────┘
  • 04 节点查看当前数据
    • 结果数据一致,新副本验证无问题
1
2
3
4
5
6
7
8
9
select count(*) from bank_user_info_replica_all;
┌──count()─┐
 39800152 
└──────────┘

select count(*) from bank_user_info_replica_local;
┌──count()─┐
 13266975 
└──────────┘

参考