如何在Spring Kafka Consumer中跳过损坏的(不可序列化的)消息?

时间:2018-11-15 21:16:16

标签: java apache-kafka spring-kafka

这个问题是关于Spring Kafka的,与Apache Kafka with High Level Consumer: Skip corrupted messages

相关

是否可以配置Spring Kafka使用者以跳过无法读取/处理(损坏)的记录?

我看到一种情况,如果无法反序列化,则消费者将卡在同一记录上。这是消费者抛出的错误。

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of java.time.LocalDate: no long/Long-argument constructor/factory method to deserialize from Number value 

使用者轮询主题,并一直循环打印相同的错误,直到程序被杀死为止。

在具有以下消费者工厂配置的@KafkaListener中,

Map<String, Object> props = new HashMap<>();
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);

2 个答案:

答案 0 :(得分:5)

答案 1 :(得分:1)

如果您使用的是旧版本的kafka,请在@KafkaListener中设置以下消费者工厂配置。

 Map<String, Object> props = new HashMap<>();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
    props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, CustomDeserializer.class);

这是CustomDeserializer的代码:

 import java.util.Map;
    import org.apache.kafka.common.serialization.Deserializer;
    import com.fasterxml.jackson.databind.ObjectMapper;
    public class CustomDeserializer implements Deserializer<Object>
    {
        @Override
        public void configure( Map<String, ?> configs, boolean isKey )
        {
        }

        @Override
        public Object deserialize( String topic, byte[] data )
        {
            ObjectMapper mapper = new ObjectMapper();
            Object object = null;
            try
            {
                object = mapper.readValue(data, Object.class);
            }
            catch ( Exception exception )
            {
                System.out.println("Error in deserializing bytes " + exception);
            }
            return object;
        }

        @Override
        public void close()
        {
        }
    }

由于我希望我的代码足够通用才能读取任何类型的json, object = mapper.readValue(data,Object.class);我正在将其转换为Object.class。而且由于我们在这里捕获了异常,因此一旦读取就不会重试。