AMQP는 애플리케이션간에 데이터를 주고받을 때, 메시지 미들웨어 브로커를 통해 데이터를 주고받을 수 있게 해주는 메시징 프로토콜이다. 여기서 데이터를 주고받기 위해 거치게 되는 메시지 미들웨어 브로커의 종류 중 하나가 RabbitMQ이다.
브로커는 producer(혹은 publisher)로부터 전달 받은 메세지를 알맞는 consumer에게 전달해준다. AMQP 또한 네트워크 프로토콜이기 때문에 producer, consumer 그리고 broker는 모두 다른 컴퓨터 시스템에서 동작할 수 있다.
메세지 큐는 프로세스 혹은 프로그램 간의 데이터를 교환할 때 사용하는 통신 방법 중 하나로, 메세지 지향 미들웨어를 구현한 시스템을 의미한다. 쉽게 말하면 메시지를 통해 프로세스간의 데이터를 주고받기 위해 만든 데이터 교환용 자료구조라고 볼 수 있다.
프로세스 혹은 프로그램 간의 데이터를 교환하기 위한 방법은 HTTP도 있다. 하지만 왜 메세지 큐를 사용해서 데이터를 주고받을까?
HTTP
HTTP는 기본적으로 Request-Response 방식으로 동작한다. 즉 하나의 요청을 보내게 된다면 해당 요청이 처리되고 Response가 올 때 까지 기다리게 되는 것이다.
Message Queue
이와 달리 요청에 대한 응답을 즉각적으로 기다리지 않아도 되는 작업들이 있다. 흔히 회원 가입 환영 Email 전송을 예를 들어 많이 설명한다. 회원 가입 완료 메일의 전송 여부는 즉각적으로 client 측에서 알아야할 정보가 아니다. 따라서 가입한 회원은 가입 이메일이 전송되는 처리까지 기다릴 필요가 없는 것이다. 따라서 이메일 전송은 다른 프로세스나 스레드에서 처리할 수 있도록 순차적으로 저장될 필요가 있다. 이와같이 처리할 업무나 데이터가 순차적으로 저장되는 곳이 Message Queue이다.
RabbitMQ는 메세지 큐를 통해 여러 애플리케이션이 데이터를 주고 받을 수 있도록 해주기 위한 AMQP의 구현체이다. 따라서 데이터가 안전하게 전달되고, 원하는 목적지로 전달될 수 있도록 구현되었다.
RabbitMQ(브로커)로 전달된 메세지는 Queue로 전달되지 않고 Exchange를 통해 들어오게 된다. 그리고 정의된 Exchange 방법과 Binding 규칙을 통해 알맞은 queue로 전달된다. RabbitMQ에는 1개 이상의 Queue들이 존재하고, 해당 queue들을 통해 각기 다른 consumer로 데이터가 전달되게 되는 것이다.
Exchange는 메세지를 받고, 0개 혹은 여러개의 queue로 메세지를 전달하는 요소이다. Exchange가 어떤 queue로 메세지를 전달하는지 결정하는 라우팅 알고리즘은 Exchange Type과 binding 규칙에 의해서 결정된다. AMQP 브로커는 4가지의 Exchange Type을 제공한다.
Direct Exchange
메세지의 routing key를 기반으로 메세지를 전달하는 방식이다. direct exchange 방식을 선택하게 되면 exchange와 queue가 특정 키로 binding되게 된다. 이와 같이 Exchange와 queue가 연결된 규칙들이 binding 규칙이다. 메세지가 Exchange로 들어오게 되면 Exchange는 메세지의 routing key를 확인하고, 일치하는 binding 규칙과 연결된 queue로 메세지를 라우팅하게 된다.
Fanout Exchange
팬아웃 방식은 연결된 모든 queue에게 메세지를 보내는 방식이다. 모든 queue에 동일하게 메세지를 전달하기 때문에 routing key는 메세지에 존재하나 하지 않으나 무시되며, exchange에 N개의 queue가 연결되어 있다면 메세지는 N개로 복사되어 각 queue로 라우팅된다.
Topic Exchange
Direct exchange 방식과 마찬가지로 routing key를 사용하는 방식이다. 다만 Direct 방식과는 달리 queue와 Exchange가 특정 키가 아닌 패턴으로 binding 되어있다. 따라서 routing key가 binding 규칙 중에서 일치하는 모든 패턴의 queue에 메세지가 라우팅 되는 방식이다.
Headers Exchange
Header exchange 방식은 메세지에 헤더에 여러 속성 값을 사용하여 라우팅하는 방식이다. 이 방식을 사용하게 되면 메세지의 routing key 값은 무시되고, 대신 다른 헤더 값을 사용할 수 있다. 헤더의 값과 binding 규칙의 값이 일치하게 되면 해당 queue로 메세지가 라우팅 된다.
Django
Django에서 Celery task를 호출하게 된다. 호출 시에는 해당 task가 RabbitMQ 브로커를 통해 celery worker로 전달된다.
Exchange Type
Exchange type은 기본 값인 Direct를 사용하였다.
Celery
Celery task 종류는 총 3가지이다. 알람 생성, 경기 알람 삭제, 특정 사용자 알람 삭제이다. concurrency pool은 eventlet을 사용하여 프로세스를 fork하는 대신 MainProcess 내에서 thread를 생성하여 동작하도록 설정하였다.
-------------- celery@DESKTOP-B4D45FN v5.2.7 (dawn-chorus)
--- ***** -----
-- ******* ---- Windows-10-10.0.19041-SP0 2022-11-16 17:04:36
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: alarm_tasks:0x1d7204e9a30
- ** ---------- .> transport: amqp://miti:**@localhost:5672//
- ** ---------- .> results: disabled://
- *** --- * --- .> concurrency: 8 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
queue를 보면 celery가 바라보고 있는 queue와 exchange type 그리고 라우팅 키를 확인할 수 있다.