티스토리 뷰

반응형

RabbitMQ, Kafka를 들어보기도 하고, 사내에서 사용하기도 하다보니 찾아보며 공부하는 것이 좋겠다 싶어 이렇게 정리하게 되었습니다. 뭐, 대충 어떠한 역할을 하는지는 알고 있었지만, 제일 중요한 "왜 필요한지?"에 대해서는 확실히 대답하지 못하는 것 같아 찾아보며 공부해보고자 합니다.

 

 

RabbitMQ, Kafka 등 이러한 메세징 SW들을 찾다보니 이들을 이루는 구조, 이론 등이 있었고, 이를 먼저 정리해보고자 합니다. 3가지 단어가 자주 등장을 하는데요, 이걸 먼저 조금씩 알고 넘어갑시다.

  • MOM (Message Oriented Middleware): 메시지 미들웨어의 이론, 개념, 설계도를 의미
  • Message Queue: 메시지 큐에 대해선 어떻게 보냐에 따라 의견이 나뉘는 것 같습니다. 단순히 자료구조로써는 메시지들을 큐 형태로 다루는 구조를 의미합니다. 하지만 거의 더 나아가 MOM의 단순 구현체의 개념으로 사용하는 경우가 더 많은 것 같습니다. '애플리케이션 간의 메시지 큐를 통한 단순한 형태의 통신 솔루션'으로 말이죠. 다시 말해서, 메시지 전송을 위해 메시지 큐, 메시지 전송 구조를 가진 미들웨어로 볼 수 있습니다.
  • Message Broker: 메시지 브로커는 메시지 큐에서 더 확장된 기능을 가지고 있다고 봅니다. 더 광범위한 전송, 메시지 내용을 통한 라우팅 및 추가/고급 기능 등을 지원하고, 구현체 별로 어떤 방식을 통해 메시지를 전달하고, 내부 구조를 어떻게 구현했는가에 따라 동작하는 방식, 목적, 성능이 달라집니다.

 

 

위 정보는 여러 웹 상의 개념들을 모아서 작성했습니다. 읽으신 분들은 아시겠지만, 사실 Message Queue와 Message Broker의 의미차이가 모호합니다.

사실 그래서 저는 Message Queue, Message Broker를 딱 어떤 기준으로 나눈다기 보다 둘을 융합해서 보는 것이 더 이해하기도 생각하기도 좋다고 생각합니다. 사람마다 다를테지만요. 그래서 이번 정리 글에서는 이 둘의 차이에 너무 집중하지 마셨으면 좋겠습니다.

 

 

여기서부턴 RabbitMQ, Kafka 같은 메시징 미들웨어를 다룰 땐 Message broker라 칭하겠습니다.

  • 'RabbitMQ(MessageQueue)니깐 MQ라고 불러야지!' 라고 하시는 분이 있을리 없지만.... RabbitMQ 공식 홈페이지에선 RabbitMQ is the most widely deployed open source message broker. 로 Message broker임을 나타내고 있습니다. (그러니 그냥 봐주세요 ☺️ )

 

MOM (Message Oriented Middleware)

 

https://docs.oracle.com/cd/E19798-01/821-1798/aeraq/index.html

 

Message Broker에 대해 알아가기전에 MOM. 즉, 메시지 지향 미들웨어부터 알아봅시다.

 

이름에서부터 역할을 알 수 있듯, 어플리케이션들의 메시지를 중간에서 관리해주는 시스템입니다.

  • 여러 클라이언트 시스템간에 메시지 통신을 중간에서 관리해줌으로써 클라이언트 시스템간의 종속성 및 결속성을 낮춰줍니다. 메시지를 보내는 이는 받는 이의 주소를 몰라도 보낼 수 있게 됩니다.
  • 주고 받는 메시지를 데이터베이스 등에 기록하는 등 백업 할 수 있기에 안정성을 높여줍니다.
  • 라우팅 규칙을 활용하여 하나의 메시지로도 특정 여러 클라이언트가 받을 수 있도록 지원합니다.

 

 

물론, 단점도 존재합니다.

  • 메시지 전체를 관리하는 시스템이 따로 필요합니다. 중앙에서 메시지를 관리할 수 있는 주체가 필요하기 때문에 이에 대한 도입 비용, 운영 비용 등 고려해야합니다.
  • 당연히 전체적인 시스템 구조가 복잡해질 수 있습니다. 송수신자가 직접 통신하는게 아니므로 다수의 서버가 MOM을 활용하게 되면 구조가 전체적으로 복잡해지고, 이에 대한 오버헤드가 발생할 수 있습니다.

 

 

앞에서 말했듯 MOM은 이론, 개념, 설계적인 방향성을 제시하고 있다고 보면 됩니다. 직접적인 구현체는 아닙니다.

MOM 시스템을 두고 여러 계층에서의 표준 및 프로토콜이 등장하게 됩니다.

 

 

또한 이러한 MOM의 개념과 표준 및 프로토콜을 활용하여 다양한 구현체들이 등장하였습니다. 메시징 미들웨어(브로커)라는 것에는 다름이 없으나 내부적으로 동작하는 방식, 프로토콜, 제공하는 기능, 성능 등 차이점이 존재합니다.


근데 왜 사용하는 걸까?

위에서 MOM의 개념과 장단점, 그리고 이를 활용한 프로토콜이라던지, 구현체들을 살펴보았는데요. 특히 구현체들 중 RabbitMQ, Kafka는 많은 기업에서 활용하고 있어 어디선가 들어본 적이 있으실 겁니다. (개발자 구인공고에 우대사항으로 있는 경우가 많더라구요 😅)

 

 

위 MOM 장단점에서 간단히 살펴보았지만, 다시 짚어 넘어가고 싶은 것이 있습니다. 이런 메시징 브로커... 도대체 왜 사용하는 걸까요?

 

먼저 제가 이런 생각을 하게 된 계기를 말씀드리겠습니다 (무식한 것 같아도 욕하지 말아주세요😥). 저는 일단 개발자 0년차구요, 취업한 후 처음으로 메시징 브로커를 접했습니다. 그러다 보니 "아, 중간(미들웨어)에 위치하면서 메시지를 받아 전달 또는 가져갈 수 있게 큐를 구성하고 있는 하나의 서버로 생각하면 되겠구나" 라고 이해했습니다.

 

 

근데 보다보면 한 가지 궁금한 점이 들었는데요.

수신자와 송신자가 있을 때, "왜 굳이 메시지 미들웨어를 사용하는거지? 왜 송신자는 수신자에게 바로 보내면 안되고, 수신자는 송신자로부터 바로 못받나?"라는 궁금증이요. 그리고 여기서 더 나아가 "그래, 송신자가 메시지를 너무 많이보내면 수신자가 터질 수 있겠구나" 라는 생각으로 흘러갔다가 "엥, 근데 송신자가 너무 많이보내서 터지는건 메시지 브로커도 마찬가지 아닌가? 🤔" , "아, 그럼 메시지 브로커는 고성능 서버를 사용안해서 안터지나? 엥,,, 근데 그럴 거면 수신자를 고성능 서버로 사용했으면 되는거 아닌가?" 까지 왔습니다.

 

 

그래서 위 생각을 정리하자면

  • "왜 굳이 메시지 브로커(미들웨어)를 사용하는거지? 왜 송신자는 수신자에게 바로 보내면 안되고, 수신자는 송신자로부터 바로 못받나?"
  • → "그래, 송신자가 메시지를 너무 많이보내면 수신자가 터질 수 있겠구나"
  • → "엥, 근데 송신자가 너무 많이보내서 터지는건 메시지 브로커도 마찬가지 아닌가? 🤔"
  • → "아, 그럼 메시지 브로커는 고성능 서버를 사용안해서 안터지나? 엥,,, 근데 그럴 거면 수신자를 고성능 서버로 사용했으면 되는거 아닌가?"

이렇습니다.

즉, 이러한 생각의 흐름은 첫 질문으로 다시 돌아오게 되었습니다. "메시지 브로커가 왜.필.요.한.거.야 !"

 


 

그럼, 진짜 왜 사용하는 것인가?

사용하는 이유는 3가지로 나누어 말할 수 있습니다.

  1. 서비스(어플리케이션) 간의 의존성 제거
  2. 메시지 처리 시점
  3. 다양하고 유연한 통신

 


서비스 간의 의존성 제거

간단한 예제를 들어볼까요?

위와 같이 간단히 송신자와 수신자가 존재합니다. 특정 업무를 위해 메시지를 전송하고 있다고 하겠습니다. 사용자가 적은 단순한 서비스라면 위의 구조로도 잘 작동할 것입니다. 송신자가 직접 수신자의 주소 정보를 알고, 해당 주소로 메시지를 보내면 되니깐요.

 

하지만 사용자가 많아져 서버를 늘리는 상황(Scale-out)이 되었습니다. 다음 그림처럼 송신 및 수신 측 둘 다 서버를 늘렸다고 합시다. 이런 경우에는 송신측에서 수신측으로 메시지를 잘 전달할 수 있을까요?

 

 

뭐... 각 송신측 서버에 접속해서 수신측 주소를 입력해주거나 하면 운영이 ... 뭐 될 수야 있겠죠.

 

하지만 매우 수고로운 일이면서, Cloud platform을 사용한다면 수신측의 주소는 서버가 늘어났다 줄어드는 상황이 많아 사람이 할 수 있는 일이 아닐 수 있겠죠 (인력의 운영비용이 엄청나게 증가하겠죠?). 이러한 문제를 서비스 검색이 불가능하다고 할 수 있습니다.

 

 

또, 다시 첫 예제상황으로 돌아와봅시다. 만약 수신 측 문제가 있어 정상적으로 동작하지 않는 상황이라면 어떨까요?

당연히도 송신 측에서 오류가 발생할 것입니다. 제대로 된 전송이 불가능하니 말이죠.

 

이 부분에서 동기(Synchronous) 방식으로 메시지 전송을 했다면 더 큰 오류가 발생할 수 있습니다. 송신 측은 Response를 받을 때까지 대기를 하게 될 텐데 수신 측 서버가 정상적으로 동작하지 않아 정해 둔 timeout 시간까지 기다리기만 하게 될 것입니다. 이런 상황 속에서 계속해서 송신 측에 request가 들어오게 되면 요청들이 쌓이게 되고 송신 측 서버마저 문제가 생길 수 있습니다.

  • 송신 측 서버가 문제가 생기면 송신 측 서버에 Request를 보내는 서버들도 또 비슷한 문제가 발생할 수 있습니다. 이를 장애 전파 라고 합니다. 이러한 장애전파를 막기 위해선 Circuit breaker, fall-back 등을 활용해야 합니다.

 

비동기(Asynchronous) 방식으로 메시지를 전송했다면 위와 같은 문제는 없을지라도 메시지가 수신 측에 정상적으로 전달되지 않아 메시지가 없어지는 문제. 즉, 메시지의 전달이 보장되지 않는 문제가 발생하게 됩니다. 그렇기에 추후 수신 측 서버가 살아나더라도 죽었을 당시의 메시지들은 다 사라진 후일 것입니다.

 

 

이러한 문제를 봐서 아시겠지만, 메시지 브로커 없이는 송신 및 수신 서버가 모두 다 정상적으로 작동하는 상태여야만 메시지 전송이 정상적으로 동작하게 됩니다.

 

 

이 뿐 아니라 문제가 없는 상황에서도 메시지 전달은 보장되어야만 합니다. 이러한 메시지 보장에 대한 메커니즘을 전달 보장 메커니즘(Guaranteed delivery mechanism)이라고 하는데요. 메시지 브로커가 없는 상황에서는 송신 또는 수신측에 직접 구현을 해야할 것입니다. 이러한 메커니즘을 구현하기는 쉽지 않을 뿐더러 특정 어플리케이션 관계마다 구현해주기 더 쉽지 않겠죠.

 

 

 

앞서 살펴 본 문제들을 정리하자면 아래와 같습니다.

  • 서버의 수가 유동적이면 정상적으로 동작이 어려움 (서비스 검색 불가상황)
  • 송신 및 수신 서버가 모두 정상적으로 동작해야만 한다는 것
  • 전달 보장 메커니즘이 없거나 구현하기 어려움

저는 이러한 문제들이 서비스 간의 의존하고 있기에 발생하고 있다고 생각했고, 이를 어플리케이션의 의존성으로 인한 문제라고 이해했습니다.

 

 

메시지 브로커는 이러한 어플리케이션 의존성을 제거해줌으로써 앞선 문제들을 해결해주고 있습니다.

 

서버 수가 유동적이어도 정상적으로 동작합니다.

  • 송신 측 서버가 늘어나도 메시지 브로커의 주소만 알고 있다면, 메시지를 보내는데는 문제가 없습니다.
  • 수신 측 서버가 늘어나도 메시지 브로커의 주소만 알고 있다면, 메시지를 받아오는데는 문제가 없습니다.

수신 측 서버가 문제가 생겨도 정상적으로 동작합니다.

  • 송신 측이 메시지를 보내면, Message Broker는 메시지를 받아 큐에 저장해놓고 수신 측이 받아가길 기다립니다.
  • 수신 측 서버에 문제가 생겨 이 메시지를 받아가지 못하더라도 메시지 브로커에서는 정해둔 설정 값마다 다르겠지만 메시지를 유지하고 있습니다. 수신 측 서버가 정상적으로 돌아오면 그 유지해 두었던 메시지를 받아 올 수 있어 문제가 생겼던 기간의 메시지들도 받을 수 있습니다.

그럼, 만약 메시지 브로커 자체가 죽으면 어떻게 될까요?

  • 브로커 자체가 죽는다고 송신 및 수신 측 서버에 부담이 가지 않습니다. 메시지 전송의 출구만 없어질 뿐 그 자체의 서버 역할을 하고 있을 것입니다. 하지만 당연히도 메시지 전송 기능 자체에는 문제가 발생할 수 있습니다.
  • 하지만 메시지 브로커 서버는 일반 서버와 달리 메시지 전송과 메시지 큐 부분에만 집중을 둔 서버로서 고가용성을 목표로 만들어져있어 서버가 이상이 있을 위험이 더 적다고 합니다.

메시지 브로커들은 보통 전달 보장 메커니즘이 구현되어 있습니다.

 


메시지 처리 시점

앞서 제 생각 중 "송신자가 메시지를 많이 보내 수신자가 터진다"라는 이야기가 있었습니다.

그럼, 메시지 브로커가 있으면 이를 해결 할 수 있는 걸까요? 메시지 브로커는 단순히 메시지를 저장했다가 바로 수신측에 주는 것 아닐까요? 라는 궁금증이 생길 수 있습니다.

해당 궁금증대로라면 사실 메시지 브로커를 사용할 필요가 없었겠죠.

 

메시지 브로커에서는 수신 측에서 원하는 시점에 메시지를 가져갈 수 있도록 (처리할 수 있도록) 지원하고 있습니다. 여기서 원하는 시점이란 유동적일 수도 있겠지만 보통 수신 측이 메시지를 처리할 수 있는 시점을 의미합니다. 이러한 기능을 '메시지 버퍼링'이라고 부르기도 합니다.

다시 말해서, 메시지 브로커는 수신 측에서 처리 가능한 시점까지 메시지를 버퍼링 할 수 있는 것입니다.

 


 

다양하고 유연한 통신

또 예시를 들어봅시다. 아래와 같은 서버인 상황이라고 하죠. 특정 이벤트가 발생하면 수신 측에 메시지를 전달하는 구조입니다.

이 상황 속에서 기획 및 개발 구조 수정으로 송신 측의 메시지를 받을 수신 측 서버가 늘어나게 되었습니다. 아래와 같이 말이죠.

 

수신 측 서버의 개수는 2개일 수도, 3개일 수도, 많게는 10개일 수도 있습니다. 이러면 송신 측에선 어떻게 해야할까요?

 

 

만약 현재의 구조대로라면 내부 코드에서 수신 측 주소로 직접 요청하는 식으로 구현을 해두어야겠죠? 정말 많은 불편함이 있을 것이며, 어느때(서버의 대수가 유동적으로 변경되는 시점)가 되면 이게 불가능한 시점이 올 수도 있습니다.

 

 

이런 경우, 메시지 브로커를 활용한다면 문제를 해결할 수 있습니다.

그 전에 먼저 메시지 채널에 대한 개념을 알고 가야하는데요. 간단히 이 글을 보고 오시면 좋을 것 같습니다.

메시지 브로커에서는 다양한 메시지 채널 방식을 지원하고 있고, 점대점(point-to-point) 및 발행-구독(pub-sub) 채널은 보통 지원을 하고 있어 위에서 설명하던 구조를 쉽게 구현할 수 있습니다.

 

 

위에서 살펴 보았듯 기존 서버구조라면 해결하기 어렵거나, 해결하지 못하는 문제들을 '메시지 브로커'를 활용해 해결할 수 있었습니다. 이제 위에서 제가 했던 생각의 흐름들을 다 해결할 수 있었습니다.

한 가지 더 살펴보고 글을 마무리 하려고 합니다. 위에선 메시지 브로커가 왜 존재해야하는지, 어떤 장점들이 있었는지 살펴보았는데요. 메시지 브로커의 단점은 없을까요?

 


메시지 브로커의 단점

당연히도 단점이 존재합니다.

 

Bottleneck point(병목현상 지점)이 될 수 있습니다.

  • 많은 고객 수로 인해 서버들이 확장(Scale-out)하는 상황에서 만약 메시지 브로커는 기존 수 그대로 남아있다면, 늘어난 고객 수 및 서버 수의 요청을 같은 수의 메시지 브로커로 감당하는 것이므로 당연히도 병목현상이 발생할 수 있습니다. 메시지 큐에 메시지가 쌓이면서 요청을 처리하는 속도가 느려질 수 있습니다.
  • 하지만 최근 많은 메시지 브로커들이 확장이 가능한 구조로 설계되어 이러한 문제는 적어지고 있습니다. 서버 수의 증가에 따라 메시지 브로커의 수도 확장해나감으로서 문제를 해결할 수 있습니다.

메시지 브로커도 죽을 수 있습니다.

  • 앞서 말씀드렸듯 메시지 브로커도 죽을 수 있습니다. 메시지 브로커가 죽게되면 송신 및 수신 측의 커뮤니케이션이 불가능한 상태가 되므로 SPOF(Single Point Of Failure)가 될 수 있습니다.
  • 이러한 메시지 브로커의 문제를 이해해 서버 구조를 설계해야하며, 다행히도 요즘 메시지 브로커는 고가용성이 보장되도록 설계되었습니다.

메시지 브로커를 운영해야합니다.

  • 당연한 사실이겠지만, 일반 서버와 별개로 메시지 브로커(서버)를 운영해야합니다. 정상적으로 동작하는지 확인하거나, 알람 기능을 추가해 생성해야 한다거나, 버전을 꾸준히 업데이트 해줘야한다거나, 버전 업그레이드로 인한 문제가 발생하진 않는지 확인하는 등 여러 이슈들을 확인하고 해결해나가야 합니다.
  • 큰 조직 일수록 서버의 수가 많고, 운영하는 컴포넌트들이 많을텐데요. 이러한 메시지 브로커도 관리 및 운영을 해줘야하므로 운영비용이 증가하는 단점이 될 수 있겠습니다.

 


정리하며

 

이 주제로 글 쓰기를 준비하고, 자료를 정리하고, 직접 글을 쓰기 시작하며 생각이 많이 정리된 것 같습니다.

읽는 여러분들도 그러셨으면 좋겠네요. 글을 다 읽으셨을테니 한번 더 생각해봅시다. "메시지 브로커가 왜 필요할까요?"

 

References

320x100
반응형
댓글
반응형
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함