본문 바로가기

개발/Spring Cloud

Spring Cloud Stream 사용해보기 1

  1. 개요
  2. Object와 MSA
  3. 메시지 주도 MSA
  4. 메시지 브로커
  5. RabbitMQ vs Apache Kafka

 

개요

이번에는 Spring Cloud Stream의 기능과 사용법에 대해서 설명하도록 하겠습니다.

Spring Cloud StreamRabbitMQ, Apache Kafka 등과 같은 메시지 브로커와 연결할 수 있는 공통 기능을 제공해 줍니다. 이것은 각기 다른 메시지 브로커들을 하나의 인터페이스로 사용할 수 있게끔 추상화시킨 라이브러리라고 할 수 있습니다. 이 때문에 어떤 종류의 메시지 브로커를 사용하는지와 상관없이 항상 동일한 소스 코드를 이용해 동일한 메시지 전송을 구현할 수 있게 해 줍니다.

Spring Cloud Stream 은 메시지 브로커의 종류와 상관없이 동일한 인터페이스로 메시지를 전송할 수 있는 기능을 제공합니다.

Spring Cloud Stream 은 메시지 전송을 위해 별도로 새롭게 만들어진 라이브러리는 아니고 기존은 Spring MessagingSpring Integration과 같은 라이브러리 기반에서 동작이 됩니다.


메시지와 Object

먼저 Spring Cloud Stream를 설명하기에 앞서 OOP에서 Object와 메시지에 대해서 이야기해 보겠습니다. 이는 메시지를 설명하는 데 있어 Object의 구조와 추상화에 대해 이해하는 것이 중요하기 때문입니다.

Object 란 내가 이해하는 수준으로 대상을 적절히 추상화하는 과정을 거쳐, 만들어진 어떤 개념적인 '형태(타입이라고 정의되는 역할)'를 의미합니다. Object는 단독으로 동작하지 않으며 서로 '협력'을 통해 어떤 결과를 만들어 내는데 이때 협력하기 위해 Object에 정의된 '책임' 즉 정의된 인터페이스를 통해 동작됩니다.

이것은 다르게 이야기하자면 Object 간의 협력은 서로에게 메시지가 전송이 되면서 동작된다는 의미입니다. OOP 언어 중 대표되는 JAVA라는 언어는 이 메시지를 처리하기 위한 방법으로 함수를 사용하고 있지만 다른 언어 (Smalltalk 과 같은 언어)에서는 메시지를 좀 더 메시지로서 취급하기도 합니다.

결국 Object는 정의한 인터페이스 즉 메시지를 주고받으면서 동작이 되며 이때 상대 Object의 내부 구현은 관심 대상이 아닙니다. 단지 '이렇게 처리해줘'라고 메시지를 전송하면 그것을 처리해 줄 것을 기대하고 메시지를 전송할 뿐이죠.

Object로 정의된 타입 (역할)에 정의된 메시지 (인터페이스)를 전달해 서로 협력하여 동작합니다

 

메시지 주도 MSA

앞서 Object의 이야기를 왜 장황하게 했느냐 하면 Object 들은 서로 메시지를 주고받으며 동작된다는 점을 설명하고자 함 이었습니다. 메시지가 서로 협력하는 기본 단위가 된다는 것입니다.

이를 마이크로 서비스 아키텍처 (Microservices architecture, MSA)에 대입해서 이야기해 보겠습니다. MSA는 프로젝트가 거대해지면서 하나의 모놀로식 (Monolithic) 형태의 시스템으로는 변경관리가 어려우므로 별도의 작은 서비스로서 업무 모듈을 분리해 개발하는 개발 방식입니다. 이것은 예전에 대두되었던 서비스 지향 아키텍처 (Service Oriented Architecture, SOA)와 개념적으로 상당히 유사한데 사실상 실패로 돌아간 SOA 개발방식이 지금은 가능해진 이유는 예전보다 물리적인 장비의 비용이 줄어들었고 Spring Cloud와 같은 여러 라이브러리가 등장하였기 때문입니다.

모놀로식 개발에서 MSA 개발 방식으로 전환할 때 MSA의 단위를 어떻게 분리할 것인지에 대한 부분이 중요한데 대부분의 경우 업무 단위로 연관이 있는 부분의 기능을 모듈 형태로 분리하게 됩니다. 이때 이렇게 분리된 모듈을 적절히 추상화하는 과정을 거치게 됩니다. 마치 Object를 설계할 때처럼 말이죠.

OOP에서 Object를 도출하는 방법과 MSA의 업무 모듈 서비스를 도출하는 방법은 결국 크게 다르지 않습니다. 단지 인터페이스가 훨씬 많고 단위가 훨씬 클 뿐이죠. 특정 도메인을 추상화한다는 점에서는 동일합니다.

특정 도메인에서 추상화 과정을 거쳐 개념적인 형태를 도출한다는 점에서 OOP의 Object 설계와 MSA의 서비스 설계는 유사합니다.

MSA를 설계할 때 이처럼 메시지를 이벤트로 하는 메시지 주도 방식의 설계가 아주 중요한데 서로 다른 업무 서비스 간의 느슨한 결합을 가지게 설계할 수 있기 때문입니다. 느슨한 결합으로 설계한다는 것은 특정 서비스가 다른 서비스에 종속이 되는 것을 방지하여 개별적인 모듈의 변경에 대한 영향이 없이 빠르게 개선을 할 수 있게 할 수 있다는 이야기입니다.

MSA를 메시지 주도 방식으로 설계를 할 때 얻는 또 다른 이점은 장애 시 발생되는 책임의 소재가 명확하다는 점에 있습니다. 만약 어떤 요청에 문제가 발생이 되었다면 모놀로식 형태의 서비스라면 요청 부분부터 처리 부분까지 모든 부분에 있어 문제가 될 여지를 살펴봐야 했지만 메시지 주도 방식에선 메시지를 수신하는 쪽의 문제만 확인하면 되기 때문에 상대적으로 디버깅이 용이하다는 장점이 있습니다.

이렇게 모듈 서비스 간의 느슨한 결합은 특정 서비스에 종속되지 않기 때문에 수평 확장에 유리하다는 장점이 있습니다.

메시지 주도 개발 방식으로 메시지를 발송한다는 것은 이벤트가 발생이 되다는 것이고 이 이벤트가 어떻게 처리되는지와 상관없이 발송하는 부분과 이벤트를 처리하는 책임이 분리가 되어 서비스 간의 느슨한 결합이 가능하게 됩니다.

 

메시지 브로커

메시지 브로커는 메시지를 전달을 요청받아 발행-구독 방식으로 특정하게 지정된 수신자가 아닌 구독하고 있는 모든 대상자에게 동일한 메시지를 전달해 주는 메시지 미들웨어를 의미합니다. 대체로 Apache KafkaRabbitMQ와 같은 Message Queue 시스템이 이를 의미합니다.

중요한 기능으로서 어떤 메시지 브로커를 선택하더라도 적어도 한번은 전달 (At-least-once delivery)이라는 기능을 제공해 줍니다. 적어도 한번은 전달은 메시지 손실, 느린 반응, 수신 장애, 수신 응답 실패 등 일반적으로 발생될 수 있는 문제에 대해서 정상적인 응답이 있을 때까지 끈질기게 메시지 브로커가 재발신하여 어떤 형태로든 서비스에 반드시 한번은 수신이 된다는 것을 보장해 준다는 것을 의미합니다.

하지만 메시지를 수신하는 구독 서비스 입장에서는 시간차를 두고 언제든 다시 재 발신한 동일한 메시지가 수신될 수도 있기 때문에 멱등 수신자 패턴을 적용하여 같은 메시지에 대해서는 같은 결과가 항상 보장되도록 해야 합니다.

메시지 브로커를 이용해 각기 다른 MSA 모듈 서비스 간에 생기는 이벤트(메시지)들을 어떤 순간에도 손실 없이 정확하게 전송하여 시스템의 안정성을 보장해 줌으로 인해 물리적으로는 분리되어 있는 시스템이지만 마치 하나의 단일 서비스처럼 동작될 수 있게 해 줍니다.


 

RabbitMQ vs Apache Kafka

이제 사용하기 위한 메시지 브로커를 선정할 차례입니다. 여러 종류의 Message Queue 가 있지만 크게 RabbitMQ와 Kafka 이렇게 두 종류의 메시지 브로커가 보편적으로 사용이 됩니다. 둘을 비교해 보자면 조금 더 성능이 중요하다면 Kafka를 다양한 형태의 메시지 처리를 해야 된다면 RabbitMQ를 사용하는 것으로 나뉠 수 있는데 Spring Cloud Stream을 사용한다면 동일한 인터페이스를 사용하므로 어떤 메시지 브로커를 선택하더라도 사용하는 입장에서는 사실상 차이가 없다고 할 수 있습니다.

message queue 종류

 

  • Apache Kafka
    • 메시지를 보내는 쪽에 특화되어 있으며 전달한 메시지가 정상적으로 전달되었는지를 브로커가 기록하지 않는다.
    • 이 때문에 상대적으로 메시지 포맷이 단순해 대용량 실시간 로그 처리에 특화되어 있다.
    • AMQP 프로토콜이나 JMS를 사용하지 않고 TCP 기반의 프로토콜을 사용해 오버헤드가 적다.
    • 분산 처리를 기본으로 설계되어 있어 분산 복제나 파티셔닝 구성이 쉽다.
  • RabbitMQ
    • AMQP (Advanced Message Queue Protocol)을 지원해 메시지를 전송한다.
    • 메시지를 보내고 나서 정상적으로 전달되었는지를 브로커가 관리한다.
    • 메시지 포맷이 상대적으로 복잡하나 이 때문에 다양한 형태의 범용 메시지를 전송할 수 있다.

<다음에 계속>

'개발 > Spring Cloud' 카테고리의 다른 글

Spring Cloud Stream 사용해보기 1  (0) 2019.09.23