Message Queue

rxxhx·2023년 12월 10일
0
post-thumbnail

1. Message Queue의 개념

  • 메시지 지향 미들웨어 (Message Oriented Middleware: MOM)
    • 비동기 메시지를 사용하는 다른 응용 프로그램 사이에서 데이터 송수신을 의미합니다.
    • 여기서 메시지란, 요청/응답/오류 메시지 혹은 단순한 정보 등의 작은 데이터가 될 수 있습니다.
    • 이러한 MOM을 구현한 시스템을 메시지 큐 (MessageQueue:MQ)라 합니다.
  • 메시지 큐 (Message Queue)
    • 프로세스 또는 프로그램 인스턴스가 데이터를 서로 교환할 때 사용하는 통신 방법입니다.
    • 메시지를 전송 및 수신하기 위해 소프트웨어 구성 요소가 queue에 연결하도록 허용하는 엔드포인트를 제공합니다.
    • 해당 메시지는 소비자(consumer)라고 부르는 또 다른 구성 요소가 메시지를 검색하고 이를 사용해 어떤 작업을 수행할 때까지 해당 queue에 저장됩니다

=> 메시지를 임시로 저장하는 간단한 버퍼

별도의 공정 작업을 연기할 수 있는 유연성을 제공하여 SOA(Service-Oriendted Architecture)의 개발에 도움을 줄 수 있습니다.

1-1. Message Queue의 사용처

  • 메시지 큐는 소비자(Consumer)가 실제로 메시지를 어느 시점에 가져가서 처리하는 지는 보장하지 않기에 큐에 넣어둔 메시지가 소비되어 처리될 것이라고 믿습니다.
  • 이러한 비동기적 특성 때문에 메시지 큐는 실패하면 치명적인 핵심 작업보다는 어플리케이션의 부가적인 기능에 사용하는 것이 적합합니다

EX) 이메일 전송
이메일 전송을 한 후 실제 받는 사람이 읽을 때까지 시간은 걸리겠지만,
해당 작업이 완료처리 될 것입니다.
→ 실시간으로 처리되지 않아도 서비스에 문제 없는 작업에 MQ를 사용할 수 있습니다.

즉, MQ는 어느 정도의 응답 지연이 허용되며, 어플리케이션의 핵심 기능은 아닌 경우에 사용하는 것이 적합합니다.

1-2. Message Queue의 장점

1. 비동기

  • 생산된 메시지의 저장, 전송에 대해 동기화 처리를 하지 않습니다.
    → 메시지큐에 넣어두기 때문에 나중에 처리할 수 있습니다.
  • 동기적 방식은 많은 메시지가 전송될 경우 병목이 발생할 가능성이 높아지고 뒤에 들어오는 요청에 대한 응답이 지연될 것입니다.

2. 낮은 결합도

  • producer와 consumer가 독립적으로 행동하면서 서비스 결합도가 낮아집니다

3. 확장성

  • 다수의 프로세스들이 큐에 메시지를 보낼 수 있습니다.
  • 생산자 서비스 혹은 소비자 서비스를 원하는대로 확장할 수 있습니다.

4. 탄력성

  • consumer 서비스가 다운되더라도 애플리케이션이 중단되지 않고 메시지는 메시지큐에 계속 머무름 ⇒ 서비스 일부의 실패가 시스템 전체에 영향을 주지 않습니다.
  • 소비자 서비스가 다시 시작될 때마다 추가설정이나 작업을 수행하지 않아도 메시지 처리를 시작할 수 있습니다.

5. 보장성

  • 큐에 보관되어 있는 모든 메시지들이 결국에는 consumer에 의해 처리됨을 보장합니다.

1-3. 메시지 큐 사용

메시지 큐 식별자 생성 : msgget()

메시지 큐를 사용하려면 메시지 큐 식별자를 생성해야 합니다. msgget() 함수를 사용하면 메시지 큐 식별자를 생성할 수 있습니다.

  • msgget() 함수는 인자로 키와 플래그를 받아 메시지 큐 식별자를 리턴합니다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);
  • key : 메시지 큐를 구별하는 키 -> IPC_PRIVATE나 ftok() 함수로 생성한 키를 지정합니다.
  • msgflg : 메시지 큐의 속성을 설정하는 플래그
  • IPC_CREAT : 새로운 키면 식별자를 새로 생성한다.
  • IPC_EXCL : 이미 존재하는 키면 오류가 발생한다.

메시지 큐 식별자와 관련된 메시지 큐와 IPC 구조체가 새로 생성되는 경우

  • key가 IPC_PRIVATE 일 때,
  • key가 IPC_PRIVATE은 아니지만 key에 지정한 식별자와 관련된 다른 메시지 큐가 없고 플래그에 IPC_CREAT가 설정되어 있을 때


메시지 전송 : msgsnd(2)

msgget 함수가 리턴한 메시지 큐를 통해 크기가 msgsz 인 메시지를 메시지를 버퍼 msgp에 담아 전송

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msgid, const void *msgp, size_t msgsz, int msgflg);
  • msgid : msgget 함수로 생성한 메시지 큐 식별자
  • msgp : 메시지를 담고 있는 메시지 버퍼의 주소
  • msgsz : 메시지의 크기(0~시스템이 정한 최댓값)
  • msgflg : 블록 모드(0) / 비블록 모드 (IPC_NOWAIT)

메시지 수신 : msgrcv() 함수

  • msgid가 가리키는 메시지 큐에서 msgtyp이 지정하는 메시지를 읽어 msgp가 가리키는 메시지 버퍼에 저장합니다
  • 성공하면 읽어온 메시지의 바이트 수를 리턴합니다. 실패하면 -1을 리턴하고 메시지를 읽어오지 않습니다.
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

ssize_t msgrcv(int msqid, void *msgq, size_t msgsz, long msgtyp, int msgflg);
  • msqid : msgget 함수로 생성한 메시지 큐 식별자
  • msgflg : 블록 모드 (0) / 비블록 모드 (IPC_NOWAIT)
  • msgp : 메시지를 담고 있는 메시지 버퍼의 주소
  • msgsz : 메시지 버퍼의 크기
  • msgtyp : 읽어올 메시지의 유형

메시지 제어 : msgctl(2)

  • 메시지 큐를 제거하거나 상태 정보를 설정하고 읽어오는 메시지 큐에 대한 제어 기능을 수행합니다
  • msgid로 지정한 메시지 큐에서 cmd에 지정한 제어를 수행합니다 buf는 cmd의 종류에 따라서 제어값을 지정하거나 읽어오는 데 사용합니다
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgctl(int msqid, int cmd, struct msqid_ds *buf);
  • msqid : msgget 함수로 생성한 메시지 큐 식별자
  • cmd : 수행할 제어 기능
    • IPC_START
    • IPC_SET
    • IPC_RMID
    • IPC_INFO
  • buf : 제어 기능에 사용되는 메시지 큐 구조체의 주소

메시지 큐 삭제하기

1 #include <sys/msg.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4
5 int main() {
6	key_t key;
7	int msgid;
8
9   key = ftok("keyfile", 1);
10  msgid = msgget(key, IPC_CREAT|0644);
11  if (msgid == -1) {
12    	perror("msgget");
13      exit(1);
14  }
15    
16  printf("Before IPC_RMID\n");
17  system("ipcs -q");
18  msgctl(msgid, IPC_RMID, (struct msqid_ds *)NULL);
19  printf("After IPC_RMID\n");
20  system("ipcs -q");
21 }

keypoint
18행 - IPC_RMID 명령
17행 - 메시지 큐 3개 존재
20행 - x
메시지 큐 사용이 끝나면 msgctl() 함수를 사용해야 함

1-4. AMQP

  • ISO 응용 계층의 MOM 표준
  • Message Queue의 오픈소스에 기반한 표준 프로토콜
  • 프로토콜만 맞다면 다른 AMQP를 사용한 애플리케이션끼리 통신이 가능(+SMTP)
  • AMQP의 목적
  • 대부분의 플랫폼은 종속적인 제품들이었습니다.
  • 서로 다른 이기종간에 메시지를 교환하기 위해서는 메시지 포멧 컨버전을 위한 메시지 브릿지를 이용하거나 시스템 자체를 통일시켜야 한다는 불편함과 비효율성이 있었습니다.
  • 이 과정에서 발생하는 속도, 응답성의 저하는 치명적인 약점이었습니다.
  • 따라서, 이러한 기존 MQ들의 약점을 보완하기 위해 등장한것이 AMQP입니다.

즉, AMQP의 목적은 서로 다른 시스템간에 (비용/기술/시간적인 측면에서) 최대한 효율적인 방법으로 메시지를 교환하기 위한 MQ 프로토콜인 것입니다.

벤더에 종속되는 것을 방지하기 위해 충족해야하는 조건

  • 모든 broker들은 동일한 방식으로 동작할 것
  • 모든 client들은 동일한 방식으로 동작할 것
  • 네트웍상으로 전송되는 명령어들의 표준화
  • 프로그래밍 언어 중립적

2. Message Queue의 오픈소스

대표적인 오픈소스 : RabbitMQ, ActiveMQ(JMS)

ActiveMQ(JMS)

  • Java로 만든 오픈소스 메시지 브로커, MOM을 자바에서 지원하는 표준 API입니다.
  • JMS는 다른 자바 애플리케이션들끼리 통신이 가능하지만 다른 MOM의 통신은 불가능합니다. (AMQP, SMTP)
  • ActiveMQ의 JMS 라이브러리를 사용한 자바 애플리케이션들끼리 통신이 가능합니다.
  • BUT) 다른 자바 애플리케이션(Non ActiveMQ)의 JMS와는 통신할 수 없습니다.
  • RabbitMQ와는 다르게 모니터링 도구가 부실합니다.

기능

  • 다양한 언어 환경의 클라이언트와 프로토콜을 지원합니다.
  • Spring 지원으로 ActiveMQ는 Spring 애플리케이션에 쉽게 임베딩할 수 있고 XML 설정이 쉽습니다.
  • REST API를 통해 웹 기반 메시징을 지원합니다.
  • Dead letter queue를 지원합니다.

RabbitMQ

  • producers에서 consumers로 메세지(요청)를 전달할 때 중간에서 브로커 역할을 합니다.

사용하는 케이스

  • 요청을 많은 사용자에게 전달할 때
  • 요청에 대한 처리시간이 길 때
  • 많은 작업이 요청되어 처리를 해야할 때

해당하는 요청을 다른 API에게 위임하고 빠른 응답을 할 때 많이 사용합니다.
MQ를 사용하면 애플리케이션간에 결합도를 낮출 수 있다는 장점도 가집니다.


REFERENCE

https://velog.io/@power0080/Message-Queue-%EA%B0%9C%EB%85%90-%EC%A0%95%EB%A6%AC
https://sugerent.tistory.com/644
https://frogand.tistory.com/212
https://goyunji.tistory.com/125
https://m.blog.naver.com/seek316/222117711303

profile
부정적인 상황을 그저 날씨처럼

0개의 댓글

관련 채용 정보