WebRTC 프로젝트에서 마이크로서비스 아키텍처 중 채팅 서비스 구현 중 문제가 발생했다.
Kafka에 데이터를 넣었으나 직렬화 관련 에러였다.
문제 원인 파악
먼저, 아래 에러 로그에서 직렬화 중 Deserializer에서 문제가 발생했다. 카프카에 객체 클래스를 전송했고 org.springframework.kafka.support.serializer.JsonDeserializer 를 사용하여 역직렬화함을 확인했다.
java.lang.IllegalStateException: This error handler cannot process 'SerializationException's directly; please consider configuring an 'ErrorHandlingDeserializer' in the value and/or key deserializer
<관련 에러 로그>
추가적으로, 아래 에러로그를 통해 역직렬화가 되지 않은 데이터를 확인할 수 있었고, 아스키 코드 변환임에도 음수(-) 문자들이 존재했다. 이는 이 부분에서 문제가 발생했구나 라고 추측할 수 있었다. 아스키 코드 - 텍스트 변환기를 통해 확인한 결과 senderID부분에 문제가 있었다.
Postman을 통해 보낸 채팅을 확인한 결과 senderId부분에 한글 문자가 입력했고, 한글 문자는 아스키 코드를 지원하지 않기 때문에 발생한 에러 였다.
MongoDB에 데이터는 정상적으로 저장되어 에러 로그를 확인할 수 없었다. => 추후 response에 에러 내용을 담기 위한 global exception hanling 필요
Caused by: org.apache.kafka.common.errors.SerializationException: Can't deserialize data [[123, 34, 95, 105, 100, 34, 58, 34, 54, 52, 50, 51, 101, 52, 100, 53, 53, 54, 49, 49, 57, 97, 55, 101, 102, 56, 100, 57, 56, 98, 48, 57, 34, 44, 34, 114, 111, 111, 109, 73, 100, 34, 58, 34, 49, 50, 51, 49, 50, 51, 50, 49, 34, 44, 34, 115, 101, 110, 100, 101, 114, 73, 100, 34, 58, 34, -20, -100, -96, -20, -96, -128, 34, 44, 34, 109, 101, 115, 115, 97, 103, 101, 84, 121, 112, 101, 34, 58, 34, 84, 69, 88, 84, 34, 44, 34, 99, 111, 110, 116, 101, 110, 116, 34, 58, 34, 97, 115, 100, 102, 97, 115, 100, 102, 34, 44, 34, 99, 114, 101, 97, 116, 101, 100, 65, 116, 34, 58, 91, 50, 48, 50, 51, 44, 51, 44, 50, 57, 44, 49, 54, 44, 49, 50, 44, 50, 49, 44, 52, 57, 57, 52, 56, 51, 48, 48, 48, 93, 125]] from topic [studyhub]
<역직렬화 상세 에러 로그>
{"_id":"6423e4d556119a7ef8d98b09","roomId":"12312321","senderId":"d``","messageType":"TEXT","content":"asdfasdf","createdAt":[2023,3,29,16,12,21,499483000]}
<아스키코드 - 텍스트 변환 값>
문제 해결
한글 문자를 사용하지 않을 수 없기 때문에 Serialize/Deserialize 방법을 바꿀 필요가 있다.
org.springframework.kafka.support.serializer.JsonSerializer를 통해 변환했을 때 아스키 코드로 변환되었으나,
org.apache.kafka.common.serialization.StringSerializer 는 UTF-8(default)로 변환하는 것을 확인했다.
+ JsonSerializer의 default encoding은 확인하지 못했다. ObjectMapper를 활용하는 것을 공식 문서에서 확인했고 ObjectMapper는 UTF-8을 default로 사용하는 것 같은데 왜 ascii문자들이 나왔는 지는 잘 모르겠다...
따라서 Json(De)serializer => String(De)serializer로 다른 라이브러리를 활용한다.
그리고 넣고 꺼낼 때마다 Object <=> String으로 변환한다.
실제 해결 코드는 아래와 같다.
@Service
@RequiredArgsConstructor // same as autowired
@Slf4j
public class KafkaProducer {
private final KafkaTemplate<String, String> kafkaTemplate;
public void send(String topic, Chat chat) {
log.info("topic : " + topic);
log.info("topic : " + chat.getContent());
ObjectMapper objectMapper = new ObjectMapper();
try {
String stringChat = objectMapper.writeValueAsString(chat);
log.info(stringChat);
kafkaTemplate.send(topic, stringChat);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
}
<KafkaProducer>
@Service
@RequiredArgsConstructor // same as autowired
@Slf4j
public class KafkaConsumer {
private final static String GROUPID = "${spring.kafka.consumer.group-id}";
private final static String TOPICS = "${spring.kafka.topic}";
private final SimpMessagingTemplate template;
@KafkaListener(topics = TOPICS, groupId = GROUPID)
public void consume(String stringChat) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Chat chat = objectMapper.readValue(stringChat, Chat.class);
log.info("Consumed Message : " + stringChat);
template.convertAndSend("/topic/"+chat.getRoomId(), stringChat);
}
}
<KafkaConsumer>
KafkaProducer : kafka에 전송 시, ObjectMapper를 이용하여 변환하였다.
KafkaConsumer : Kafka에서 꺼낼 시, ObjectMapper를 이용하여 변환하여 roomId 만 얻은 후 string으로 전송하였다.
이러한 중 아래 에러가 발생하였으나 @NoArgsConstructor를 통해 해결하였다.
(no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
'백엔드' 카테고리의 다른 글
gRPC통신에 관하여 (0) | 2023.08.07 |
---|---|
Jackson 라이브러리를 활용한 (역)직렬화 다형성 - JsonTypeInfo / JsonSubTypes (0) | 2023.05.16 |
Jar VS War (0) | 2022.11.15 |
REST API (0) | 2021.11.28 |
Maven , Gradle (0) | 2021.11.16 |