|
@@ -66,7 +66,9 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
private BinlogFormat[] supportBinlogFormats; // 支持的binlogFormat,如果设置会执行强校验
|
|
|
private BinlogImage[] supportBinlogImages; // 支持的binlogImage,如果设置会执行强校验
|
|
|
|
|
|
- // 心跳检查
|
|
|
+ // update by yishun.chen,特殊异常处理参数
|
|
|
+ private int dumpErrorCount = 0; // binlogDump失败异常计数
|
|
|
+ private int dumpErrorCountThreshold = 3; // binlogDump失败异常计数阀值
|
|
|
|
|
|
protected ErosaConnection buildErosaConnection() {
|
|
|
return buildMysqlConnection(this.runningInfo);
|
|
@@ -322,12 +324,12 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
}
|
|
|
return startPosition;
|
|
|
}
|
|
|
-
|
|
|
- protected EntryPosition findEndPosition(ErosaConnection connection) throws IOException {
|
|
|
- MysqlConnection mysqlConnection = (MysqlConnection) connection;
|
|
|
- EntryPosition endPosition = findEndPosition(mysqlConnection);
|
|
|
- return endPosition;
|
|
|
- }
|
|
|
+
|
|
|
+ protected EntryPosition findEndPosition(ErosaConnection connection) throws IOException {
|
|
|
+ MysqlConnection mysqlConnection = (MysqlConnection) connection;
|
|
|
+ EntryPosition endPosition = findEndPosition(mysqlConnection);
|
|
|
+ return endPosition;
|
|
|
+ }
|
|
|
|
|
|
protected EntryPosition findStartPositionInternal(ErosaConnection connection) {
|
|
|
MysqlConnection mysqlConnection = (MysqlConnection) connection;
|
|
@@ -389,6 +391,24 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
}
|
|
|
} else {
|
|
|
if (logPosition.getIdentity().getSourceAddress().equals(mysqlConnection.getConnector().getAddress())) {
|
|
|
+ if (dumpErrorCountThreshold >= 0 && dumpErrorCount > dumpErrorCountThreshold) {
|
|
|
+ // binlog定位位点失败,可能有两个原因:
|
|
|
+ // 1. binlog位点被删除
|
|
|
+ // 2.vip模式的mysql,发生了主备切换,判断一下serverId是否变化,针对这种模式可以发起一次基于时间戳查找合适的binlog位点
|
|
|
+ boolean case2 = standbyInfo == null && logPosition.getPostion().getServerId() != null
|
|
|
+ && !logPosition.getPostion().getServerId().equals(findServerId(mysqlConnection));
|
|
|
+ if (case2) {
|
|
|
+ long timestamp = logPosition.getPostion().getTimestamp();
|
|
|
+ long newStartTimestamp = timestamp - fallbackIntervalInSeconds * 1000;
|
|
|
+ logger.warn("prepare to find start position by last position {}:{}:{}", new Object[] { "", "",
|
|
|
+ logPosition.getPostion().getTimestamp() });
|
|
|
+ EntryPosition findPosition = findByStartTimeStamp(mysqlConnection, newStartTimestamp);
|
|
|
+ // 重新置为一下
|
|
|
+ dumpErrorCount = 0;
|
|
|
+ return findPosition;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 其余情况
|
|
|
logger.warn("prepare to find start position just last position");
|
|
|
return logPosition.getPostion();
|
|
|
} else {
|
|
@@ -431,7 +451,7 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
}
|
|
|
} catch (Exception e) {
|
|
|
// 上一次记录的poistion可能为一条update/insert/delete变更事件,直接进行dump的话,会缺少tableMap事件,导致tableId未进行解析
|
|
|
- processError(e, lastPosition, entryPosition.getJournalName(), entryPosition.getPosition());
|
|
|
+ processSinkError(e, lastPosition, entryPosition.getJournalName(), entryPosition.getPosition());
|
|
|
reDump.set(true);
|
|
|
return false;
|
|
|
}
|
|
@@ -465,7 +485,7 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
|
|
|
lastPosition = buildLastPosition(entry);
|
|
|
} catch (Exception e) {
|
|
|
- processError(e, lastPosition, entryPosition.getJournalName(), entryPosition.getPosition());
|
|
|
+ processSinkError(e, lastPosition, entryPosition.getJournalName(), entryPosition.getPosition());
|
|
|
return false;
|
|
|
}
|
|
|
|
|
@@ -545,6 +565,22 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
return null;
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 查询当前db的serverId信息
|
|
|
+ */
|
|
|
+ private Long findServerId(MysqlConnection mysqlConnection) {
|
|
|
+ try {
|
|
|
+ ResultSetPacket packet = mysqlConnection.query("show variables like 'server_id'");
|
|
|
+ List<String> fields = packet.getFieldValues();
|
|
|
+ if (CollectionUtils.isEmpty(fields)) {
|
|
|
+ throw new CanalParseException("command : show variables like 'server_id' has an error! pls check. you need (at least one of) the SUPER,REPLICATION CLIENT privilege(s) for this operation");
|
|
|
+ }
|
|
|
+ return Long.valueOf(fields.get(1));
|
|
|
+ } catch (IOException e) {
|
|
|
+ throw new CanalParseException("command : show variables like 'server_id' has an error!", e);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 查询当前的binlog位置
|
|
|
*/
|
|
@@ -686,8 +722,8 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
}
|
|
|
|
|
|
lastPosition = buildLastPosition(entry);
|
|
|
- } catch (Exception e) {
|
|
|
- processError(e, lastPosition, searchBinlogFile, 4L);
|
|
|
+ } catch (Throwable e) {
|
|
|
+ processSinkError(e, lastPosition, searchBinlogFile, 4L);
|
|
|
}
|
|
|
|
|
|
return running;
|
|
@@ -705,6 +741,19 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ @Override
|
|
|
+ protected void processDumpError(Throwable e) {
|
|
|
+ if (e instanceof IOException) {
|
|
|
+ String message = e.getMessage();
|
|
|
+ if (StringUtils.contains(message, "errno = 1236")) {
|
|
|
+ // 1236 errorCode代表ER_MASTER_FATAL_ERROR_READING_BINLOG
|
|
|
+ dumpErrorCount++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ super.processDumpError(e);
|
|
|
+ }
|
|
|
+
|
|
|
public void setSupportBinlogFormats(String formatStrs) {
|
|
|
String[] formats = StringUtils.split(formatStrs, ',');
|
|
|
if (formats != null) {
|
|
@@ -788,4 +837,9 @@ public class MysqlEventParser extends AbstractMysqlEventParser implements CanalE
|
|
|
public void setHaController(CanalHAController haController) {
|
|
|
this.haController = haController;
|
|
|
}
|
|
|
+
|
|
|
+ public void setDumpErrorCountThreshold(int dumpErrorCountThreshold) {
|
|
|
+ this.dumpErrorCountThreshold = dumpErrorCountThreshold;
|
|
|
+ }
|
|
|
+
|
|
|
}
|