[대규모 서비스] MOM, MQ, AMQP에 대하여

D A S H B O A R D
D E V E L O P
S E C U R I T Y
 MOM
 MQ
 AMQP
 AMQP의 컴포넌트
 Connection vs Channel
 Virtual Host
 Standard Exchange Type
Reference

 MOM (Message Oriented Middleware)

이름에서 알 수 있듯이 소프트웨어(어플리케이션)간의 메시지를 중간에서 관리(교환)해주는 역할을 한다는 것을 알 수 있다. 또한, 메시지를 통해 분산된 여러 시스템간의 다리 역할을 하며, 결합성을 낮추고 비동기식으로 데이터를 교환할 수 있도록 해준다.
정리하자면 아래와 같다.

정리

여러 클라이언트 시스템간에 메시지 통신을 중간에서 관리해줌 → 시스템간 종속성 및 결합성 ↓
주고 받는 메시지를 데이터베이스 등에 기록하는 등 백업 → 안정성 ↑
라우팅 규칙을 활용하여 하나의 메시지로도 특정 여러 클라이언트가 받을 수 있도록 지원
이들이 서로 실시간 비동기식 데이터를 교환할 수 있도록 하는 소프트웨어
Queue, Broadcast, Multicast 등의 방식으로 메세지를 전달
메세지를 발행하는 Publisher (Producer), 소비하는 Subscribe (Consumer)로 구성

단점

중앙에서 메시지를 관리할 수 있는 주체가 필요하기 때문에 이에 대한 도입 비용, 운영 비용 등 고려 → 메시지 전체를 관리하는 시스템이 따로 필요
송수신자가 직접 통신하는게 아니므로 다수의 서버가 MOM을 활용하게 되면 구조가 전체적으로 복잡해지고, 이에 대한 오버헤드가 발생 → 전체적인 시스템 구조가 복잡해질 가능성
미들웨어란?
미들웨어란 Middle + (soft)ware 로 소프트웨어 중간에서 상호작용을 하도록 도와주는 것을 말한다. 예를 들어 Spring에서 DB와 JAVA 서버를 연결해 주는 JDBC가 있다.

 MQ (Message Queue)

프로세스 또는 프로그램 인스턴스가 데이터를 서로 교환할 때 사용하는 통신 방법
더 큰 개념으로는 메세지 지향 미들웨어(MOM:Message Oriented Middleware)를 구현한 시스템을 의미
Producer, Consumer가 존재하며 Producer는 메세지를 큐에 전송하고 Consumer가 큐의 메세지를 처리하는 방식
MQ를 사용하면 비동기로 요청을 처리하고 Queue에 저장하여 Consumer에게 병목을 줄여줄 수 있음

장점

비동기(Asynchronous) : 큐(Queue)에 넣기 때문에 나중에 처리할 수 있다.
비동조(Decoupling) : 애플리케이션(Application)과 분리할 수 있다.
탄력성(Resilience) : 일부가 실패 시 전체에 영향을 받지 않습니다.
과잉(Redundancy) : 실패할 경우 재실행 가능합니다.
보증(Guarantees) : 작업이 처리된걸 확인할 수 있습니다.
확장성(Scalable) : 다수의 프로세스들이 큐에 메시지를 보낼 수 있습니다.

단점

큐가 가득찼을 경우, 메시지를 더 이상 저장하지 못하기 때문에, 메시지를 버리거나 다른 곳에 저장한다.
메시지 큐의 크기는 생각보다 작기 때문에 송신측이 수신측보다 빠르다면 문제가 자주 발생할 소지
큐가 가득찼을 경우 어디에 저장?!
오래된 메시지 삭제
메시지를 백업 스토리지로 이동
오류 및 알림 처리

사용 이유

서버부하가 많은 작업 - 지연처리
이미지 처리, 비디오 인코딩, 대용량 데이터 처리와 같은 작업을 할 때 MQ에 넣어두고 동시에 처리할 수 있을만큼만 가지고와서 처리하는 방법
부하 분산
여러 서비스가 하나의 MQ를 바라보도록 설계할 경우 각각의 서비스는 자신이 처리 가능한 처리량에 맞게 가지고와 처리함
데이터 손실 방지
만약 서버가 다운될 경우 메모리에 저장된 메시지가 모두 사라지는 경우가 있다. 이를 MQ를 사용한다면 이를 방지할 수 있음
MQ로부터 가져온 데이터를 일정 기간동안 처리했다고 MQ에 알려주지 않았을 경우 MQ는 해당 메시지를 다시 가지고와 다시 처리할 수 있도록 도와줌

 AMQP(Advanced Message Queuing Protocol)

AMQP는 MOM의 개방형 표준으로, 응용 계층 프로토콜이다. 이는, MQ는 플랫폼에 종속적인 제품들이 많아 이기종 간에 메시지를 교환하기 위해서는 메시지 포맷 변경을 위한 메시지 브릿지 이용 및 시스템 자체를 통일 시켜야 하는 불편함 존재한다.
이렇듯 메시지 브릿지를 이용하면 속도 저하가 발생하는 등의 문제가 생긴다.
이를 해결하기 위해 나온 것이 바로 AMQP다!!
특정 플랫폼에 종속되지 않기 위해 3가지 조건을 충족해야 함
모든 Broker들은 똑같은 방식으로 동작 할 것
모든 Client들은 똑같은 방식으로 동작 할 것
네트워크 상으로 전송되는 명령어들의 표준화

 AMQP의 컴포넌트

Producer
Message 를 Consumer 에게 전달하기 위해 Message 를 Exchange 에 Publish 합니다.
Message 를 보내는 일 이외에는 아무것도 하지 않습니다.
Queue 에 직접 접근하지 않고, 항상 Exchange 를 통해 접근
Binding
Exchange와 Queue의 mapping. 1:1 또는 1:N
전달 받은 메시지를 원하는 Queue 로 전달하기 위해 Bindings 이라는 규칙을 정의
Exchange
Publisher로 부터 수신한 메시지를 적절한 Queue 또는 다른 Exchange로 분배하는 라우팅 기능 수행
Broker는 여러개의 exchange type 인스턴스를 가질 수 있음
exchange type : Binding과 메시지를 매칭 시키기 위한 라우팅 알고리즘을 정의, 메시지를 어떤 방법으로 라우팅 시킬지를 결정
Queue
메모리나 디스크에 메시지를 저장하고, 그것을 Consumer에게 전달하는 역할을 함
Queue는 스스로가 관심있는 메시지 타입을 지정한 Binding을 통해 exchange에 binding 됨
Routing Key
Publisher에서 송신한 메시지 헤더에 포함되는 일종의 가상 주소
Exchange는 Routing Key를 이용해서 어떤 Queue로 메시지를 Routing 할지 결정
Standard Exchange Type
대부분 MQ(Message Queue)에서 가능한 여러가지 상황에 대해 AMQP에서 정의한 표준 라우팅 알고리즘
Virtual Host
Broker 내의 가상 영역
Connection
클라이언트가 RabbitMQ 브로커와 상호 작용하기 위해 취해야 하는 첫 번째 단계는 연결을 설정
발행자와 소비자, Broker 사이의 물리적인 연결
일반 TCP 연결이거나 TLS를 사용하는 암호화된 연결
Channels
발행자와 소비자, Broker 사이의 논리적인 연결, 하나의 Connectoin 내에 다수의 Channel 설정 가능
Consumer
Message 를 수신하는 주체입니다.
Queue 에 직접 접근하여 Message 를 가지고 옵니다.
바인딩? 라우팅 키?
Binding Key는 어떤 큐에 어떠한 데이터를 넣을지에 대한 규칙을 정의 하는 것이라 보면 쉬움
Routing Key는 Binding Key와 매칭되는 곳으로 Routing 하기위해 메시지 헤더에 존재

 Connection vs Channel

Connection 일반적 특징

RabbitMQ에서 지원하는 모든 프로토콜은 TCP 기반
효율성을 위해 긴 연결을 가정 (AMQP 프로토콜 작업당 새 연결이 열리지 않음.)
하나의 클라이언트 연결은 단일 TCP 연결을 사용함
클라이언트가 연결을 성공하려면, RabbitMQ 대상 노드는 특정 프로토콜에 대한 연결을 허용해야 함
연결은 오래 지속되어야 하기 때문에 일반적으로 구독을 등록하고, 폴링 대신에 메시지를 전달하여 소비
연결이 더 이상 필요하지 않은 경우, 리소스 절약을 위해 연결을 닫아야 한다. 이를 수행하지 못하는 클라이언트는 리소스의 대상 노드를 고갈시킬 위험이 있음
기본 TCP 연결을 갑자기 닫는 대신 AMQP 0-9-1 연결을 정상적으로 닫아야 함
AMQP 0-9-1 버전 프로토콜의 특징
단일 TCP 연결을 통해 다중화 연결 방법을 제공한다.
단일 연결에 대한 채널을 통해 여려 경량 연결을 열 수 있다.
즉, AMQP 0-9-1 버전의 프로토콜을 사용하고 있는 클라이언트는 단일 TCP 연결 후, 하나 이상의 채널에서 메시지 전달, 소비, 관리 작업을 수행할 수 있다.

Channel 일반적 특징

AMQP 0-9-1 연결은 “단일 TCP 연결을 공유하는 경량 연결”로 생각할 수있는 채널 과 함께 다중화
단일 연결 위에 여러 논리 흐름을 다중화한다는 의미
클라이언트가 수행하는 모든 프로토콜 작업은 채널에서 발생
채널 안에 연결할 Queue를 선언할 수 있으며, 채널 하나당 하나의 Queue만 선언이 가능
특정 채널의 통신은 다른 채널의 통신과 완전히 분리되어 있기 때문에 프로토콜은 채널 ID와 같은 식별자를 포함시켜 전달
채널 ID를 통해 클라이언트나 브로커 모두 채널에 대한 파악이 가능
채널은 Connection Context에만 존재하기 때문에 Connection이 닫히면, 연결된 모든 채널도 닫힘
클라이언트에서 처리를 위해 멀티 프로세스/스레드를 사용한다면, 프로세스/스레드 별로 새 채널을 열고 공유하지 않는 것이 일반적
Channel 다중화 이유
연결 설정은 상대적으로 비용이 많이 드는 작업이기 때문에 클라이언트와 서버 측 모두에서 리소스를 더 잘 사용할 수 있음
많은 TCP 연결(Connection)을 동시에 열어두면 시스템 리소스가 소비되고 방화벽을 구성하기가 더 어려워 지므로 바람직하지 않기 때문

Connection Life Cycle

1.
클라이언트는 라이브러리를 사용해서 Host와 Port 정보를 통해연결 정보를 구성
2.
라이브러리는 HostName을 하나 이상의 IP Address로 확인
3.
라이브러리는 대상 IP Address 및 Port에 대한 TCP 연결
4.
서버가 TCP 연결을 수락한 후 프로토콜별 협상 절차가 수행
5.
그런 다음 서버는 클라이언트를 인증
6.
클라이언트는 이제 작업을 수행할 수 있으며, 각 작업에는 서버의 권한 부여 확인이 포함
AMQP 0-9-1 버전 프로토콜의 Connection Life Cycle
연결 및 채널이 포함된 모델이 있고, 채널은 연결 멀티플렉싱을 허용한다. (TCP 연결에 여러 논리적 연결을 가짐.)
연결에서 동시에 열 수 있는 최대 채널 수는 연결 시, 클라이언트와 서버가 협상
클라이언트는 서버에서 구성한 최댓값보다 많은 채널을 허용하도록 구성할 수 없음
성공적으로 연결을 열고 인증한 후, 응용 프로그램은 하나 이상의 채널을 열고, 이를 사용하여 프로토콜 작업을 수행

Channel Life Cycle

OPEN
1.
클라이언트는 연결을 성공적으로 연 후, 채널을 오픈
2.
새 채널을 열게 되면, 자동으로 채널 ID가 할당
3.
Connection과 마찬가지로 채널은 지속적으로 열린 상태여야 함
4.
작업마다 채널을 여는 작업은 네트워크 왕복의 비용이 들기 때문에 매우 비효율적
CLOSE
채널이 더 이상 필요하지 않으면 닫아야 함
채널을 닫으면 채널을 사용할 수 없게 되고, 해당 리소스를 회수하도록 예약하는 방식으로 처리
Connection vs Channel
Connection은 물리적인 연결
Connection은 단일 TCP 연결만 가능
AMQP 0-9-1 버전의 프로토콜을 사용하는 Connection의 경우, Channel이라는 경량 연결을 포함
Channel은 Connection Context를 공유하며, 하나 이상의 경량 연결이 가능
Channel 하나당 하나의 Queue만 연결이 가능

 Virtual Host

하나의 RabbitMQ 브로커에서 여러 개의 메시지 도메인을 사용할 수 있게 해 주는 논리적 그룹을 의미 → 논리적 분리
각각의 vhost는 Queue, Exchange, Binding, 권한에 있어서 완전히 분리된 메시징 환경을 가짐 → 각 사용자마다 격리된 환경 제공
vhost는 하나의 브로커에서 여러 메시징 도메인을 가능하게 하는 논리적 컨테이너이며 이들 간의 분리와 메시징 트래픽을 컨트롤을 관리 유지

 Standard Exchange Type

Direct Exchange

라우팅 키가 정확히 일치하는 Queue에 메시지 전송
Message의 routing_key를 Queue에 1:N으로 매칭 시키는 방법(유니케스트 및 멀티케스트)
만약 라우팅 키가 일치하는 바인딩된 큐가 없다면 메시지가 무시된다.
Default Exchange?
Default Exchange 는 이름이 없는 Direct Exchange 한 형태
Default Exchange 는 전달될 목적지 Queue 이름과 동일한 Routing Key 를 부여
쉽게 말하면 Routing 키가 큐의 이름!!!

Topic Exchange

와일드카드를 이용해 Message를 Queue에 매칭하는 방법(Multicast)
routing_key는 "."으로 구분된 0개 이상의 단어 집합으로 간주하고, 와일드 카드 문자들을 이용해서 특정 Queue에 Binding 한다.
와일드 카드
* (start) : 하나의 단어를 의미
# (hash) : 0개 이상의 단어를 의미.
"#" 만 Binding 하면, 모든 routing_key를 수신한다는 의미로 Fanout Exchange와 동일한 동작 수행

Fanout Exchange

모든 메시지를 모든 Queue로 라우팅 하는 유형(Broadcast)

Headers Exchange

Topic과 유사한 방법이지만 라우팅을 위해 header를 사용한다는 점에서 차이
producer에서 정의된 header의 key-value 쌍과 consumer에서 정의된 argument의 key-value 쌍이 일치하면 binding
And(all) 와 or(any) 선택 가능
binding key 만을 사용하는 것보다 더 다양한 속성을 사용 가능
이 타입을 사용하면 binding key는 무시되고, 바인딩 시 지정된 값과 헤더 값이 같은 경우에만 일치하는 것으로 간주
key
value
description
x-match
all
header의 모든 key-value 쌍 값과 argument의 모든 key-value쌍 값이 일치할 때 binding - AND
x-match
any
argument의 key-value 쌍 값 중 하나라도 header의 key-value 쌍 값과 일치할 때 binding - OR