通过双写迁移数据至云数据库ClickHouse

在迁移业务数据至云数据库ClickHouse的过程中,如果数据量规模大、写入吞吐量高或者数据生命周期(TTL)较短,为避免数据同步延迟导致新旧集群状态不一致,您可以采用双写方案进行数据迁移。双写过程中,业务应用层同时向源集群和新的目标集群写入增量数据,并一次性迁移历史存量数据。通过此方式,可以有效降低数据同步延迟,实现数据的平滑过渡,减少对线上业务的影响。

方案概述

本方案的核心思路是通过双写机制,在保障业务连续性的前提下完成数据迁移。基本流程如下:

  1. 准备目标集群:购买目标集群,并在目标集群中创建好与源集群结构一致的数据库和表。

  2. 启用双写:改造业务写入逻辑,使新的数据同时写入源和目标两个集群。

  3. 迁移存量数据:将某个时间点之前的历史数据从源集群迁移至目标集群。

  4. 切换读流量:将业务的读取流量从源集群切换至目标集群。

  5. 验证业务并停止双写:观察业务在新集群的运行状态,验证通过后,停止向源集群写入数据。

根据您的数据表是否按时间分区,本文提供以下两种具体的操作方法:

  • 按时间分区的数据迁移:适用于数据按照时间分区存储的场景。

  • 非时间分区(含时间字段)的数据迁移:适用于数据未按时间分区,但每行数据包含时间字段的场景。

适用范围

业务不会对历史数据进行写操作,以避免存量数据迁移过程中出现不一致的情况。

按时间分区的数据迁移

本方法适用于数据表以按照时间维度(如按天、按月)进行分区的情况。

  1. 准备目标集群:新建集群,并在目标集群中创建好与源集群结构一致的数据库和表。

  2. 启用双写。改造业务应用,向源集群和目标集群同步写入数据(假设当前写入的分区为T1)。

  3. 迁移存量数据。将T1分区及之前的所有历史数据从源集群迁移至目标集群。

    • TTL场景:如果表的TTL设置较短,并且可以接受等待TTL的时长,那么可以不进行手动的存量迁移。等待旧数据在源集群上因TTL过期而自动删除后,两边的数据达到一致性状态。

    • TTL或立即迁移场景:如果TTL较长,或希望尽快完成迁移,请参见以下步骤迁移数据。

      1. 等待数据不再写入目标集群T1分区。

      2. 清理目标集群T1分区数据。

        -- 清理分区数据
        ALTER TABLE table_name DROP PARTITION T1;
        
        -- 检查数据不存在
        SELECT count() FROM table_name WHERE partition_key = T1;
      3. 迁移所有小于或等于T1的历史分区数据。

        说明

        如果等待不再写入T1分区的时间太长,或期望尽早完成存量数据迁移,则建议小于T1分区的存量数据迁移使用方案1,T1分区的存量数据迁移使用方案2。

        方案1:使用BACKUPRESTORE命令迁移(推荐)

        1. 通过BACKUPRESTORE命令,将源集群的数据迁移到新集群的临时库。具体操作,请参见使用BACKUPRESTORE命令实现数据备份恢复

        2. 将临时库的数据按照分区搬迁至生产库(ALTER MOVE速度较快)。

          ALTER TABLE table_source MOVE PARTITION partition_expr TO TABLE table_dest;

        方案2:使用INSERT INTO SELECT FROM remote方式迁移

        1. 通过INSERT INTO SELECT FROM remote的方式,将源集群的数据写入到目标集群的生产库。具体操作,请参见将自建ClickHouse向企业版迁移

        2. 如果出现迁移异常,可以删除数据后重新迁移。

          -- 按照时间分区清理
          ALTER TABLE table_name DROP PARTITION partition_expr;
          
          -- 按照时间清理
          ALTER TABLE table_name DELETE WHERE {TIME}>='{TIME1}' AND {TIME}<='{TIME2}';
  4. 切换读流量。确认存量数据迁移完成后,将业务应用的读请求全部切换到目标集群。

  5. 验证业务并停止双写。观察业务在新集群的运行状态,验证通过后,停止向源集群写入数据。

非时间分区(含时间字段)的数据迁移

此方法适用于数据表本身未设置时间分区,但每行数据中都包含时间字段的情况。

  1. 准备目标集群。新建集群,并在目标集群中创建好与源集群结构一致的数据库和表。

  2. 启用双写。改造业务应用,向源集群和目标集群同步写入数据。

  3. 清理目标集群某个时刻T1之前的数据。

    -- 清理<=T1的数据
    ALTER TABLE table_name DELETE WHERE {TIME}<='{T1}';
    
    -- 检查数据不存在
    SELECT count() FROM table_name WHERE {TIME}<='{T1}';
  4. 迁移存量数据。

    1. 通过INSERT INTO SELECT FROM remote的方式,将源集群的数据分批写入到新集群的生产库。具体操作,请参见将自建ClickHouse向企业版迁移

    2. 如果出现迁移异常,可以删除数据重新迁移。

      ALTER TABLE table_name DELETE WHERE {TIME}>='{T1}' AND {TIME}<='{T2}';
  5. 切换读流量。确认存量数据迁移完成后,将业务应用的读请求全部切换到目标集群。

  6. 验证业务并停止双写。观察业务在新集群的运行状态,验证通过后,停止向源集群写入数据。