[alibaba/canal]1.1.7 Connection reset by peer频繁触发后Server端自动停机

2024-07-22 840 views
1
环境
  • Java 1.8
  • Canal 1.1.7
  • Server 和 Client在同一台机器上
问题描述

Canal Server运行一段时间后,触发“Connection reset by peer”,且客户端重新连接也无法解决问题,直至Canal Server端宕机。重启Canal Server可立即解决问题。

看了很多issue说是处理空闲连接超时,作者和其他同学给的解决方案是:

  1. 做好重试。
  2. 加大空闲连接超时时间。

疑问:

  1. 重试并没起到作用(详见下面的代码)
  2. 为何加大空闲连接超时时间可以解决这个问题?连接如若实际不可用,不是应该缩短空闲连接超时时间,以尽早释放无效连接从而建立新的连接吗?如果加大超时时间可以消掉这个错,为何客户端SDK不直接设置成永不超时,内部消化掉?

Server 端的日志和实际表现上看,当Connection reset by peer触发一段时间后,Server端就自动停机了,Server是不是因为这个错停机,无任何可供排查的日志。

代码案例
public class CanalConsumer {

    private volatile boolean isRunning;
    private volatile boolean isConnected;
    private final CanalConnector connector;

    //...初始化代码

    public synchronized void start() {
        if (isRunning) {
            return;
        }
        this.isRunning = true;
        new Thread(this::run, "canal-consumer").start();
    }

    private void run() {
        while(isRunning) {
            try {
                connect()
                Message message = connector.getWithoutAck(1024);
                long batchId = message.getId();
                List<CanalEntry.Entry> entries = message.getEntries();
                if (batchId != -1 && entries != null && !entries.isEmpty()) {
                    // 消费数据
                }
                connector.ack(batchId);
            } catch(Exception e) {
                // 只要出现Canal客户端异常都会断开连接并在下一次触发重新连接
                if (e instanceof CanalClientException) {
                    try {
                       disconnect()
                    } catch(CanalClientException ex) {
                       log.error("failed", ex);
                    }
                }
            }
        }
    }

   private void connect() {
        if (isConnected) {
            return;
        }
        connector.connect();
        connector.subscribe("xxx");
        isConnected = true;
   }

  private void disconnect() {
        if(!isConnected) {
            return;
        }
        isConnected = false;
        connector.disconnect();
   }

}

回答

1

connector.getWithoutAck(batchSize, 3L, TimeUnit.SECONDS), 建议加个超时时间,如果不加超时时间,你的请求到服务端会一直等待的,等待batchsize的数量才会返回,如果一直没有batchsize,就会出现链接被关闭的情况

6

@chenqi14 Message getWithoutAck(int batchSize)方法,接口上的注释是这样写的:

    /**
     * 不指定 position 获取事件,该方法返回的条件: 尝试拿batchSize条记录,有多少取多少,不会阻塞等待<br/>
     * canal 会记住此 client 最新的position。 <br/>
     * 如果是第一次 fetch,则会从 canal 中保存的最老一条数据开始输出。
     * 
     * @param batchSize
     * @throws CanalClientException
     */
    Message getWithoutAck(int batchSize) throws CanalClientException;
4

你可以线下测试一下,我理解是会一直等待的,否则,不可能出现频繁的Connection reset by peer

0

是一直阻塞的,注释可能有问题

0

不会一直阻塞,getWithoutAck默认会设置timeout=-1,代表不做阻塞

6

Connection reset by peer问题没得到解决与答复。 关于Canal Server进程退出的问题,已经用Systemd监听Server进程退出后重新拉起绕过了。 只要Canal Server重启,Connection reset by peer这个异常一段时间内都不会再报。