OLTP分库分表数据CDC到Doris的架构设计
当将分库分表的OLTP数据通过CDC(Change Data Capture)同步到Apache Doris时,Doris端的表设计需要特别注意。以下是完整的解决方案:
一、Doris分库分表能力解析
Doris本身不采用传统分库分表的概念,而是通过以下两种方式实现数据分布:
- 分区(Partition) :按照日期、地区等维度划分
- 示例:按天分区
PARTITION BY RANGE(dt)
- 示例:按天分区
- 分桶(Bucket) :类似分片,数据水平切分
- 示例:
DISTRIBUTED BY HASH(user_id) BUCKETS 32
- 示例:
二、分库分表源数据同步方案
方案1:合并同步 - 单Doris表整合多源表
适用场景:源表分库分表仅是水平拆分,表结构完全相同
sql
-- Doris建表示例
CREATE TABLE ods_merged (
id BIGINT,
user_id BIGINT,
order_amount DECIMAL(16,2),
dt DATE
)
ENGINE=OLAP
PARTITION BY RANGE(dt) (
PARTITION p202301 VALUES LESS THAN ('2023-02-01'),
PARTITION p202302 VALUES LESS THAN ('2023-03-01')
)
DISTRIBUTED BY HASH(user_id) BUCKETS 32
PROPERTIES (
"replication_num" = "3"
);
CDC配置要点:
- 为每个分表配置单独的CDC作业
- 所有分表数据写入同一Doris表
- 使用Flink SQL的UNION ALL合并流
方案2:分表同步 - 保持分表结构
适用场景:需要保留原始分表结构或分表结构不同
sql
-- 按源分表名建立对应Doris表
CREATE TABLE ods_shard_0 (...) -- 对应源db0.tbl0
CREATE TABLE ods_shard_1 (...) -- 对应源db1.tbl1
CDC配置要点:
- 为每个分表配置独立的CDC到Doris表的管道
- 查询时通过Doris的多表查询功能联合分析
三、关键技术实现
1. 使用Flink CDC Connector
java
// 示例:捕获多个分表合并到Doris
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 源表1
MySQLSource<String> source1 = MySQLSource.<String>builder()
.hostname("host1")
.port(3306)
.databaseList("db0")
.tableList("db0.tbl0")
.username("user")
.password("pass")
.deserializer(new JsonDebeziumDeserializationSchema())
.build();
// 源表2
MySQLSource<String> source2 = MySQLSource.<String>builder()
.hostname("host1")
.port(3306)
.databaseList("db1")
.tableList("db1.tbl1")
.username("user")
.password("pass")
.deserializer(new JsonDebeziumDeserializationSchema())
.build();
// 合并两个源
DataStreamSource<String> stream1 = env.addSource(source1);
DataStreamSource<String> stream2 = env.addSource(source2);
DataStream<String> unionStream = stream1.union(stream2);
// 写入Doris
DorisSink.sink(
DorisSinkOptions.builder()
.setFenodes("fe:8030")
.setUsername("user")
.setPassword("pass")
.setTableIdentifier("db.ods_merged")
.build(),
unionStream
);
2. 处理自增ID冲突
当合并多分表时,需注意自增ID冲突问题:
解决方案:
- 使用复合主键:
PRIMARY KEY (id, shard_id)
- 改造原ID:
新ID = 原ID * 分片数 + 分片编号
- 使用UUID等分布式ID
四、Doris分区与分桶设计建议
-
分区策略:
sql-- 按时间分区是最佳实践 PARTITION BY RANGE(dt) ( PARTITION p202301 VALUES LESS THAN ('2023-02-01'), PARTITION p202302 VALUES LESS THAN ('2023-03-01') )
-
分桶策略:
sql-- 按查询最频繁的字段分桶 DISTRIBUTED BY HASH(user_id) BUCKETS 32 -- 大表建议10-100个bucket -- 小表可减少到3-10个bucket
五、性能优化要点
-
批量导入:
- 设置合适的
batch.size
和interval
参数 - 推荐批量大小50-100MB,间隔10-30秒
- 设置合适的
-
并行度:
sql-- 增加并行导入线程 SET GLOBAL parallel_fragment_exec_instance_num = 16;
-
压缩传输:
properties# 在Doris FE配置中启用压缩 enable_http_compression=true
六、监控与维护
-
监控导入任务:
sqlSHOW ROUTINE LOAD; -- 查看CDC导入任务 SHOW BACKENDS; -- 查看节点状态
-
数据校验:
sql-- 比对源库与Doris数据量 SELECT COUNT(*) FROM olap_table; -- 与源库各分表SUM(COUNT)对比
-
定期维护:
sql-- 自动compaction ADMIN SET FRONTEND CONFIG ("enable_auto_compaction" = "true"); -- 手动compaction COMPACT TABLE tbl_name;
七、典型问题解决方案
问题1:数据倾斜
- 解决方案:调整分桶字段,选择离散度高的列
问题2:同步延迟
- 解决方案:增加Flink任务并行度,优化网络
问题3:DDL变更
- 解决方案:使用Schema Registry管理表结构变更
通过以上设计,可以高效地将分库分表的OLTP数据实时同步到Doris,既保持数据分析性能,又能处理源数据分散的问题。实际实施时需要根据数据量和查询模式调整分区和分桶策略。