将自建ClickHouse数据迁移到云ClickHouse中

当您计划将自建数据库ClickHouse迁移到云数据库ClickHouse提升业务的可扩展性和可靠性时,本文档将为您提供实际操作指南以及如何处理可能遇到的问题。参考本文档迁移策略,您将能够高效、安全地完成数据迁移,并最大化云端环境的利益。

说明

出于安全考虑,云数据库ClickHouse无法直接访问公网,只能够访问同一VPC内的其他服务器。所以数据迁移前,请确保自建实例与目标实例云数据库ClickHouse之间网络通畅。

方案概览

数据迁移策略分为两个主要步骤:首先是元数据迁移,确保所有的表结构等正确无误的迁移到云数据库ClickHouse;其次是数据迁移,您可以选择使用ClickHouse的remote函数直接迁移数据,或者将数据导出并在云数据库ClickHouse导入完成迁移。

自建实例与目标实例的网络关系

迁移方法

自建实例部署在阿里云ECS中,且该ECS与云数据库ClickHouse为同一个VPC。

  1. 步骤一:元数据(建表的DDL)的迁移

  2. 通过remote函数进行数据迁移

自建实例部署在阿里云ECS中,且该ECS与云数据库ClickHouse为不同VPC。

  1. 首先需要将两个VPC网络连通,详细操作请参见跨VPC互联解决方案概述

  2. 步骤一:元数据(建表的DDL)的迁移

  3. 通过remote函数进行数据迁移

自建实例不在阿里云ECS中,例如在线下自建IDC内。

  1. 首先需要将线下IDC与阿里云VPC连通,详细操作请参见连接本地IDC

  2. 步骤一:元数据(建表的DDL)的迁移

  3. 通过remote函数进行数据迁移

自建实例与目标实例无法进行网络连通操作。

  1. 步骤一:元数据(建表的DDL)的迁移

  2. 通过文件导出导入方式进行数据迁移

无法进行网络连通操作,但是已经有了Spark、Flink等基础设施。

可以尝试编写Spark、Flink job将自建实例数据读出,然后写入目标实例云数据库ClickHouse。

步骤一:元数据(建表的DDL)的迁移

ClickHouse元数据的迁移,主要指进行建表DDL迁移。

如需安装clickhouse-client工具,请安装与目标实例云数据库ClickHouse版本一致的clickhouse-client工具。下载链接,请参见clickhouse-client

  1. 查看自建实例的database列表。

    clickhouse-client --host="<old host>" --port="<old port>" --user="<old user name>" --password="<old password>" --query="SHOW databases"  > database.list

    参数说明:

    参数

    描述

    old host

    自建实例的地址。

    old port

    自建实例的端口。

    old user name

    登录自建实例的账号,拥有DML读写和设置权限,允许DDL权限。

    old password

    上述账号对应的密码。

    说明

    system是系统数据库,不需要迁移,可以直接过滤掉。

  2. 查看自建实例的table列表。

    clickhouse-client --host="<old host>" --port="<old port>" --user="<old user name>" --password="<old password>" --query="SHOW tables from <database_name>"  > table.list

    参数说明:

    参数

    描述

    database_name

    数据库名称

    您也可以通过系统表直接查询所有database和table名称。

    SELECT DISTINCT database, name FROM system.tables WHERE database != 'system';
    说明

    查询到的表名中,如果有以.inner.开头的表,则它们是物化视图的内部表示,不需要迁移,可以直接过滤掉。

  3. 导出自建实例中指定数据库下所有表的建表DDL。

    clickhouse-client --host="<old host>" --port="<old port>" --user="<old user name>" --password="<old password>" --query="SELECT concat(create_table_query, ';') FROM system.tables WHERE database='<database_name>' FORMAT TabSeparatedRaw" > tables.sql
  4. 将建表DDL导入到目标实例云数据库ClickHouse。

    说明

    您需要在建表DDL导入之前,在云数据库ClickHouse中创建表所在数据库。

    clickhouse-client --host="<new host>" --port="<new port>" --user="<new user name>" --password="<new password>"  -d '<database_name>'  --multiquery < tables.sql

    参数说明:

    参数

    描述

    new host

    目标实例云数据库ClickHouse的地址。

    new port

    目标实例云数据库ClickHouse的端口。

    new user name

    登录目标实例云数据库ClickHouse的账号,拥有DML读写和设置权限,允许DDL权限。

    new password

    上述账号对应的密码。

步骤二:数据迁移

通过remote函数进行数据迁移

  1. (可选)在进行云数据库ClickHouse数据迁移时,如果需要考虑网络流量。您可以通过调整network_compression_method参数来选择合适的压缩算法,减少流量的使用。

    • 在目标实例云数据库ClickHouse中临时修改或查看network_compression_method,示例如下。

    • SET network_compression_method = 'ZSTD';
    • 在目标实例云数据库ClickHouse中查看network_compression_method参数值,示例如下。

    • SELECT * FROM system.settings WHERE name = 'network_compression_method';
  2. 在目标实例云数据库ClickHouse中,通过如下SQL进行数据迁移。

INSERT INTO <new_database>.<new_table> 
SELECT * 
FROM remote('<old_endpoint>', <old_database>.<old_table>, '<username>', '<password>') 
[WHERE _partition_id = '<partition_id>']
SETTINGS max_execution_time = 0, max_bytes_to_read = 0, log_query_threads = 0;
说明

20.8版本优先使用remoteRaw函数进行数据迁移,如果失败可以申请小版本升级。

INSERT INTO <new_database>.<new_table> 
SELECT * 
FROM remoteRaw('<old_endpoint>', <old_database>.<old_table>, '<username>', '<password>')
[WHERE _partition_id = '<partition_id>']
SETTINGS max_execution_time = 0, max_bytes_to_read = 0, log_query_threads = 0;

参数说明:

重要

通过partition_id对数据过滤后,可以减少资源占用,建议您选用此参数。

(可选)如果您不知道如何获取partition_id及part的数量,可以通过以下SQL在system.parts系统中查询。

SELECT partition_id, count(*) AS part_count from clusterAllReplicas(default, system, parts) WHERE `database` = '<old_database>' AND `table` = '<old_table>' GROUP BY partition_id ;

参数

描述

new_database

目标云数据库ClickHouse实例中的数据库名。

new_table

目标实例云数据库ClickHouse中的表名。

old_endpoint

源实例的endpoint。

自建ClickHouse

endpoint格式:源实例节点的IP:port

重要

此处port为TCP port。

云数据库ClickHouse

源实例的endpoint为VPC内网endpoint,不是公网endpoint。

重要

以下端口3306和9000是固定值。

  • 社区版实例:

    • endpoint格式:VPC内网地址:3306

    • 示例:cc-2zeqhh5v7y6q*****.clickhouse.ads.aliyuncs.com:3306

  • 企业版实例:

    • endpoint格式:VPC内网地址:9000

    • 示例:cc-bp1anv7jo84ta*****clickhouse.clickhouseserver.rds.aliyuncs.com:9000

old_database

自建实例的数据库名。

old_table

自建实例的表名。

username

自建实例的账号。

password

自建实例的密码。

max_execution_time

查询的最大执行时间。设置为0表示没有时间限制。

max_bytes_to_read

查询在读取源数据时能读取的最大字节数。设置为0表示没有限制。

log_query_threads

是否记录查询执行的线程信息。设置为0表示不记录线程信息。

_partition_id

数据分区ID。

通过文件导出导入方式进行数据迁移

通过文件,将数据从自建实例数据库导出到目标实例云数据库ClickHouse中。

  • 通过CSV文件导出导入

    1. 将数据从自建实例数据库导出为CSV格式文件。

      clickhouse-client --host="<old host>" --port="<old port>" --user="<old user name>" --password="<old password>"  --query="select * from <database_name>.<table_name> FORMAT CSV"  > table.csv
    2. 导入CSV文件到目标实例云数据库ClickHouse。

      clickhouse-client --host="<new host>" --port="<new port>" --user="<new user name>" --password="<new password>"  --query="insert into <database_name>.<table_name> FORMAT CSV"  < table.csv
  • 通过Linux pipe管道进行流式导出导入

    clickhouse-client --host="<old host>" --port="<old port>" --user="<user name>" --password="<password>"  --query="select * from <database_name>.<table_name> FORMAT CSV" | 
    clickhouse-client --host="<new host>" --port="<new port>" --user="<user name>" --password="<password>"   --query="INSERT INTO <database_name>.<table_name> FORMAT CSV"

常见问题

  • Q:如何处理报错:“Too many partitions for single INSERT block (more than 100)”?

    A:单个INSERT操作中超过了max_partitions_per_insert_block(最大分区插入块,默认值为100)。ClickHouse每次写入都会生成一个data part(数据部分),一个分区可能包含一个或多个data part,如果单个INSERT操作中插入了太多分区的数据,那会造成ClickHouse内部有大量的data part(会给合并和查询造成很大的负担)。为了防止出现大量的data part,ClickHouse内部做了限制。

    解决方案:请执行以下操作,调整分区数或者max_partitions_per_insert_block参数。

    • 调整表结构,调整分区方式,或避免单次插入的不同分区数超过限制。

    • 避免单次插入的不同分区数超过限制,可根据数据量适当修改max_partitions_per_insert_block参数,放大单个插入的不同分区数限制,修改语法如下:

      SET GLOBAL ON cluster DEFAULT max_partitions_per_insert_block = XXX;
      说明

      ClickHouse社区推荐默认值为100,分区数不要设置得过大,否则可能对性能产生影响。在批量导入数据后可修改值为默认值。

  • Q:为什么目标实例云数据库ClickHouse连接自建数据库ClickHouse连接失败?

    A:可能是您的自建数据库ClickHouse设置了防火墙或白名单等操作。可以在云数据库ClickHouse控制台查看云数据库ClickHouse的VPC网络,并且将该VPC的整个网段都加入到自建数据库ClickHouse的白名单中。如果希望控制白名单的网段范围,避免潜在安全问题,那么可以通过如下SQL查询到目标实例云数据库ClickHouse的后台Server IP,只将这几个IP加入自建实例的白名单中。

    SELECT * FROM system.clusters;