订阅更新

DataWorks数据集成同步速度慢——并发、批量、网络怎么调?

数据采集手册 第 18 题 约 10 分钟读完

本文目录
  1. 先说结论
  2. 业务场景:亿级表同步从6小时降到45分钟
  3. 方案一:channel并发数调优
  4. 方案二:splitPk切片均匀性
  5. 方案三:写端batchSize与事务
  6. 优化前后对比
  7. 面试高频追问
  8. 实战踩坑:跨VPC同步带宽被打满影响业务
  9. 总结

先说结论

DataX慢的三类根因:① 读端瓶颈(源库扫表慢/网络IO低);② 写端瓶颈(目标库写入限速);③ 框架瓶颈(channel数不够/序列化开销)。

调优四板斧:① channel并发;② splitPk切片均匀;③ 单通道batchSize;④ 跨VPC网络配置。

万能经验值:简单字段、同VPC:channel=16、batchSize=2048;跨VPC:channel=8、batchSize=1024、开压缩。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

DataWorks是阿里云数仓团队几乎绕不开的工具,数据集成(底层就是DataX)是最常用的数据搬运模块。"同步慢"是上线后最容易撞到的坑——配置默认跑的话,同步一张亿级表动辄几小时。这道题面试官想看的不是"调并发"这种表面答案,而是你懂不懂DataX的工作原理、能不能结合读写两端综合优化。

业务场景:亿级表同步从6小时降到45分钟

有个日调度任务,同步一张1.2亿行的MySQL订单表到Hologres,默认配置下每天跑6小时,还经常卡在某个分片超时失败。一轮调优后降到45分钟稳定跑完,调了四个地方:splitPk改成有序主键、channel从4加到16、writer batchSize从1024加到4096、跨VPC开了压缩。

优化前后对比:
                        优化前           优化后
  数据量                 1.2亿行          1.2亿行
  耗时                   6h              45min
  吞吐                   5500行/s         44000行/s  (8倍)
  并发channel数          4               16
  splitPk               update_time      id(自增主键)
  writer batch          1024            4096
  compress              无              lz4
  源库IO压力             低峰期10%        低峰期35%(可接受)

方案一:channel并发数调优

channel是DataX的并行度,对应spawn多少个reader/writer线程对。默认1个,大数据量场景必须调大。但不是越大越好——看源库能承受多少并发查询、目标库能吃多少并发写入。

{
  "job": {
    "setting": {
      "speed": {
        "channel": 16,             // 并发数(最关键)
        "byte": 10485760,           // 单channel限速10MB/s保护源库
        "record": 10000            // 单channel限速1万行/s
      },
      "errorLimit": {
        "record": 0,                // 错误记录数限制
        "percentage": 0.02          // 错误率阈值
      }
    },
    "content": [{
      "reader": { "name": "mysqlreader", ... },
      "writer": { "name": "hologreswriter", ... }
    }]
  }
}
 
// 怎么定channel数?
//   - 源库: 走从库,channel ≤ 32(不能把从库打满)
//   - 目标库: Hologres/ADB高并发,channel 16-32
//     MySQL/PG低并发,channel 4-8
//   - DataWorks资源组: 公共资源组默认最多16,独享资源组可到64
//   - 单表数据量: <100万行用4,1亿行用16-32

方案二:splitPk切片均匀性

DataX按splitPk把表切成N份(N≈channel数),每个reader负责一份。如果splitPk不均匀(比如按create_time切,但数据时间分布严重倾斜),就会有几个reader跑几分钟完事、几个reader跑几小时——木桶效应。

{
  "reader": {
    "name": "mysqlreader",
    "parameter": {
      "username": "xxx",
      "connection": [{
        "jdbcUrl": ["jdbc:mysql://slave:3306/db"],
        "table": ["orders"]
      }],
      // ✓ splitPk选择原则:
      //   1) 分布均匀(自增主键id最好)
      //   2) 有索引(否则切片query全表扫)
      //   3) 整数或日期(支持范围切分)
      "splitPk": "id",
      "where": "create_time >= '${bizdate}' AND create_time < '${nextdate}'",
      "column": ["id", "user_id", "amount", ...]
      // 注意: 不用 column: ["*"],
      //       显式列出字段避免新增列时作业失败
    }
  }
}
 
// ❌ 反面例子: 按create_time切
// "splitPk": "create_time"
// 大促期间订单在2-3点高峰集中,某些小时的reader数据量是其他的10倍
// 结果整个作业被最慢的reader拖住
 
// 手动切片(终极武器)
// 放弃splitPk,直接在querySql里写死范围:
// ["SELECT * FROM orders WHERE id BETWEEN 0 AND 10000000",
//  "SELECT * FROM orders WHERE id BETWEEN 10000001 AND 20000000", ...]

关键点:自增主键是splitPk的最佳选择。没有自增ID的表可以考虑加一个shard_id列(user_id % 32),或者分两阶段同步(先ODS用并行,DWD层统一重写)。

方案三:写端batchSize与事务

Writer端的batchSize决定了多少条记录攒一个batch commit到目标库。太小:频繁提交事务开销大;太大:单个事务过长可能锁表或超时。

{
  "writer": {
    "name": "hologreswriter",
    "parameter": {
      "username": "xxx",
      "endpoint": "xxx.hologres.aliyuncs.com:80",
      "database": "xxx",
      "table": "dwd_orders",
      "writeMode": "insertorignore",   // insertorignore/update/replace
      "writeBatchSize": 4096,           // 批大小(默认1024)
      "writeBatchByteSize": 8388608,    // 批字节上限8MB
      "numThread": 4,                   // 单channel内部线程数
      "disableCopyWrite": false         // Hologres用COPY高速写入
    }
  }
}
 
// 调优经验(按目标库分):
// Hologres: batchSize=4096-8192, 开copy write, throughput 3万+行/s/channel
// MaxCompute: tunnel批量写, batchSize不太关键
// MySQL:   batchSize=1024-2048, 再大容易锁表
// ES:      batchSize=1000-2000(文档较大), bulk API
// HDFS:    写Parquet时 batchSize=10000+, 减少文件数

优化前后对比

参数默认值优化值提升来源
channel416并发度×4
splitPk无/update_timeid(自增)切片均匀,消除木桶
writeBatchSize10244096减少事务提交4倍
compression无lz4跨VPC带宽减半
column*显式列表减少网络传输30%

面试高频追问

追问一:DataWorks的公共资源组和独享资源组怎么选?

三个维度决策:① 吞吐——公共资源组并发上限低(16),独享可以到64+;② 稳定性——公共资源可能被其他租户抢占,独享完全独立;③ 成本——独享按小时付费,固定成本高。经验:T+1核心同步用独享(稳定且能调高并发),T+1非核心和测试用公共。生产关键作业配失败重跑+资源组降级(独享失败时退化到公共)。

追问二:DataX读MySQL用JDBC,怎么避免把MySQL连接池打满?

DataX每个channel建一个JDBC连接,16个channel就是16个连接。MySQL默认max_connections是151,普通业务可能只留30-50给数据同步,16并发就占了一大半。对策:① 走只读从库,从库max_connections设大(比如500);② 在DataX侧用连接池复用(configure session initSql="SET session xxx=yyy");③ 错峰调度,避免多个大作业同时跑。独立DBA环境的最稳做法是给数据同步专门建账号,配独立max_user_connections。

追问三:大表DataX同步经常失败重试,怎么做增量/断点续传?

DataX本身不支持断点续传(无状态),每次失败都从头开始。解决方案:① 按日期/ID范围切成多个子作业,失败只重跑子作业;② 用DataWorks的失败重试策略(最多3次,间隔15分钟);③ 极大表(10亿+)用分区级调度,每个分区一个DataX作业,配独立checkpoint表。根本上说DataX不是为流式续传设计的,超大表场景应该考虑Flink CDC替代。

实战踩坑:跨VPC同步带宽被打满影响业务

有次跨VPC(MySQL在VPC-A、Hologres在VPC-B)的DataX作业,channel开到32、没开压缩,结果把VPC对等连接的带宽打满,VPC-A里其他业务的跨网调用都超时。SRE查出来是数据同步占了80%+带宽。后来限流+开压缩后带宽占用降到20%。

// 跨VPC必做的三件事
{
  "setting": {
    "speed": {
      "channel": 8,                     // 跨VPC降到8
      "byte": 5242880                    // 单channel限速5MB/s
      // 总带宽上限 = 8 × 5MB/s = 40MB/s (320Mbps)
      // VPC对等通常有1Gbps,留60%+给业务
    }
  },
  "content": [{
    "reader": {
      "parameter": {
        "connection": [{
          // 开启客户端压缩
          "jdbcUrl": ["jdbc:mysql://...?useCompression=true&useSSL=false"]
        }]
      }
    },
    "writer": {
      "parameter": {
        "compression": "lz4"           // 传输压缩
      }
    }
  }]
}
 
// 进阶: 如果同一VPC对等有多个同步作业
// DataWorks独享资源组 → 在VPC-A内接读MySQL
// 然后走同区域内网到VPC-B(避免走公网,带宽更大)

解决方案:跨VPC作业必须限流+压缩+错峰。带宽是共享资源,数据同步再快也不能影响业务。后来把这套规则写进《DataWorks上线规范》,所有跨VPC作业发布前强制review。

总结

DataWorks数据集成调优是个系统工程:读端切片均匀(splitPk)、框架并发合理(channel)、写端批量攒批(batchSize)、网络传输压缩(跨VPC必开)。调优逻辑是"找瓶颈再对症下药"——读慢还是写慢还是框架慢?不同瓶颈的解法完全不同。面试时讲清楚"DataX原理+瓶颈定位+参数意义",比背参数表分高得多。

下一篇聊架构选型大题:离线采集和实时采集要不要分开,同一份业务数据的Lambda取舍

你们公司DataWorks跑得快吗?最大的作业优化到多少吞吐?评论区聊聊~

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

刷题进度保存在当前浏览器