数据库的binlog也有删除策略,不可能永久保存所有的binlog。如何迁移binlog已经不存在的存量数据? otter针对这种场景需求设计了自由门模块。详见otter中的自由门说明 。 自由门的原理如下: a. 基于otter系统表retl_buffer,插入特定的数据,包含需要同步的表名,pk信息。 b. otter系统感知后会根据表名和pk提取对应的数据(整行记录),和正常的增量同步一起同步到目标库。 原先需要在每一个迁移的库所在实例建立retl.retl_buffer库表(存量数据迁移控制表)。当迁移的库比较多时,在多个实例上面分别建立retl库,不利于统一控制,同时给库表元数据管理带来一定的难度。为了后续DRC的统一快捷运维和减少运维成本,我们对自由门进行集中控制(不同实例上的数据迁移由同一个retl.retl_buffer库表控制)。通过在retl_buffer表上增加channel、pipeline两个字段,区分retl.retl_buffer库表中的数据属于不同的库表。然后在SelectTask阶段对数据进行分批整理 ,每批的管道改成同步管道信息。(统一控制相对单独控制存在一个风险点:如果同步的这批存量数据在Extract阶段后和Load阶段前存在源库数据对应记录的修改,同时修改的增量binlog又比存量同步的数据同步更快,存在数据老数据覆盖新数据的风险,不过这种场景概率极小)
//如果数据来自RETL库RETL_BUFFER表,将数据分批,每批的管道改成同步管道信息
if (StringUtils.equalsIgnoreCase(RETL_BUFFER, pipeline.getPairs().get(0).getSource().getName())
&& StringUtils.equalsIgnoreCase(RETL, pipeline.getPairs().get(0).getSource().getNamespace())) {
Long lastPipeLineId = null;
Long lastChannelId = null;
for (EventData data : eventData) {
// 获取每一条数据对应的pipeline
EventColumn pipelineColumn = getMatchColumn(data.getColumns(), PIPELINE_ID);
// 获取每一条数据对应的channelID
EventColumn channelColumn = getMatchColumn(data.getColumns(), CHANNEL_ID);
if(pipelineColumn == null || channelColumn == null){
logger.warn("data from RETL.RETL_BUFFER has no PIPELINE_ID OR CHANNEL_ID,the getKeys are {}",new Object[]{data.getKeys().toArray()});
continue;
}
Long pipeLineId = Long.valueOf(pipelineColumn.getColumnValue());
Long channelId = Long.valueOf(channelColumn.getColumnValue());
if (pipeLineId == null || channelId == null) {
continue;
}
//第一条数据,不发送
if (lastPipeLineId == null && lastChannelId == null) {
lastPipeLineId = pipeLineId;
lastChannelId = channelId;
rowBatch.merge(data);
continue;
}
//数据管道或通道有变化时,每个管道号数据作为一批发送
if (pipeLineId != lastPipeLineId || channelId != lastChannelId) {
// 构造唯一标识
Identity identity = new Identity();
identity.setChannelId(lastChannelId);
identity.setPipelineId(lastPipeLineId);
identity.setProcessId(etlEventData.getProcessId());
rowBatch.setIdentity(identity);
long nextNodeId = etlEventData.getNextNid();
List pipeKeys = rowDataPipeDelegate.put(new DbBatch(rowBatch),
nextNodeId);
etlEventData.setDesc(pipeKeys);
etlEventData.setNumber((long) rowBatch.getDatas().size());
etlEventData.setFirstTime(startTime); // 使用原始数据的第一条
etlEventData.setBatchId(message.getId());
if (profiling) {
Long profilingEndTime = System.currentTimeMillis();
stageAggregationCollector.push(pipelineId, StageType.SELECT,
new AggregationItem(profilingStartTime, profilingEndTime));
}
arbitrateEventService.selectEvent().single(etlEventData);
rowBatch = new RowBatch();
}
lastPipeLineId = pipeLineId;
lastChannelId = channelId;
rowBatch.merge(data);
}
if(rowBatch!=null && rowBatch.getDatas() != null && rowBatch.getDatas().size()>0){
// 构造唯一标识
Identity identity = new Identity();
identity.setChannelId(lastChannelId);
identity.setPipelineId(lastPipeLineId);
identity.setProcessId(etlEventData.getProcessId());
rowBatch.setIdentity(identity);
long nextNodeId = etlEventData.getNextNid();
List pipeKeys = rowDataPipeDelegate.put(new DbBatch(rowBatch),
nextNodeId);
etlEventData.setDesc(pipeKeys);
etlEventData.setNumber((long) rowBatch.getDatas().size());
etlEventData.setFirstTime(startTime); // 使用原始数据的第一条
etlEventData.setBatchId(message.getId());
if (profiling) {
Long profilingEndTime = System.currentTimeMillis();
stageAggregationCollector.push(pipelineId, StageType.SELECT,
new AggregationItem(profilingStartTime, profilingEndTime));
}
arbitrateEventService.selectEvent().single(etlEventData);
}
}
在平时工作中,难免会遇到把 XML 作为数据存储格式。面对目前种类繁多的解决方案,哪个最适合我们呢?在这篇文章中,我对这四种主流方案做一个不完全评测,仅仅针对遍历 XML 这块来测试,因为遍历 XML 是工作中使用最多的(至少我认为)。 预 备 测试环境: AMD 毒龙1.4G OC 1.5G、256M DDR333、Windows2000 Server
Netty 3.x的user guide里FrameDecoder的例子,有几个疑问:
1.文档说:FrameDecoder calls decode method with an internally maintained cumulative buffer whenever new data is received.
为什么每次有新数据到达时,都会调用decode方法?
2.Dec
hive> select * from t_test where ds=20150323 limit 2;
OK
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
问题原因: hive堆内存默认为256M
这个问题的解决方法为:
修改/us
Simply do the following:
I. Declare a global variable:
var markersArray = [];
II. Define a function:
function clearOverlays() {
for (var i = 0; i < markersArray.length; i++ )
Quick sort is probably used more widely than any other. It is popular because it is not difficult to implement, works well for a variety of different kinds of input data, and is substantially faster t