문제 인식
저희 프로젝트에 STOMP + 웹소켓 + 카프카 + 몽고 DB를 사용한 채팅 기능을 구현 했습니다.
채팅방에 처음 입장할 때 입장하기 메시지를 채팅방에 있는 사람에게 보내는데, 해당 메시지를 수신하는데 5분이 걸리는 문제가 있었습니다.
채팅은 실시간성이 중요한 기능이기에 반드시 해결해야하는 문제였습니다.
문제 파악
채팅 메시지는 STOMP의 pub/sub 구조와 카프카의 메시지 브로커를 통해 전달이 됩니다.
당시 입장 메시지 데이터 흐름
- 채팅방에 입장하면 서버와 클라이언트는 웹소켓 연결을 맺고 입장 메시지를 서버에게 보냅니다.
- 서버는 받은 입장 메시지를 메시지 핸들러를 거치고 카프카의 해당 채팅방 토픽으로 보냅니다.
- 채팅방 토픽을 구독하고 있는 카프카 리스너에서 입장 메시지를 받습니다.
- 카프카에게 받은 메시지를 몽고 DB에 저장합니다.
- 몽고 DB에 저장한 후 해당 채팅방을 구독하고 있는 클라이언트에게 보냅니다.
저는 먼저 PUB, SUB, 메시지 브로커 중에 무엇이 문제인지 확인하기 위해 카프카의 해당 토픽을 확인했습니다.
토픽을 확인한 결과, 메시지는 잘 들어왔고 SUB 부분에 문제가 있다고 판단했습니다.
문제 위치를 정확히 파악을 하기 위해 카프카 리스너와 몽고 DB 저장 로직 사이, 몽고 DB 저장 로직과 구독자에게 메시지를 보내는 로직 사이에 메시지를 출력하는 로그를 추가했습니다.
그런 다음 실행한 결과, 카프카 리스너에서 데이터를 늦게 받아서 생긴 문제임을 확인했습니다.
왜 카프카 리스너에서 데이터를 늦게 받는지 조사한 결과, 카프카 컨슈머 리밸런싱과 관련이 있었습니다.
메시지 브로커는 해당 토픽의 각 파티션마다 메시지를 어떤 컨슈머에게 보낼 것인지를 정해야 합니다.
즉, 컨슈머 그룹 내의 컨슈머 수에 변화가 있거나, 토픽의 파티션이 변경이 되었을 때 리밸런싱을 통해 파티션 별로 컨슈머를 재할당합니다.
이 리밸런싱이 일어나게 되면 리밸런싱이 일어난 컨슈머 그룹 내의 모든 컨슈머의 읽기 작업이 중단됩니다.
저는 채팅방에 입장 했을 때, 특정 채팅방을 위한 토픽을 새로 만들고 있었습니다.
그래서 만들어진 토픽의 파티션에 컨슈머를 할당하기 위해 리밸런싱이 일어나게 되었고, 카프카 리스너에서 바로 메시지를 받지 못한 것입니다.
문제 해결
해결 방법으로 다음 2가지가 떠올랐습니다.
- 첫 번째, 채팅방을 사용하려면 예약을 먼저 해야했기 때문에 예약할 때 미리 토픽을 생성하는 방법
- 두 번째, 채팅은 하나의 토픽으로만 사용하는 방법
저는 다음 2가지 이유로 두 번째 방법을 채택했습니다.
- 예약을 취소하면 토픽을 생성한 비용이 낭비가 되고, 토픽을 삭제하지 않는 한 토픽에 대한 정보가 이전보다 더 쌓일 것이라 생각했습니다.
- 리밸런싱은 카프카 성능에 부정적인 영향을 주기 때문에 최대한 안일어나는 것이 좋다는 글을 보았습니다.
그래서 저는 서버를 실행할 때, chat 토픽이 없으면 생성하게끔 하고 모든 채팅방은 chat 토픽을 이용하게 변경하였습니다.
그 결과, 첫 입장 메시지를 받는 데 5분 걸리던 것이 1초 미만으로 걸리게 되었습니다.
'프로젝트 트러블 슈팅' 카테고리의 다른 글
QueryDsl 연관관계 2Depth 이상 엔티티 로딩 이슈 (0) | 2024.09.27 |
---|---|
도커로 생성한 MySQL 다른 포트 매핑 문제 (0) | 2024.09.27 |
Redis 역직렬화 이슈 (3) | 2024.09.27 |
소셜 로그인이 확률적으로 성공하는 문제 (0) | 2024.04.03 |
카프카 컨슈머 역직렬화 실패 (0) | 2024.03.28 |