kafka消息无法正常消费,且报异常:java.lang.IllegalArgumentException: Path must not end with / character

背景

昨天同事在重启消费者进程后,导致后台消息无法正常消费,看日志,有报数据库的异常:org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection;另外偶尔还有kafka异常:java.lang.IllegalArgumentException: Path must not end with / character。同时,发现一个奇怪的地方,有个info级别的日志,说明spring关闭了bean的销毁方法:INFO [main] org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(444)。同时看zookeeper上的消费者,发现有部分topic下的消费者没有注册。

在一番折腾后,将代码回滚到上一版本,临时解决了问题。

总结

今天重点分析了下日志,发现引起问题有如下几个原因:

1、目前消费者程序中注册消费者都是在bean初始化时进行的,当创建stream时,因为有个新建的consumer对应的topic名为空,导致创建抛出了异常。该异常信息为java.lang.IllegalArgumentException: Path must not end with / character。但因为该信息被spring容器吃掉了,所以在日志中没有任何体现。spring发现异常后,会调用DefaultSingletonBeanRegistry.destroySingletons来关闭bean实例。在配置文件里,数据库连接池、以及部分consumer会在消费bean实例时,释放资源。

下面代码,因为topic名为空,所以抛出了异常Path must not end with / character:

Map<String, List<KafkaStream<byte[], byte[]>>> topicMessageStreams = connector.createMessageStreams(topics);
spring容器会吃掉初始化方法里的异常,同时销毁bean实例。因为数据库连接池、部分consumer会在销毁时关闭资源,所以报出无法取到jdbc连接异常以及zookeeper上的消费者没有正常注册:

连接池销毁:

    <bean id="writeDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
        destroy-method="close">

消费者被销毁:

public class RefundApproveMessageReceiver implements InitializingBean, DisposableBean {
	@Override
    public void destroy() throws Exception {
        if (connector != null) {
        	connector.shutdown();
        }
        if (threadPool != null) {
        	threadPool.shutdown();
        }
    }
}

2、注册了新的consumer后,需要发起rebalance,但因为topic名为空,所以拼接的zk节点路径肯定是以"/"字符结尾了,所以在日志里看到了异常:java.lang.IllegalArgumentException: Path must not end with / character。

3、spring的初始化方法里要谨慎处理异常,否则spring吃掉异常后,会对实例进行关闭,可能导致有些资源无法正常使用。


你可能感兴趣的:(java,spring,zookeeper,kafka)