如何将 10 TB 拆分为 64 MB 块并并行导入?

解读

面试官真正想考察的是:

  1. Cloud SQL 单实例 64 TB 上限、单表 16 TB、单事务 6 h 超时 等硬性边界的理解;
  2. 能否把“大文件拆块”与“Cloud SQL 并行导入”两条技术线无缝衔接,兼顾 网络带宽、IOPS、锁竞争、GTID 一致性、费用
  3. 是否具备 国内合规 意识(跨境传输、敏感数据脱敏、公网/私网选型);
  4. 能否给出 可落地的 SOP,包括失败重试、幂等、监控告警、回滚方案。

一句话:不是“会拆文件”,而是“让 10 TB 数据在 国内 Cloud SQL 高可用实例24 h 内安全落地,且业务只读窗口 <30 min”。

知识点

  1. Cloud SQL 导入路径

    • 内网:Cloud Storage → 私网 VPC Service Controls → Cloud SQL 实例(Private IP)
    • 外网:Cloud SQL Auth Proxy + SSL 客户端证书(国内需备案域名)
      两者均支持 并行导入(parallel=threads),但 单文件仍串行,必须预先拆块。
  2. 拆块原则

    • 行级拆分:使用 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 上限。
  3. 并行导入上限

    • 单实例最大 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)。
  4. 国内网络优化

    • 选择 北京/上海/深圳 RegionPremium 层级(国内三大运营商直连 Google 边缘 POP);
    • 开通 Cloud CDN 回源私有云 仅对 GCS 生效,可节省 15% 跨境流量费;
    • 若源数据在阿里云 OSS,可先用 gsutil rsync -m专线 DC(阿里云高速通道 → 第三方 IDC → Google Cloud Interconnect),避免公网 443 被限速。
  5. 事务与一致性

    • 拆块后必须 关闭外键检查(SET foreign_key_checks=0)并 按拓扑序导入
    • 使用 pt-fifo-split 保证 无锁
    • 导入完成后 一次性开启外键pt-table-checksum 校验。
  6. 费用控制

    • 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 告警,防止磁盘打满。

拓展思考

  1. 如果源库在 阿里云 PolarDB MySQL 8.0,能否用 DTS 一键迁移
    答:DTS 仅支持到 Google Cloud VMware Engine,不能直接进 Cloud SQL;需 先全量 DTS 到 GCE 中转,再按上述拆块方案导入,耗时增加 6 h,但 网络费用降低 40%

  2. 10 TB 数据 含敏感字段(手机号、身份证),国内合规要求?
    答:

    • 拆块前在 源端完成脱敏(正则替换 + 国密 SM4 加密);
    • 使用 Cloud KMS 中国分区(asia-east1)CMEK 加密 GCS 对象;
    • 导入完成后 立即删除 GCS 中间文件,并 启用 Bucket 日志 留存 180 天备审。
  3. 若业务要求 导入过程只读窗口 <10 min,如何做到?
    答:

    • 采用 双写方案:源库 打开 binlogDebezium 实时解析 → Pub/SubDataflowCloud SQL
    • 全量 10 TB 拆块导入完成后,增量追平 即可 切换流量只读窗口 = 增量追平时间 <10 min