WebSocket, Stomp, Kafka, MongoDB, MySQL, Redis를 사용하여 채팅 기능을 구현하였다.
이번에는 시간 타입 변경(String -> LocalDateTime)에 의한 성능 개선 경험 그리고 Kafka를 사용한 성능 개선 경험에 대해 작성해보려 한다.
성능 테스트 구성
테스트에 앞서 WebSocket 테스트를 위해서는, JMeter에 WebSocket 플러그인을 설치해야 한다.
Thread Group 구성
- 웹소켓 연결 시작(WebSocket Open Connection)
- 웹소켓 연결 요청(SEND CONNECT)
- 채팅방 구독 요청(SEND SUBSCRIBE)
- 메시지 전송(SEND CHAT)
- 응답 대기(READ CHAT)
- 웹소켓 연결 해제(DISCONNECT)
※ 이때, 채팅방 구독 해제와 웹소켓 연결 해제 과정에서 동일한 과정을 수행하므로 하나만 작성하였다.
※ 50명의 사용자가 1초 동안 20번씩 채팅 메시지를 전송한다 가정하였습니다.
성능 개선 이전 채팅 기능 성능 테스트
기존 채팅 기능 구성💬
WebSocket, STOMP, MongoDB, Redis, MySQL 사용
[시간 타입 변경x, 카프카 사용 x]
메시지 전송 기준 TPS
- TPS: 144.7
시간 타입 변경(String -> LocalDateTime)
- TPS: 144.7 -> 224.6 (55.1% 성능 개선)
Kafka를 사용한 성능 개선
메시지 전송 기준 TPS
- 144.7 -> 224.6 -> 484.6 (234.9% 성능 개선)
분명 Kafka를 적용하여 성능이 개선되었지만, 아쉬운 부분이 있다.
현재 프로젝트에서는 카프카를 사용하여 채팅 메시지(tovalley-chat)과 알림(tovalley-notification 두 가지 토픽을 생성하고, 이를 기반으로 메시지와 알림 시스템을 구축했다.
카프카는 기본적으로 비동기 그리고 분산 처리를 통해 성능을 향상시킨다.
프로젝트에서 카프카 프로듀서와 컨슈머를 사용해 비동기 방식의 이점을 보고 있으나, 분산 처리에 대해서는 이점을 보지 못하고 있다.
현재 채팅 메시지와 알림 토픽 각각은 하나의 파티션과 하나의 컨슈머로 처리되고 있다. 이는 초기 단계에서는 충분할 수 있으나, 데이터 처리량이 증가할 경우 처리 성능의 병목이 발생할 수 있다.
Kafka를 사용한 추가 개선 가능성 (분산 처리)
토픽 파티션 수 조정
토픽의 파티션 수를 조정하기에 앞서, 주의해야 할 점이 있다.
- 카프카에서 토픽의 파티션 수를 늘릴 수는 있지만 줄일 수는 없다.
- 너무 많은 파티션은 오버헤드를 증가시키고, 관리가 복잡해질 수 있다.
- 컨슈머 수가 파티션 수보다 많으면 일부 컨슈머는 데이터를 처리하지 못하고 유휴 상태가 된다.
- 반면, 파티션 수가 컨슈머 수보다 많으면 효율적인 데이터 처리를 위해 컨슈머 수를 증가시킬 필요가 있다.
그러므로, 테스트를 통해 지연이 발생하지 않는 최적의 파티션 수와 컨슈머 수를 찾아내는 것이 중요하다!!
참고: Kafka에서는 하나의 파티션 내에서만 메시지 순서를 보장한다.
현재 하나의 토픽에 대해 두개의 파티션으로 분리한 상태라 메시지 순서 보장이 안된다.
메시지 순서 유지를 위해 Key 기반 파티셔닝 방식을 사용해야 한다.
Key 기반 파티셔닝: 메시지 순서를 유지하려면, Kafka Producer가 메시지를 보낼 때 특정 '키(key)'를 지정하고, 이 키를 기반으로 Kafka가 메시지를 파티션에 할당하도록 한다. 예를 들어, 채팅방 ID나 사용자 ID와 같은 고유 식별자를 키로 사용하면, 동일한 채팅방이나 사용자의 메시지는 항상 동일한 파티션에 위치하게 되어 메시지 순서가 유지된다. 단, 이 방법은 모든 메시지가 균등하게 분산되지 않을 수 있으므로 파티션 간 부하 불균형을 초래할 수 있다.
대규모 트래픽 처리 상황에서 동일한 `chatRoomId`를 가진 메시지들이 모두 같은 파티션으로 라우팅되기 때문에, 해당 파티션을 처리하는 컨슈머의 부하가 증가하게 된다. 이는 파티션들 간의 작업 부하 불균형을 초래할 수 있으며, 결국 전체 시스템의 처리 성능에 영향을 미칠 수 있다.
현재 테스트 시나리오와 같이 하나의 채팅방에 대해 메시지 전송 성능을 테스트하면 부하 불균형으로 인해 성능상의 이점을 확인할 수 없다.
이러한 문제를 해결하기 위해 한명의 사용자가 서로 다른 두개의 채팅방에 메시지를 전송한다 가정하고 테스트를 진행한다.
2개의 파티션, 2개의 컨슈머(Consumer)
채팅, 알림 각각의 토픽이 2개의 파티션으로 분리되고 2개의 컨슈머에 처리되는 것을 확인할 수 있다.
그 후, 기존 성능 테스트 방식을 사용해 처리를 해보았다.
기존 하나의 파티션, 하나의 컨슈머를 사용한 결과와 비교하면 다음과 같다.
- TPS: 484.6 -> 522.0 (7.7% 성능 개선)
3개의 파티션, 3개의 컨슈머(Consumer)
- TPS: 484.6 -> 522.0 -> 483.4 (7.4% 성능 감소)
3개의 파티션으로 분할한 결과, 전반적으로 2개의 파티션보다 성능이 악화된 것을 확인할 수 있다.
즉, 파티션이 1개일 때와 성능이 비슷하게 측정된다.
Kafka 성능 튜닝
찾아보니, 컨슈머를 효율적으로 사용하기 위해서는, fetch.min.bytes와 fetch.max.wait.ms 설정을 조정해야 한다는 것을 알게 되었다.
간략하게 설명하자면, fetch.min.bytes는 컨슈머가 데이터를 가져올 때 요청하는 최소 데이터이다. (설정된 바이트 수 이상의 데이터가 브로커에 있는 경우에만 데이터를 가져온다.) 이는 네트워크를 통한 불필요한 데이터 전송을 줄이고, 더 큰 데이터 덩어리를 한 번에 가져오기 위함으로 네트워크 사용량과 지연 시간을 줄이는 데 도움이 된다.
fetch.max.wait.ms의 경우 지정된 데이터 양이 브로커에 도달하지 않았을 때, 컨슈머가 데이터를 가져오기 위해 최대로 기다릴 수 있는 시간을 의미한다. 이는 지연 시간과 대역폭 사용 사이의 균형을 맞추는 데 도움을 준다.
다음은 시스템에서 카프카 컨슈머를 설정한 내용이다. 살펴보면, fetch.min.bytes와 fetch.max.wait.ms를 설정한 내용이 없다. 각각의 기본값은 1byte과 500ms이다.
이러한 설정값은 컨슈머(Consumer)가 메시지 브로커에 데이터가 쌓일 때마다, 데이터를 소비하게 되므로 성능과 효율성 측면에서 좋지 못하다.
fetch.min.bytes와 fetch.max.wait.ms 각각의 값을 최적화할 필요가 있다.
fetch.min.bytes: 10000, fetch.max.wait.ms: 200ms
그리고 채팅과 알림 토픽의 파티션과 컨슈머의 개수가 각각 1개인 경우, 2개인 경우, 3개인 경우 모두 성능 측정한 결과는 다음과 같다.
- TPS: 623.5, 522.0 -> 638.4 (22.2% 성능 개선), 238.3
토픽의 파티션과 컨슈머의 개수가 2개인 경우, 모든 측면에서 제일 좋은 성능을 나타낸다.
반면, 3개인 경우 모든 측면에서 가장 좋지 않은 성능을 나타냈다. 이는 파티션과 컨슈머의 개수가 증가함에 따라 처리해야 할 데이터의 양과 복잡성이 증가했기 때문일 수 있다. 그리고 처리량이 크게 감소한 것은 파티션과 컨슈머의 개수가 증가하면서 데이터 처리에 더 많은 시간이 소요되었기 때문이다. 특히, 최대 응답 시간의 증가는 데이터 처리에 있어 불규칙성과 지연이 증가했음을 시사한다.
성능 개선 결과
개선 방식 | TPS | 성능 개선 비율 |
성능 개선 이전 | 144.7 | 기준 |
시간 타입 (String -> LocalDateTime) | 224.6 | 55.1% 성능 개선 |
카프카 적용(파티션 분리, fetch.min.bytes, fetch.max.wait.ms 설정) | 638.4 | 341.2% 성능 개선 |
참고
https://kafka.apache.org/documentation/
'기술 블로그 > ToValley' 카테고리의 다른 글
[Spring Boot, WebSocket, Kafka, MongoDB] 채팅 기능 구현#3. 기본 설정 (0) | 2024.04.09 |
---|---|
[Spring Boot, WebSocket, Kafka, MongoDB] 채팅 기능 구현#2. 도메인 설계 (0) | 2024.03.21 |
[Spring Boot, WebSocket, Kafka, MongoDB] 채팅 기능 구현#1. 기술 선정 (0) | 2024.03.20 |
Refresh Token 문제 및 해결 과정 (0) | 2024.01.05 |
[Spring Boot + React]배포#5. AWS 보안 그룹 설정 (0) | 2023.12.17 |