如何将 10 TB 拆分为 64 MB 块并并行导入?
解读
面试官真正想考察的是:
- 对 Cloud SQL 单实例 64 TB 上限、单表 16 TB、单事务 6 h 超时 等硬性边界的理解;
- 能否把“大文件拆块”与“Cloud SQL 并行导入”两条技术线无缝衔接,兼顾 网络带宽、IOPS、锁竞争、GTID 一致性、费用;
- 是否具备 国内合规 意识(跨境传输、敏感数据脱敏、公网/私网选型);
- 能否给出 可落地的 SOP,包括失败重试、幂等、监控告警、回滚方案。
一句话:不是“会拆文件”,而是“让 10 TB 数据在 国内 Cloud SQL 高可用实例 上 24 h 内安全落地,且业务只读窗口 <30 min”。
知识点
-
Cloud SQL 导入路径
- 内网:Cloud Storage → 私网 VPC Service Controls → Cloud SQL 实例(Private IP)
- 外网:Cloud SQL Auth Proxy + SSL 客户端证书(国内需备案域名)
两者均支持 并行导入(parallel=threads),但 单文件仍串行,必须预先拆块。
-
拆块原则
- 行级拆分:使用 split 工具(Linux)或 gsutil compose 合并时保持 UTF-8 行边界,防止中文截断;
- 块大小:64 MB 是 Cloud SQL 单线程导入吞吐拐点(≈120 MB/s,64 MB 块 0.5 s 完成,排队理论最优);
- 分片键:优先 主键区间 或 自增 ID 模运算,避免热点;
- 文件数:10 TB / 64 MB ≈ 163 840 个对象,需 分批前缀(gs://bucket/shard_000/…)防止 GCS 单目录 1 k QPS 上限。
-
并行导入上限
- 单实例最大 32 个并发导入线程(MySQL 8.0 高可用版);
- 每线程占用 1 条 后端连接(max_connections 默认 4000,但导入线程与业务连接共享池);
- 磁盘写带宽:SSD 实例 30 k IOPS,顺序写 480 MB/s,32×64 MB ≈ 2 GB/s 峰值,需 预扩容磁盘(至少 5 TB 才能拿到 30 k IOPS)。
-
国内网络优化
- 选择 北京/上海/深圳 Region 的 Premium 层级(国内三大运营商直连 Google 边缘 POP);
- 开通 Cloud CDN 回源私有云 仅对 GCS 生效,可节省 15% 跨境流量费;
- 若源数据在阿里云 OSS,可先用 gsutil rsync -m 走 专线 DC(阿里云高速通道 → 第三方 IDC → Google Cloud Interconnect),避免公网 443 被限速。
-
事务与一致性
- 拆块后必须 关闭外键检查(SET foreign_key_checks=0)并 按拓扑序导入;
- 使用 pt-fifo-split 保证 无锁;
- 导入完成后 一次性开启外键 并 pt-table-checksum 校验。
-
费用控制
- 163 840 次 Class A 请求 ≈ 160 美元,批量 Compose 成 1 GB 逻辑块 可减少 90% 请求费;
- 临时提升 SSD 容量 至 5 TB,导入后 立即缩容(仅收取 1 h 费用),节省 70% 存储。
答案
Step 0 前置检查
- 确认目标实例 版本、字符集、sql_mode 与源库一致;
- 创建 专用服务账号(cloudsql-importer@project.iam),绑定 roles/cloudsql.admin、roles/storage.objectViewer;
- 在 VPC-SC 边界 内创建 私有池,防止数据出境。
Step 1 拆块(以 MySQL 为例)
# 源库 10 TB 单表,主键 bigint
mkdir -p /data/split
mysql -h<source> -e "SELECT MIN(id),MAX(id) FROM bigtable;"
# 假设 1~50 000 000 000
split_size=$((64*1024*1024))
row_est=$((split_size/avg_row_len)) # 约 800 000 行
seq 1 $row_est 50 000 000 000 | \
xargs -P 32 -I {} sh -c "
mysql -h<source> --quick --silent \
-e 'SELECT * FROM bigtable WHERE id>={} AND id<{}+$row_est' \
| gzip > /data/split/shard_$(printf %05d {}).csv.gz
"
gsutil -m rsync -r /data/split gs://prod-import/shard/
Step 2 并行导入
# 生成 import 脚本
for f in $(gsutil ls gs://prod-import/shard/); do
echo "gcloud sql import csv prod-instance $f \
--database=prod \
--table=bigtable \
--async \
--quiet"
done > import_jobs.sh
# 32 并发
cat import_jobs.sh | xargs -P 32 -I {} sh -c {}
# 等待全部完成
gcloud sql operations list --instance=prod-instance --pending
Step 3 后置校验
- pt-table-checksum 校验主从一致;
- ANALYZE TABLE 更新统计信息;
- 开启外键、打开 binlog、降配磁盘。
Step 4 回滚预案
- 导入前 创建磁盘快照(秒级);
- 任何一块失败,单文件重试 3 次后 整体回滚快照;
- 通过 Cloud Monitoring 设置 disk/write_bytes >400 MB/s 持续 5 min 告警,防止磁盘打满。
拓展思考
-
如果源库在 阿里云 PolarDB MySQL 8.0,能否用 DTS 一键迁移?
答:DTS 仅支持到 Google Cloud VMware Engine,不能直接进 Cloud SQL;需 先全量 DTS 到 GCE 中转,再按上述拆块方案导入,耗时增加 6 h,但 网络费用降低 40%。 -
10 TB 数据 含敏感字段(手机号、身份证),国内合规要求?
答:- 拆块前在 源端完成脱敏(正则替换 + 国密 SM4 加密);
- 使用 Cloud KMS 中国分区(asia-east1)CMEK 加密 GCS 对象;
- 导入完成后 立即删除 GCS 中间文件,并 启用 Bucket 日志 留存 180 天备审。
-
若业务要求 导入过程只读窗口 <10 min,如何做到?
答:- 采用 双写方案:源库 打开 binlog,Debezium 实时解析 → Pub/Sub → Dataflow → Cloud SQL;
- 全量 10 TB 拆块导入完成后,增量追平 即可 切换流量,只读窗口 = 增量追平时间 <10 min。