본문 바로가기
Programming

대용량 데이터 처리를 위한 Message Broker

by LeeJ1Hyun 2023. 1. 30.
메세지 브로커 (Message Broker)

 

대용량 데이터 처리를 위한 미들웨어(서로 다른 어플리케이션이 서로 통신하는데 사용되는 소프트웨어)이다.

 

 

일반적으로 데이터를 3개의 어플리케이션들이 데이터를 주고 받으려면 3개의 커넥션이 필요하다.

 

 

어플리케이션이 2개만 더 늘어나도 커넥션은 10개로 늘어난다. 어플리케이션의 개수가 늘어날수록 커넥션의 개수도 기하급수적으로 늘어나게 된다. 이들의 연결 관계는 점점 복잡해지고 프로그램의 확장도 어려워진다. 어플리케이션들의 연결을 한 곳으로 모아 관리하는 소프트웨어가 있다면 구조는 더욱 간단해진다. 이것이 바로 미들웨어의 힘이다.

 

 

어플리케이션들의 사이에서 서로 통신할 수 있게 하고, 데이터를 주고 받을 수 있게 하는 분산 소프트웨어이다. 메세지 브로커도 미들웨어의 종류중 하나이다. 메세지 미들웨어를 MOM(Message Oriented Middleware)이라고도 한다.

 

메세지 브로커(Message Broker)는 메세지를 생산하는 Publisher(송신자)와 저장된 메세지를 사용하는 Subscriber(수신자) 사이에서 메세지를 저장하고 전달해주는 역할을 한다.

 

메세지 브로커의 구조

 

메세지가 적재되는 공간을 메세지 큐(Message Queue)라고 하며, 메세지들의 그룹을 토픽(Topic)이라고 한다. Subscriber는 각각 토픽에 맞는 메세지만을 전달받을 수 있다. Publisher, Subscriber가 아닌 Producer, Consumer라고도 한다. 메세지를 전송 및 수신하기 위해 중간에 메세지 큐를 두는 Buffer와 같은 개념이다. 덕분에 수신자가 원하는 시점(처리 가능한 시점)에 메세지를 가지고 갈 수 있다. 메세지들을 한 곳에 모아 여러 어플리케이션들의 관계를 느슨하게 해줄 뿐만 아니라 Subscriber의 상태가 불안정한 상황에 Publisher가 전달한 메세지는 그대로 적재되어 있다가 다시 전송이 된다. 비동기 방식을 따르고 있다. 기존의 데이터 전달 구조는 생산과 전달을 직접 연결하여 수행했기 때문에 Subscriber가 불안정하면 데이터를 전송했지만 날아가는 현상이 일어나기도 했다.

 

메세지 큐는 단순히 Queue 자료 구조 형태로 메세지를 다루는 구조를 의미한다. 메세지 브로커는 메세지 큐에서 더 확장하여 광범위한 전송, 해당 메세지의 특성을 통한 라우팅 등 고급 기능을 지원하기 때문에 목적에 따라 내부 구조가 달라진다. 간단하게 말하면 메세지 브로커는 Publisher가 만들고 보낸 메세지를 받아서 Subscriber에게 전달하는 역할이고, 메세지 큐는 메세지 브로커 내부에 메세지가 적재되는 공간이다.

 

메세지 브로커의 대표적인 예로는 RabbitMQ, Kafka 등이 있다. 정확하게 말하자면 RabbitMQ는 방금 소개한 전통적인 메세지 브로커이고,  Kafka는 이벤트 스트리밍 플랫폼이다. Publisher와 Subscriber간의 연결은 느슨하게 만들었지만 메세지 브로커와 Subscriber간의 결합력이 높아지게 된다. 트래픽이 증가하게 되어 메세지가 증가하면 수평적으로 확장하는데 어려움이 존재한다. 메세지 브로커가 메세지가 성공적으로 전달되었다고 판단하면 큐에서 삭제하기 때문에 이를 다시 재생하기도 어렵다.

 

그래서 등장한 것이 이벤트 스트리밍 플랫폼(데이터 스트림을 읽고 쓰고 저장하고 처리하는 역할을 가진 시스템)인 카프카이다. 목적은 동일하지만 작동 방식에 차이점이 존재한다. 바로 토픽이라는 것이 이벤트 스트리머에 저장된다. 생성된 이벤트를 토픽이라고 불리는 이벤트의 레코드 로그를 스트리머에 순서대로 기록한다. 해당 토픽을  Subscriber가 전달받은 후에도 이벤트 스트림에서 토픽을 유지하기 때문에 오류가 나도 이벤트를 다시 재생할 수 있다.

 

카프카와 일반적인 메세지 브로커의 차이는 클러스터로 실행된다는 점이다. 전통적인 메세지 브로커는 각각의 어플리케이션을 수동으로 연결해야 하지만 카프카는 모든 데이터 스트림 처리를 위하여 하나의 중심 플랫폼 역할을 한다. 카프카 클러스터 내부에 여러개의 브로커가 존재하고 하나의 카프카 서버는 하나의 브로커라고 보면 된다.

 

메세징 모델에는 1:1, 1:N 관계가 존재한다. Publisher, Subscriber 그리고 Producer, Consumer 용어를 구분 없이 쓰다보니 헷갈릴 수도 있다.

 

Point to Point

 

메세지를 만들고 송신하고 이를 큐에 적재하고 큐가 수신자에게 전달하는 모델에서는 Producer, Consumer라고 하는 것이 일반적이고,

 

Publish-Subscribe

 

메세지를 만들고 이를 큐 내부의 토픽에 적재하고 이 토픽을 구독하고 있는 수신자들에게만 전달하는 모델에서는 Publisher, Subscriber라고 한다.

 

카프카를 개발한 링크드인의 시스템 구조가 얼마나 간단해졌는지를 통해 MOM의 필요성을 깨달을 수 있다.

 

기존의 링크드인 시스템 구조 https://www.confluent.io/blog/event-streaming-platform-1/

 

카프카를 도입한 후 시스템 구조 https://www.confluent.io/blog/event-streaming-platform-1/

 

이벤트의 흐름 제어를 한 곳으로 모아 서비스의 확장이 더욱 용이해졌다.

 

RabbitMQ는 쉽고 빠르게 작은 서비스의 메세지 브로커를 구축하기 좋다. 또한 메세지 전달 보장이 필수적이다. 단, 메세지 처리 순서가 보장 되지 않는다는 점을 유의해야 한다. 메세지 브로커가 전달 완료되었다고 생각한 메세지는 큐에서 지워지기 때문에 영속성을 보장할 수 없다는 점도 존재한다.

 

Kafka는 높은 처리량을 감당할 수 있으며 스케일 아웃이 중요한 경우에 사용한다. 메세지 처리 순서가 보장되지만 전달 보장은 필수적이지 않다는 점이 특징이다. 또한 메세지의 영속성이 보장된다.

 

Springboot + Kafka를 통한 Publisher/Subscriber 구현

 

Springboot를 이용하기 전 Kafka만을 이용하여 Pub/Sub 구조를 구현해보자.

 

1. Kafka, zookeeper(분산 애플리케이션을 위한 코디네이션 시스템) 서버를 켠다.

2. 토픽을 생성한다.

3. 해당 토픽을 송신하는 producer, 수신하는 consumer에 접속한다.

4. producer에서 메세지를 전송한다.

5. consumer에 메세지가 도착한다.

 

 

Producer가 실시간으로 생성한 메세지가 Consumer에게 전달되고 있는 모습이다. 같은 Game 토픽으로 연결되어 있기 때문에 전달 가능한 것이다. 만약 여러 개의 토픽을 만들고 A토픽 관련하여 Producer 메세지를 보내도, B토픽의 Consumer는 메세지를 받을 수 없다.

 

Springboot에서는 application.yml에 groupId를 작성해줘야 한다. Consumer는 Consumer Group이 존재하기 때문에 식별 가능한 Consumer Group을 작성해야 하기 때문이다.

 

@Service
public class KafkaConsumerService {

    @KafkaListener(topics = "Game", groupId = "group-id-amugae")
    public void consume(String message) throws IOException {
        System.out.println("받은 메세지 : " + message);
    }
}

 

@KafkaListener 어노테이션을 통하여 토픽이 Game이고 groupId가 group-id-amugae인 Consumer에게 수신되어야 할 메세지를 듣고 있다가 전달해준다.

 

@Service
public class KafkaProducerService {

    @Autowired
    private KafkaTemplate<String, String> kafkaTemplate;

    public void sendMessage(String message) {
        System.out.println("메세지 전송 : " + message);
        this.kafkaTemplate.send("Game", message);
    }
}

 

KafkaTemplate는 KafkaProducer를 감싸고 있는 인스턴스이다. 이를 통해 메세지를 송신할 수 있다.

 

@RestController
public class KafkaProducerController {

    @Autowired
    private KafkaProducerService kafkaProducerService;

    @PostMapping(value = "/message")
    public void sendMessage(String message) {
        kafkaProducerService.sendMessage(message);
    }
}

 

@PostMapping으로 해당 주소에 메세지를 보낼 것이다.

 

POSTMAN

 

intellij 실행 화면

 

Postman으로 요청을 보낸 결과 Consumer에게 잘 전달된 것을 볼 수 있다.

 

 

 

 

 

* 아래의 자료들을 참고하였습니다.

 

Message Queue

Message Queue는 대용량의 데이터를 처리하기 위해 분산 처리할때 쓰는 것이다. 또한, 프로세스 또는 프로그램 간에 데이터를 교환할 때 사용하는 통신 방법 중에 하나이다.

velog.io

 

[Tech] RabbitMQ와 Kafka의 차이? 메시지 브로커와 이벤트 스트리밍 플랫폼

아래 글을 참고하여 작성하였습니다. 더보기 https://www.koyeb.com/blog/rabbitmq-vs-apache-kafka-comparing-message-brokers-and-modern-event-streaming-platforms https://www.instaclustr.com/blog/rabbitmq-vs-kafka/ 어플리케이션과 시스

programming-workspace.tistory.com

 

Kafka 이벤트 스트리밍 이해하기

Kafka 학습 목적으로 전체 내용은 링크된 도서를 참고하여 카프카 핵심가이드 - 제이펍 출판사 - 심재철 옮김 글을 정리하였습니다 Kafka 는 이미 많은 기업에서 사용되고 있다 포춘 500대 기업 중 1/

wjjeong.tistory.com

 

Putting Apache Kafka To Use: A Practical Guide To Building an Event Streaming Platform (Part 1) | Confluent

Putting Apache Kafka To Use: A Practical Guide to Building an Event Streaming Platform.

www.confluent.io

 

Apache Kafka(아파치 카프카)란 무엇인가?

기존 링크드인의 데이터 처리 시스템은 각 파이프라인이 파편화되고 시스템 복잡도가 높아 새로운 시스템을 확장하기 어려운 상황이였음기존 메시징 큐 시스템인 ActiveMQ를 사용했지만, 링크드

velog.io

 

Springboot + Kafka 연동하여 pub/sub 구현 예제

지난 시간에는 kafka를 설치하여 topic을 발행하고 producer가 메세지를 보내고 consumer가 메세지를 받는 것을 예제를 통해 알아보았다. 이번에는 kafka를 테스트를 했던 CLI 환경이 아닌 springboot app에서

oingdaddy.tistory.com

댓글