kym8821 님의 블로그
[Spring Boot] 실시간 비동기 작업 처리기 만들기 - 기초 개념 본문
요구사항 분석
이번에 실시간으로 사용자 입력을 받아서 이를 AI 서버에 전달하여 실시간으로 사용자에게 응답하는 기능을 개발하게 되었다. 따라서 아래와 같은 요소들을 고려해야할 조건으로 정했다.
- 사용자의 입력 순서에 맞게 출력을 제공해야 한다.
- 여러개의 서버가 존재할 때, 입력에 대한 한 번의 응답만 존재해야 한다.
- 장기적인 연결이 가능해애 하고 데이터가 소실되면 안된다.
이러한 상황에서 Kafka와 Stomp를 활용한 실시간 비동기 작업 처리가 적절한 방법이라 생각했다.
Stomp
우선 Kafka에 대해서 알아보기 전에 Stomp 먼저 알아본다.
Stomp 특징
Stomp는 웹소켓 위에서 동작할 수 있는 프레임 기반 메세징 프로토콜로, 아래 특징들이 있다.
- Stomp는 웹소켓 기반으로 동작하므로 웹소켓 연결이 필요하다
- Stomp는 메세지 브로커를 활용한 publisher-subscriber 구조를 갖는다
- Stomp는 프레임 기반의 서브 프로토콜이다. 즉, 메세지 전송시 규격이 존재한다.
- 이는 Stomp를 웹소켓과 구분짓는 가장 큰 특징이다.
Stomp의 프레임
Stomp의 메세지는 일정한 규격을 갖고 크게 command, header, body로 구분된다.
- command : connect, subscribe, send 등등 메세제의 종류를 정의
- header : key-value 꼴의 헤더 정보를 저장
- body : 데이터(payload)를 포함하고, 마지막에 null 문자로 끝남.
Stomp는 웹소켓 위에서 동작하는 프레임 기반 서브 프로토콜이다.
따라서 이론상 아래와 같이 소켓 통신을 진행해도 정상적으로 Stomp가 동작한다.
SEND // command
destination: /app/audio/forwarding // header
content-type: application/json
receipt:message-12345
{"message": "MESSAGE"} // body
^@
postman으로 위 메세지를 테스트하면, null 문자열을 제대로 식별하지 못하기에 문제가 발생한다
mac notepod가 있다면, null 값을 복사하여 대체하도록 하자.
Stomp 동작 방식
이번에는 Stomp의 동작 방식에 대해서 알아본다.
Stomp는 위에서 설명했듯, 메세지 브로커를 활용하여 publisher-subscriber 구조를 갖는다.
여기서 메세지 브로커는 publisher로부터 메세지를 전달받아서 consumer에게 전달하는 중간 다리 역할이다.
아래 kafka 설명에서 보다 자세히 다루겠지만, 메세지 브로커의 동작 원리에 대해서 설명하겠다.
- 클라이언트가 메세지 브로커의 특정 주제를 구독
- 여기서 주제(topic)은 메세지가 발행되는 경로이다.
- 주제의 존재 덕분에, consumer들은 자신이 구독한 경로의 메세지만 받아볼 수 있다.
- 클라이언트는 서버에 메세지를 전달하고, 해당 메세지를 특정 주제로 publish
- 메세지 브로커는 해당 주제를 subscribe하고 있는 주체들(consumer)에게 메세지를 전달
이제 Stomp의 동작 방식에 대해서 알아보자.
- Stomp는 웹소켓 위에서 동작하므로 클라이언트-서버 웹소켓 연결
- 클라이언트는 stomp 연결을 위해 CONNECT command 메세지를 전달
- 해당 CONNECT 메세지는 웹소켓 연결이 아닌 stomp 프로토콜을 활용한 통신을 위한 연결이다.
- 서버는 연결 성공시 클라이언트에게 CONNECTED command 메세지 전달
- 클라이언트는 특정 주제를 구독하기 위한 SUBSCRIBE command 메세지 전달
- 클라이언트는 메세지 publish를 위해 SEND command 메세지 전달
- 해당 메세지는 클라이언트와 직접적으로 연결된 서버에서만 처리됨
- 해당 메세지를 publish한다면, 다른 서버나 클라이언트들이 해당 메세지를 consume하여 사용 가능
- 메세지를 publish한 주제를 구독하는 consumer에게 MESSAGE command 메세지 전달
Kafka
stomp는 자체적으로 메세지 브로커를 제공하기에 해당 브로커를 사용해도 정상 동작한다.
하지만, MSA 환경이나 순서 보장 등의 추가 요구상황이 필요하다면 내부 브로커만으로는 부족할 수 있다.
이러한 상황에서 우리는 kafka를 메세지 브로커로서 활용할 수 있다.
Kafka 특징
Kafka는 정확히 말하자면 메세지 브로커가 아니다.
Kafka는 외부 이벤트 브로커이고, publisher-subscriber 구조를 갖는다.
카프카는 이벤트 소싱 방식을 채택한다.
이벤트 소싱이란 시스템의 모든 상태를 일으키는 이벤트를 순서에 맞게 저장하는 개념을 말한다.
따라서 kafka는 다른 메세지 브로커들과 달리, 메세지를 한번 consume해도 만료 시간까지 해당 메세지가 사라지지 않는다.
kafka 브로커, 토픽, 파티션
kafka에 대해서 보다 자세히 이해하기 위해서는 브로커, 토픽 파티션에 대해서 이해해야 한다.
- 토픽 : 카프카에서 메세지가 저장 및 구독되는 논리적 채널 (메세지의 카테고리)
- 사용자가 특정 토픽에 메세지를 전송하면, 해당 토픽을 구독하는 사용자들가 메세지를 consume한다.
- 파티션 : 토픽을 물리적으로 분할하는 단위로 하나의 토픽은 여러개의 파티션으로 구성된다.
- 같은 토픽의 같은 파티션에 있는 메세지들은 순서대로 처리된다. 다만, 서로 다른 토픽의 경우 순서를 보장하지 않는다.
- 브로커 : 카프카 클러스터 내에서 메세지를 저장 및 관리하는 서버이다.
- 카프카 클러스터는 여러개의 카프카 브로커로 구성되고, 카프카 브로커에는 여러개의 토픽이 있을 수 있다.
- 메세지는 카프카 클러스터의 여러 브로커의 파티션에 분산 저장된다.
- 브로커는 자신 내부 파티션에 대한 읽기/쓰기 처리를 관리한다.
이 내용을 정리하면, 아래와 같은 구조를 그려볼 수 있다.
zookeeper와 kafka
kafka는 주키퍼 클러스터와 카프카 클러스터로 구성되어 있고, 여러대의 서버에 데이터를 분산 저장한다
여기서 zookeeper가 하는 역할에 대해서 알아보자.
zookeeper는 분산 시스템에서 노드(서버) 간의 동기화와 구성 관리를 도와주는 도구이다.
zookeeper의 대표적인 기능은 아래와 같다.
- 분산 락 : 여러 프로세스가 동시에 동일 자원에 접근하여 발생하는 충돌 방지
- 노드 상태 관리 : 클러스터 내 노드 상태 추적 및 관리
- 분산 설정 관리 : 여러 노드의 설정을 일관되게 유지 및 공유
- 리더 선출 : 분산 환경에서 하나의 리더를 선출하여 해당 리더가 주요 작업을 하도록 함.
이러한 zookeeper의 기능들은 kafka에서 아래와 같이 사용된다.
- 메타데이터 관리
- 분산 환경에서 kafka 클러스터는 여러개의 브로커로 구성되고, 각 브로커의 파티션에 메세지가 저장된다.
- 이러한 카프카의 토픽과 파티선의 메타 데이터를 주키퍼가 관리 및 공유해주기에 분산 환경에서 브로커 간 정보를 동기화할 수 있다.
- 리더 선출 및 분산 조정
- 여러대의 브로커가 있을 때, 메세지를 consume할 때는 여러 브로커들 중 리더를 선출하여 해당 브로커만 메세지를 처리해야 한다.
- 이러한 상황에서 zookeeper가 리더 선출을 돕는다.
- 브로커 상태 모니터링 및 장애 처리
- 주키퍼는 카프카 브로커들의 상태를 모니터링하고, 장애를 일으킨 경우 이를 감지하여 처리한다.
- 이를 통해 카프카는 내결함성을 챙길 수 있다.
카프카의 장단점
- 장점
- 카프카는 분산 환경에서 대용량 데이터를 효과적으로 처리할 수 있는 강력한 도구이다.
- 카프카는 동일 토픽의 동일 파티션에 대해 메세지 소비 순서를 보장한다.
- zookeeper와의 연계를 통해 카프카는 내결함성과 확장성에서 이점이 있다.
- 단점
- 다른 메세지 브로커와 달리, fault 처리 매커니즘을 제공하지 않는다.
- 메세지 소비 순서를 보장하기에 메세지 처리 재시도시 같은 파티션의 다른 메세지를 처리하지 못한다.
즉, 카프카는 대용량 데이터의 효율적인 처리와 메세지 전달에 초점을 맞추지만, 메세지 전송 확인에 대한 기능은 부족하다
Kafka + Stomp
마지막으로 Kafka를 메세지 큐로 사용한 경우, stomp가 어떻게 동작하는지 알아보도록 하자.
kafka + stomp 동작 방식
외부 브로커를 두었을 때, stomp의 동작방식은 아래 그림에서 크게 벗어나지 않는다.
기존 작동방식과 비교했을 때 StompBroker라는 내부 브로커를 사용하는 것 대신 StompBrokerRelay라는 요소가 생겼다.
StompBrokerRelay는 외부 브로커와 stomp를 중계하는 역할을 한다. 이를 통해서 외부 브로커에 메세지를 produce, consume할 수 있다.
정리하자면, 기존의 StompBroker의 역할을 StompBrokerRelay와 외부 Message Broker가 대체한 것이다.
마무리
이번에는 Stomp와 kafka를 활용한 실시간 작업 처리 장치를 구현하기 위한 기술들을 알아보았다.
다음에는 이러한 기술들을 Spring Boot에 적용하여 웹소켓 기반의 실시간 작업 처리 장치를 구현할 것이다.
'Spring > 기초 개념' 카테고리의 다른 글
Spring Data JPA의 영속성 컨텍스트 (0) | 2025.04.02 |
---|---|
[Spring Boot] 실시간 비동기 작업 처리기 만들기 - 실습 (0) | 2025.03.26 |
SpringBoot에서 Mockito로 소셜 로그인 단위 테스트 (0) | 2025.02.14 |
Access Token와 Refresh Token을 활용한 인증과 인가 (0) | 2025.02.07 |
Spring Boot에서 테스트코드 작성하기 (0) | 2025.02.01 |