Streamsets监听binlog 实现数据同步
实时同步原有数据库到新的数据库(原有字段可以不完全匹配)
简要说明:
监听binlog , 根据配置文件 js处理所有列对应到新表使用的列, 处理额外需要处理的特殊列,例如 关联id ,根据mapping 找出 等. 处理介绍
通用流程 查询 新表mapping id 关系 如存在更新 不存在先插入mapping id 后执行同步
实现后的大体截图效果
1、数据迁移
前提
自增id 全部 对应 mapping_表名
例如:
create table mapping_table_name
(
id int auto_increment
primary key,
old_id int null,
brand_id int null
);
create index brand_id
on mapping_table_name (brand_id);
create index old_id
on mapping_table_name (old_id);
1.1 全量操作 步骤 :
-
查询全字段 sql
-
按照所有列查询原表数据:
1. select id as old_id,
同步表的所有列 ,
1 AS brand_id,
0 AS new_id,
(@rowNum := @rowNum + 1) AS rowNo
FROM db1.tableName m,
(SELECT (@rowNum := 0)) b
ORDER BY rowNo ASC
- 所有列 中 原表无法查询数据 需要单列出,在pipeline中额外处理. 例如 userid 根据 mapping表查询
1.2 增量操作步骤 :
-
检测binlog serverid 最好 区别开来 长时间不运行需要reset origin & start 启动
-
增加映射关系, 配置表字段 说明
source_table : 监听表 op_db: 需要写入的数据库 op_table: 需要写入的 数据表 mapping_table_name: id映射表 init_columns: 需要额外处理或初始化的字段 name : 字段名 prop: 1. value 值 直接初始化值 "prop": { "value": "1" } 2. 用原value中 “id” 数据库字段 初始化值 "prop": { "value": "id", "read_old": 1 }
js处理
function initConfig() {
//var config_str = '[{"source_table":"table1_old","op_db":"db1","op_table":"table1_new","mapping_table_name":"mapping_table1_new","init_columns":[{"name":"brand_id","prop":{"value":"1"}},{"name":"old_id","prop":{"value":"id","read_old":1}},{"name":"new_id","prop":{"value":"0"}}]}]';
var config_str = '${dc_config}';
var config_obj_arr = JSON.parse(config_str);
var config_obj_map ={};
for(var j=0;j<config_obj_arr.length;j++) {
var key = config_obj_arr[j].source_table;
config_obj_map[key] = config_obj_arr[j];
}
return config_obj_map;
}
function convertToValue(record) {
if(record.value['Type'] == "DELETE") {
for(var key in record.value['OldData']) {
var value = record.value['OldData'][key];
record.value[key] = value;
}
} else {
for(var key in record.value['Data']) {
var value = record.value['Data'][key];
record.value[key] = value;
}
}
}
function setTable(record, config_table) {
record.value.op_db = config_table.op_db;
record.value.op_table = config_table.op_table;
record.value.mapping_table_name = config_table.mapping_table_name;
}
function handler(record) {
var config_map = initConfig();
var source_table = record.value['Table'];
if(source_table) {
var config_table = config_map[source_table];
if(config_table) {
record.value.dc_handle = 1;
setTable(record,config_table);
convertToValue(record);
if(config_table.init_columns) {
var initColumns = sdc.createMap(true);
for(var k = 0 ; k< config_table.init_columns.length; k++) {
var init_col = config_table.init_columns[k];
if(init_col.prop.read_old) {
initColumns[init_col.name] = 1;
record.value[init_col.name] = record.value[init_col.prop.value];
} else {
initColumns[init_col.name] = 1;
record.value[init_col.name] = init_col.prop.value;
}
}
record.value.dc_columns = initColumns;
}
}
}
}
// Sample JavaScript code
var records = sdc.records;
for(var i = 0; i < records.length; i++) {
try {
sdc.log.info("###1"+records[i].value);
sdc.log.info("###2"+records[i].sdcRecord.get("/Data"));
sdc.log.info("###2"+records[i].sdcRecord.get("/Data"));
sdc.log.info("###2"+records[i].sdcRecord);
handler(records[i]);
//JSON.stringify(jsonObject )
sdc.log.info("###2"+JSON.stringify(records[i]));
// Write record to processor output
sdc.output.write(records[i]);
} catch (e) {
// Send record to error
sdc.error.write(records[i], e);
}
}
例如:
[
{
"source_table": "table1_old",
"op_db": "db1",
"op_table": "table1_new",
"mapping_table_name": "mapping_table1_new",
"init_columns": [
{
"name": "brand_id",
"prop": {
"value": "1"
}
},
{
"name": "old_id",
"prop": {
"value": "id",
"read_old": 1
}
},
{
"name": "new_id",
"prop": {
"value": "0"
}
}
]
}
]
- 替换表中间额外处理元素 , 与 全量 步骤3 相同处理 .