环境信息
canal version 1.1.2 mysql version 5.7
问题描述
并行解析模式下,解析过程中,如果在ringbuffer中顺序靠前的binlog解析失败,靠后的binlog解析成功,则这部分未正常解析的数据会被直接丢弃(此bug会导致靠后的binlog能正常通过sequencebarrier,并被下游消费后记录offset,重试时会读到这个offset,从而跳过了那部分最初解析失败的数据)
原因分析: 并行解析模块用到了disruptor,其中onevent方法中的算子执行出现异常时,BatchEventProcessor会nextSequence++,wookpool模式下会将processedSequence置为true。这中情况下,如同一batch中有部分数据可以被正确解析(在ringbuffer中相对解析失败的数据顺序靠后),则会正常通过sequencebarrier,被下游处理后并ack,最终导致这部分解析失败的数据丢失(个人认为不应该直接丢弃,问题会被覆盖,且串行解析版本这类解析失败的情况均会hang在这里)
BatchEventProcessor和WookProcessor部分代码如下: BatchEventProcessor.java
private void processEvents() { T event = null; long nextSequence = sequence.get() + 1L;
while (true)
{
try
{
…………………………
while (nextSequence <= availableSequence)
{
event = dataProvider.get(nextSequence);
eventHandler.onEvent(event, nextSequence, nextSequence == availableSequence);
nextSequence++;
}
…………………………
}
catch (final Throwable ex)
{
exceptionHandler.handleEventException(ex, nextSequence, event);
sequence.set(nextSequence);
###重点看这里###
nextSequence++;
}
}
WorkProcessor.java
public void run() { if (!running.compareAndSet(false, true)) { throw new IllegalStateException("Thread is already running"); } ……………………………… { try { …………………… } catch (final Throwable ex) { // handle, mark as processed, unless the exception handler threw an exception exceptionHandler.handleEventException(ex, nextSequence, event); ###重点看这里### processedSequence = true; } }
问题重现
我在1.1.2版本调试上图的NPE BUG时发现了这个问题(后来发现1.1.3版本已经修复了NPE)。在1.1.2版本,当canal收集延迟时,连续改表加字段两次可触发上图中的NPE异常。
NPE发生后 预期行为:对于meta过期导致无法解析的binlog,应该一直再重试,永远无法解析成功 实际行为:串行解析模式下如预期;并行解析模式下,重试居然后跳过了那段无法解析的binlog
后来调试发现,同一个ringbuffer中中前半部数据分会因为NPE无法解析,后半部分数据能够正确解析,正如这个issue最开始的原因分析,后半部分数据通过了sequencebarrier,并被成功ack,并记录offset到zk上,重试时读到了zk上的offset,从而跳过了这部分binlog。
修复这个问题的pr如下: 只需要在默认的exceptionHandler中立刻抛出这个异常即可
原提问者GitHub用户
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。