[트러블슈팅] Kafka Consumer 역직렬화 오류 및 공통 모듈 활용

greenlemonT·2025년 2월 27일
post-thumbnail

Kafka 메시지 역직렬화 및 Retry 설정 트러블슈팅

<문제 상황>

Kafka 메시지를 Consumer에서 처리하는 과정에서 아래와 같은 ClassNotFoundException이 발생했다.

Caused by: java.lang.ClassNotFoundException: finpago.matchingservice.matching.messaging.events.TradeMatchingEvent

이는 Execution Service에서 Kafka 메시지를 역직렬화할 때 TradeMatchingEvent 클래스를 찾을 수 없어 발생하는 문제다.


<문제 원인>

원래 각 모듈마다 TradeMatchingEvent을 넣어서 사용햇는데 (객체 내용으로 판별하는줄)
그 파일 경로로 판단하는거여서 경로가 달라서 역직렬화 오류가 생기는거엿다

현재 Matching Service가 TradeMatchingEvent를 Kafka에 전송하고 있지만, Execution Service에서는 해당 클래스를 찾을 수 없다.

이는 TradeMatchingEvent가 Matching Service의 패키지 경로에 존재하기 때문이며, Execution Service에서는 이를 로드할 수 없는 상태이다.

오류 메시지

Caused by: java.lang.ClassNotFoundException: finpago.matchingservice.matching.messaging.events.TradeMatchingEvent

Execution Service가 Matching Service에서 전송한 TradeMatchingEvent를 역직렬화하려고 하지만, 해당 클래스가 존재하지 않아 역직렬화에 실패한다.


<해결 방법>

1. Matching 모듈과 Execution 모듈이 동일한 TradeMatchingEvent 클래스를 사용하도록 설정

현재 Matching 모듈과 Execution 모듈이 서로 다른 패키지에서 TradeMatchingEvent를 정의하고 있기 때문에, Kafka 메시지를 처리할 때 클래스가 일치하지 않아 역직렬화 오류가 발생한다.

해결책: 공통 모듈에 TradeMatchingEventOrderCreateReqEvent을 생성하여 공유

  1. TradeMatchingEvent, OrderCreateReqEvent 클래스를 common 모듈로 이동한다.

    • 경로: finpago.common.messaging.events.TradeMatchingEvent
  2. MatchingService 및 ExecutionService가 공통 모듈을 의존하도록 설정

    • 각 서비스의 build.gradle에 다음과 같이 추가한다.
    dependencies {
        implementation project(':common')
    }
  3. Kafka Consumer 및 Producer 설정에서 올바른 패키지 경로를 지정

    • ExecutionService의 Kafka Consumer 설정 수정
    @Bean
    public ConsumerFactory<String, TradeMatchingEvent> tradeConsumerFactory() {
        Map<String, Object> props = new HashMap<>();
        props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS);
        props.put(ConsumerConfig.GROUP_ID_CONFIG, GROUP_ID);
        props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
        props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);
    
        // 공통 모듈의 패키지로 변경
        props.put(JsonDeserializer.VALUE_DEFAULT_TYPE, "finpago.common.messaging.events.TradeMatchingEvent");
        props.put(JsonDeserializer.TRUSTED_PACKAGES, "finpago.common.messaging.events");
    
        return new DefaultKafkaConsumerFactory<>(props);
    }
    • MatchingService의 Kafka Producer 설정 수정
    @Bean
    public ProducerFactory<String, TradeMatchingEvent> tradeProducerFactory() {
        Map<String, Object> props = new HashMap<>();
        props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS);
        props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
        props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, JsonSerializer.class);
    
        // 헤더 정보를 추가하여 직렬화 문제 방지
        props.put(JsonSerializer.ADD_TYPE_INFO_HEADERS, true);
    
        return new DefaultKafkaProducerFactory<>(props);
    }

2. Matching 모듈과 Execution 모듈의 TRUSTED_PACKAGES 설정

공통 모듈을 사용하더라도 Kafka Consumer가 특정 패키지만 신뢰하도록 설정하면 역직렬화 오류가 발생할 수 있다.

이를 방지하기 위해 TRUSTED_PACKAGES 설정을 수정해야 한다.

@Bean
public ConsumerFactory<String, TradeMatchingEvent> tradeConsumerFactory() {
    Map<String, Object> props = new HashMap<>();
    props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, BOOTSTRAP_SERVERS);
    props.put(ConsumerConfig.GROUP_ID_CONFIG, GROUP_ID);
    props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
    props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, JsonDeserializer.class);

    // Matching 모듈에서 보낸 메시지를 신뢰할 수 있도록 설정
    props.put(JsonDeserializer.TRUSTED_PACKAGES, "finpago.common.messaging.events");

    return new DefaultKafkaConsumerFactory<>(props);
}

결론

Kafka 메시지 역직렬화 오류(ClassNotFoundException)는 MatchingService와 ExecutionService가 서로 다른 패키지에 동일한 클래스를 정의할 때 발생할 수 있다.

이를 해결하려면 공통 모듈(common)을 만들어 모든 서비스에서 동일한 이벤트 클래스를 사용하도록 구성해야 한다.

0개의 댓글