【跨国数仓迁移实践10】 MMS助力GoTerra实现BigQuery到MaxCompute 50PB数据迁移

106 阅读10分钟

本系列文章将围绕东南亚头部科技集团 GoTerra 的真实迁移历程展开,逐步拆解 BigQuery 迁移至 MaxCompute 过程中的关键挑战与技术创新。本篇为第10篇,MMS如何助力GoTerra实现BigQuery到MaxCompute 50PB数据迁移

注:客户背景为东南亚头部科技集团,文中用 GoTerra 表示。

2025年6月,随着 GoTerra 集团最后一个GCP BigQuery分区 19.5 GB 的数据迁移到阿里云MaxCompute,历时 6 个月、总量高达 50PB 的数据迁移项目终于圆满收官。
这是一个跨越大洲(从美国到印尼)、涉及10 多个公司实体、数十个project、数十万张table的大规模迁移工程,目标是在仅 6 个月内完成迁移——任务艰巨,挑战空前。

这不是一次传统的全量同构迁移,还包含增量异构迁移,对迁移工具、数据处理能力、网络传输、协同机制都提出了极高要求。
而这一切,都由为大数据迁移而生的 MMS(MaxCompute Migration Service) 轻松承载。

1、项目背景与挑战

GoTerra集团把大数据业务从BigQuery迁移到MaxCompute,项目涉及非常广泛:

  • 数据规模:按BigQuery logical size统计,大约50PB
  • 数据对象:大约70个Project、10万张table
  • 业务范围:10+个Account,每个Account背后是一个子公司实体
  • 项目节奏:2025年1月启动迁移,6月底完成

除此之外,还有技术上的挑战:

  1. DataType复杂: 客户大量使用Array、JSON和Struct类型,其中存在多层Struct类型嵌套的情形,还使用到Decimal、timestamp、datetime等类型
  2. 分区策略多样: BigQuery支持非常灵活的分区策略,比如Time-unit column partitioning和Ingestion time partitioning
  3. 迁移速度要求高: 6个月迁移50PB,不出任何差错的情况下,至少每周迁移2PB。因此每周3PB才有较大容错空间
  4. 迁移灵活调度: 需要满足不同业务方多样化优先级需求
  5. API first:所有迁移功能,必须以API的形式提供给GoTerra客户

2、对象迁移方案

2.1 数据对象映射

BigQuery采用三层对象模型:Project -- Dataset -- Table

因此迁移到MaxCompute,继续保持三层模型:Project -- Schema -- Table

源对象目标对象
BigQuery ProjectMaxCompute Project
BigQuery DatasetMaxCompute Schema
BigQuery TableMaxCompute Table

2.2 数据类型映射

BigQuery 数据类型MaxCompute数据类型备注
BooleanBoolean
Bytes(L)Binary(L)
DateDate
DatetimeTimestamp_NTZ由于BigQuery Datetime 是non-timezone,
且精度到10-6
MaxCompute Timestamp_NTZ也是一种non-time zone的数据类型,精度到精度到10-9
JSONJSONJSON
INT64
SQL aliases:
INT, SMALLINT, INTEGER, BIGINT, TINYINT, BYTEINT
bigint
NUMERIC
SQL aliases: DECIMAL
Decimal(38, 9)BigQuery NUMERIC 默认精度:
+ precision=38,
+ scale=9
DECIMAL(p[,s])DECIMAL(p[,s])BigQuery精度 :
Maximum scale range: 0 ≤ S ≤ 9
Maximum precision range: max(1, S) ≤ P ≤ S + 29
MaxCompute精度 :
Maximum scale range: 0 ≤ S ≤ 30
Maximum precision range: max(1, S) ≤ P ≤ 38
因此可以MaxCompute DECIMAL可以完全兼容BigQuery DECIMAL类型
BIGNUMERIC
SQL aliases: BIGDECIMAL
Decimal(p,s)
BigQuery BIGNUMERIC默认精度:
+ precision=76,
+ scale=38
由于MaxCompute 没有BIGDECIMAL类型,
同时以上默认精度也超出了MaxCompute DECIMAL类型的值域,
因此对于BigQuery BIGNUMERIC类型,需要由客户根据自己的数据特征,来指定目标精度
BIGDECIMAL(p[,s])DECIMAL(p[,s])同上,需要客户保证数据特征,指定目标精度
FLOAT64DoubleDouble
RangeStringMaxCompute没有Range类型,因此转为String
StringStringString
StructStructStruct
TimeBigint计算出 00:00:00.000000的offset 整数值value,以微秒为单位
TimestampTimestamp_NTZ由于前期沟通的失误,迁移团队把BigQuery timestamp映射到MaxCompute Timestamp
其实合理的映射应该是Timestamp_NTZ
GeographyStringMaxCompute没有Geography类型,因此转为String
IntervalStringINTERVAL_YEAR_MONTH /
INTERVAL_DAY_TIME
ArrayArrayMaxCompute不支持 T=JSON 的情况,
MMS把它转成Array,且它的element value以 jsonString形式存在

2.3 分区策略映射

BigQuery提供非常丰富的分区策略

2.3.1 Integer range partitioning

- 按指定integer columnrange 分区
- 由于客户没用到该分区策略,MaxCompute没有支持

2.3.2 Time-unit column partitioning

- MaxCompute通过 auto partitioned 机制 生成一个伪列来等价实现BigQuery Time-unit 分区效果
- DDL demo如下:
Time-UnitBigQuery DDLMaxCompute DDL
dailycreate table test_table (id int64, d date) partition by d;create table test_table (id bigint, d date)
AUTO PARTITIONED BY (trunc_time(d, 'day') as _partition_value);
monthlycreate table test_table (id int64, d date)
partition by date_trunc(d, MONTH);
create table test_table (id bigint, d date)
AUTO PARTITIONED BY (trunc_time(d, 'month') as _partition_value);

2.3.3 Ingestion time partitioning

- BigQuery在处理Ingestion time partitioning时,通过在insert record时,自动记录insert timestamp,并存储在 伪列_PARTITIONTIME上
- MaxCompute通过auto partitioned 来实现BigQuery的Ingestion time分区效果
- DDL demo 如下:
Time-UnitBigQuery DDLMaxCompute DDL
hourlycreate table test_table (a string) PARTITION BY TIMESTAMP_TRUNC(_PARTITIONTIME, HOUR);
create table test_table(a string, _partitiontime timestamp_ntz) auto partitioned by (trunc_time(_partitiontime, 'hour') as _partition_value);
dailycreate table test_table (a string) PARTITION BY _PARTITIONDATE;create table test_table(a string, _partitiontime timestamp_ntz) auto partitioned by (trunc_time(_partitiontime, 'day') as _partition_value);

3、迁移系统架构

迁移系统在技术选型上

3.1 方案一

画板

  • 先把BigQuery table数据dump到GCS
  • 再通过传输工具把GCS文件传到OSS
  • 最后使用MaxCompute external table技术把OSS文件导入

3.2 方案二

画板

基于BigQuery Read API,通过MaxCompute Spark直接读BigQuery数据,直接写入MaxCompute

3.3 方案选型

综合考虑了易用性、成本与架构简洁性,MMS选择方案二。

3.4 网络专线方案

画板

4、迁移关键技术

提供对象映射能力只是“万里长征第一步”,在此之上还要解决迁移速度、迁移原子性、优先调度、Column-Reorder-Fillback、双跑追增量等关键问题。

4.1 迁移速度优化

为了做到每周3PB的迁移速度,MMS主要从以下三方面着手:

  • 网络带宽层面,需要专线保障,规划50Pbs
  • 迁移系统读BigQuery数据时,启用压缩
  • 为Spark迁移任务预备了数千CU计算资源,随时待命

经过以上优化后,迁移专线带宽常态化接近用满的状态

每周3PB的目标也很轻松达到,顶峰时期,单天跑出1.92PB的极限速度。

4.2 迁移原子性

客户有一天在群里问我们,有个partition明明有数据,为什么有时查不到数据。

经过分析发现,MMS在迁移的时候,采用的做法是

drop if exists partition
create if not exits partition
insert into ... select ...

以上流程明显有问题,在drop和commit 之间,从数据使用者角度 这个partition就是没数据的。

假如这个时候迁移系统因为网络或pod资源问题,可能会造成更大时间跨度的不一致。

因此,一种具备原子性的迁移方案呼之欲出:

insert overwrite ... select ...

由于MaxCompute只支持 statement 级别的原子性,insert overwrite 语句的效果,相当于DBMS

begin;
drop if exists partition
create if not exits partition
insert into ... select ...
commit;

4.3 优先调度

GoTerra客户内部有上百个业务团队,他们对不同table、partition迁移紧迫性是不一样的。

  1. 有的部门说,我今天就要在MaxCompute用到这些数据,越快越好
  2. 有的部门说,这批数据,我这几天还不需要的,但是我下周一定要用到
  3. 有的部门说,这批数据,量非常大,我几个月后才需要

由于上述第1类场景的存在,GoTerra客户负责数据迁移的平台团队,一开始每天向内部收集迁移需求,然后向MMS提交一批迁移任务。要确保这批任务全部完成后,他们才会启动下一批迁移任务。

有时客户内部有紧急迁移需求,还不得不暂停正在迁移的任务,让MMS优先处理紧急的。

等到这批紧急的迁移完成后,再人工重启刚刚暂停的任务。

沟通成本非常高!

这样运行了一周后,MMS团队被客户搞崩溃了,于是设计了基于优先级的调度功能。

这里的优先级priority不是传统的自然数 ( 比如 0~9 ) ,毕竟确定priority 每个value的语义,也不是容易的事。

MMS团队借用了平时排需求的**ETA(Estimated Time of Arrival)**概念,作为实际的优先级定义,无论是客户,还是MMS团队,都很容易理解哪天需要完成这个迁移任务。

有了基于ETA优先调度能力后,客户就可以更好的统筹迁移任务,并且MMS可以做到7*24全天候迁移。

4.4 Column-Reorder-Fillback

为什么会出现column reorder

GoTerra客户存在一批实时写入的streaming表,数据架构大致如下:

画板

Kafka系统的message 是带 record schema的

客户自建了一个X-Flink系统(类似Flink的流计算系统),根据上游kafka的message,按需执行add column。

对于这一类streaming表,靠迁移BigQuery端的数据,是永远无法把X-Flink系统迁移到MaxCompute的

因此迁移过程,源端streaming表与目标端streaming表将在一段时间同时被写入的情况,即双跑局面:

画板

  • 1 实时系统 推送消息到kafka
  • 2 GCP侧 X-Flink 拉取 kafka数据
  • 3 GCP侧 X-Flink 实时写入GCP侧Streaming表-A
  • 4 阿里云侧 X-Flink 拉取 kafka数据
  • 5 阿里云侧 X-Flink 实时写入阿里云Streaming表-B
  • 6 GCP侧Streaming表-A Fillback 数据到阿里云Streaming表-B

在双跑期间,由于各种各样的原因,阿里云Streaming表与GCP侧Streaming表数据将存在差异

因此需要步骤6 Fillback 来修正两边Streaming表的差异。

同时,由于步骤3与步骤5 执行add column的时机不同,就导致表A与表B的字段顺序不同。

如何处理Column reorder Fillback

  • 对于基本类型的字段,column reorder fillback 是比较简单的
  • 对于Struct嵌套类型的字段,需要逐级对sub field做旋转操作

以struct 类型为例,

create table a(
  c1 struct<c1_1:String,c1_2:struct<c1_2_1:String,c1_2_2:String>,c1_3:String>
);

create table b(
  c1 struct<c1_3:String,c1_2:struct<c1_2_2:String,c1_2_1:String>,c1_1:String>
);

以下是column reorder的fillback 过程如下:

画板

4.5 双跑期间增量数据迁移优化

双跑期间,GoTerra客户几乎所有的ETL都要在BigQuery 与 MaxCompute两边同时运行。

为了能在MaxCompute侧运行当日ETL,需要提前准备好对应的上游数据分区。

客户要求MMS在2小时内把这些分区的数据从BigQuery迁移到MaxCompute。

为此,MMS系统对任务调度算法进一步升级。

为了方便描述,下文把SLA=2小时的迁移任务,称为紧急迁移任务。

原有的调度算法

原来调度 priority(ETA)只在 Project内生效,即不同的Project的迁移任务完全隔离。

如下图,MMS 会从每个Project中挑选 ETA最小的task执行

画板

如上图,Project A有4个紧急迁移任务,ETA都在2024年5月份,

Project B有4个普通迁移任务,ETA都在2025年5月份。

此时 task1与task5同时被调度执行。

客户双跑第一天,紧急迁移任务平均完成时间超过6小时,远低于客户要求。

改进后的调度算法

只要把Prority改为全局调度就解决了客户问题

画板

改进后,紧急任务的平均完成时间在30分钟以内,顺利保障了客户双跑期间对上游分区的紧急同步需求。

5、未来规划

在完成 GoTerra客户迁移后,MaxCompute与MMS产品依然在演进:

  • 未来将全面对齐BigQuery数据类型,尤其是Geography与BigDecimal
  • MMS将支持 View的迁移
  • 支持更智能的调度算法,动态感知带宽并调整迁移任务资源分配