Message Queue
도입
WebLogic, JEUS 등과 같은 엔터프라이즈 WAS에는 Message Service 라는 것이 포함되어 있습니다. 시스템을 설치하거나 관리 콘솔을 사용하다가 ‘이런것도 있군’ 하면서 뭣에 쓰는 물건인지 궁금했었습니다. 메시지 라는 이름에서 비동기 처리에 관련된 느낌은 받았지만, 웹 앱을 주로 다루는 입장에서는 많이 활용되는 기능은 아니었습니다.
최근 들어 Microservice나 IoT 등 소프트웨어 개발의 여러 영역에서 Message Queue가 많이 활용되고 있어 그 중 하나인 RabbitMQ를 통해 어떤 물건인지 살짝 돌아보고자 합니다.
- 메시지 큐의 주요한 특징과 효과
- 분산 : 확장 가능성 높아짐(Scalability), 다양한 환경의 프로그래밍이 가능(Polyglot). 디커플링(decoupling) 향상.
- 비동기 : 사용자 반응속도 향상, 장애 허용성 향상.
메시지 큐는 기본적으로 분산과 관련되어 있습니다. 메시지 큐는 어디에선가 생성된 메시지를 받고 그걸 어디론가 전달해 줍니다. 어찌보면 굉장히 단순한 일을 합니다. 메시지를 생산하는(보내는) 곳과 소비하는(받는) 곳이 다르기 때문에 기본적으로 분산의 특징을 가지고 있습니다. 분산은 시스템의 확장을 쉽도록 해줍니다. 메시지 큐에 연결만 하면 전체 시스템에 새로운 노드를 추가할 수 있기 때문입니다. 메시지 생성과 소비는 서로 다른 프로그래밍 환경에서 할 수 있습니다. 필요한 작업에 적합한 환경을 선택할 수 있게 해줍니다.
사용자 반응속도와 관련해서는 오래 걸리는 작업은 큐에 넘기고 보다 빨리 응답을 넘길 수 있도록 도와 줍니다. 또한 큐 라는 저장소를 내장하고 있기 때문에 가용성을 높이는 효과도 있습니다. 시스템 사이를 직접 연결할 때 한 쪽이 동작하지 않으면 전체 시스템에 문제가 생기게 됩니다. 하나의 시스템이 작동하지 않더라도 메시지 큐는 받은 메시지를 정상적으로 저장하고 있으므로 나중에 복구되었을 때 다시 저장된 메시지를 보내게 됩니다. 이를 통해 전체 시스템의 장애 허용성(Fault tolerance)을 높일 수 있습니다.
메시지 큐는 특정 환경에 종속된 기술이 아니고 시스템 구성에 있어 일반적인 이슈를 해결하기 위한 솔루션이라고 생각됩니다. 어떤 시스템과 다른 시스템을 연결해주는 역할을 하는것이죠. 시스템 사이의 메시지 중계 뿐만 아니라 하나의 시스템 안에서도 효율을 높이기 위해 작업 큐로 활용할 수 있습니다.
RabbitMQ
오픈소스로 사용할 수 있는 메시지 큐는 여러가지가 있습니다. Apache Kafka, RabbitMQ, Apache ActiveMQ가 대표적인 것들이고 그 외에도 다양합니다. 아마존에서는 SQS라는 서비스로 메시지 큐를 제공하고 있습니다. 각각의 특징도 서로 다르니 필요한 곳에 맞게 도입하면 될것 같습니다. 메시지 큐를 이해하기 위해 RabbitMQ을 선택했습니다. RabbitMQ는 플러그인 아키텍처로 쉽게 기능을 확장할 수 있고, 클러스트링을 지원해 확장성과 가용성이 높은 것을 특징으로 합니다.
시작하기
RabbitMQ는 ErLang으로 구현되어 있으며 그 외에도 몇 가지 의존성이 있습니다. OS에 영향을 끼치지 않고 실험하기 위해 도커로 진행해보겠습니다. 시놀로지 NAS를 사용하시는 분들은 도커 애드온을 먼저 설치하시면 되겠습니다. 도커를 사용하면 시놀로지를 꽤 유용한 개발 플랫폼으로 활용할 수 있는 것 같습니다.
컨테이너 설치
- 우선 도커를 설치합니다. 설치되어 있으면 다음 항목으로. 윈도에서 Docker Toolbox를 설치합니다. Hyper-V 환경을 사용하시는 분은 일반 Docker Desktop으로 하시거나 각 운영체제에 맞는 도커를 설치하시면 됩니다. 그나저나 Hyper-V와 Virtual Box 충돌은 해결이 좀 어떻게 좀 해결이 안 되는건지…ㅠ(참조)
- Docker Toolbox의 UI 툴인 Kitematic을 실행하고 RabbitMQ를 찾아 설치해줍니다. 터미널에서 할 경우
$ docker pull rabbitmq
로 하시면 됩니다.
-
컨테이너가 설치되고 실행되면 포트를 확인합시다. 5672 포트가 메시지를 주고 받기 위한 포트입니다. 외부에 바인딩되는 포트는 랜덤으로 지정됩니다. 고정할 필요가 있으면 Settings에서 수정해줍니다.
관리 UI 플러그인 설치
RabbitMQ에서는 편하게 관리할 수 있는 UI를 제공하고 있습니다. 플러그인 형태로 제공되고 커맨드 한 번에 설치할 수 있습니다. 이외에도 REST API를 제공하므로 관리 자동화에 활용할 수 있습니다.
- Kitematic 에서 EXEC를 선택하면 쉘이 나옵니다. 커맨드(도커 퀵스타트 터미널)로는
docker exec -it [컨테이너ID] /bin/bash
로 쉘에 들어갈 수 있습니다. $ rabbitmq-plugins enable rabbitmq_management
로 관리 플러그인을 활성화 해줍니다.
-
관리 포트는 15672를 사용하게 설정되어 있습니다. 설정 화면에서 포트를 열어줍니다.
-
브라우저에서 접속하면 로그인 화면이 나옵니다. 기본 ID/PW인 guest/guest를 입력해줍니다.
-
관리 콘솔이 나옵니다. 접속자, 채널, 큐 등을 보고 추가/변경/삭제할 수 있습니다. 테스트를 해보면서 각 요소가 어떻게 변하는지 확인해보면 RabbiMQ를 이해하는데 도움이 될 것입니다.
간단한 테스트
공식 사이트에서 제공되는 튜토리얼을 몇 가지 테스트 해보겠습니다. 파이썬이 기본으로 나오니 파이썬으로..다른 프로그래밍 언어로 도 튜토리얼을 제공하므로 알맞은 걸로 선택하시면 되겠습니다. 라이브러리는 pika를 사용합니다. pip install pika
로 설치하면 됩니다.
메시지 보내고 받기
텍스트 메시지를 보내고 받는 테스트 입니다.
- 보내기
- 받기
- 실행하기
- rabbitmq-receive-message.py 를 실행합니다.
python rabbitmq-receive-message.py
- RabbitMQ 관리 콘솔을 보면 Queue가 하나 생긴걸 볼 수 있습니다.
- rabbitmq-send-message.py 를 실행합니다.
python rabbitmq-send-message.py
- receive 를 보면 메시지를 수신하고 출력한 걸 볼 수 있습니다.
- receive 를 추가로 실행합니다. 여러개의 수신자가 있을 때 어떻게 돌아가는지 보는거죠. 여러번 send를 하다 보면 메시지 전달이 round-robin 방식으로 이루어지는 것을 알 수 있습니다. 공평하게 배분하는 것이죠.
Fanout(메시지 브로드캐스팅) 사용하기
위의 예제에서는 하나의 메시지가 하나의 리시버로 들어가는 형태였습니다. 이번에는 리시버 전체에 전달되는(브로드캐스팅) 예제입니다.
- 보내기
- 받기
- 실행하기
- rabbitmq_receive_logs.py를 여러 개 실행합니다.
- rabbitmq_emit_log.py 를 여러 차례 실행합니다.
- 발행한 메시지가 모든 리시버에게 전달되는 것을 확인할 수 있습니다.
라우팅 사용하기
라우팅 기능은 일종의 필터 역할을 합니다. 하나의 큐에서 어떤 메시지를 읽어올지 선택할 수 있게 됩니다. 메시지의 분류는 routing_key 라는 항목으로 할 수 있습니다.
- 보내기
- 받기
- 실행하기
- receive 를 실행합니다. warning과 error 메시지만 받도록 합니다.
python rabbitmq_receive_logs_direct warning error
- 또 다른 receive 를 실행합니다. 이번에는 info, warning, error 메시지를 받을 수 있도록 합니다.
python rabbitmq_receive_logs_direct.py info warning error
- send를 실행합니다. error 로 보내봅니다.
python rabbitmq_emit_log_direct.py error "Run. Run. Or it will explode."
양쪽 receive에서 모두 메시지를 받는 것을 확인할 수 있습니다. - 이번에는 info로 보내봅니다.
python rabbitmq_emit_log_direct.py error "Run. Run. Or it will explode."
두 번째 receive에는 메시지가 전달되지만 첫 번째 receive에는 전달되지 않습니다. - 관리 콘솔을 확인해 봅시다. Exchange에 가면 direct_logs 라는 항목이 있습니다. 눌러보면 라우팅 키와 어떤 큐로 전달되는지 확인할 수 있습니다.
여기까지 간략히 RabbitMQ를 살펴봤습니다. 이외에도 메시지 전달 확인이나 보다 유연한 라우팅인 토픽 등의 기능이 있습니다. 메시지 큐의 사용처가 점차 확대되는 상황에서 어느정도 이해를 갖추고 있는게 좋을 것 같습니다.
활용 아이디어
MQ를 활용한 프로젝트로 생각해 볼만한 것.
- 동기화 매커니즘 : 이벤트를 큐에 저장해놓고 주기적으로 동기화는 상황이라면 MQ가 도움을 줄 것입니다.
- 웹 앱에서 오래 걸리는 작업 떠넘기기 : 엑셀 보고서 생성과 같이 실시간 응답성이 중요하지 않은 작업은 큐에 넣고 백그라운드로 실행하는게 좋을 것 같습니다. 사용자 응답은 빨라지고 서버의 리소스를 덜 잡아먹게 됩니다. 홈택스 같은 곳에서도 증명서 발급에 이런 식으로 구현된 것을 볼 수 있습니다. 사용자가 신청하고, (담당자가 확인하고?), 발급이 완료되면 리스트에서 증명서를 확인할 수 있게 됩니다.
- 메시지 앱 : 채팅 등 기본적으로 비동기 메시지 성격인 서비스라면 MQ를 사용하기 적당해 보입니다.
- 주기적인 Polling 제거 : 정해진 시간마다 이벤트를 확인하고 작업을 돌리는 폴링 방식 보다는 MQ를 활용하는게 나을 것 같습니다.
- 사무실/카페의 BGM DJ : 보통 스트리밍 서비스로 음악을 틀 것 같은데 플레이 리스트에 곡을 추가하거나 볼륨 조절을 하는 기능을 리모트로/여러 사람이 제어하는데 사용할 수 있을 것 같습니다. 스트리밍 서비스들에서 API가 제공된다면 해볼만할 것 같습니다.
- IoT : 각 디바이스들을 연결하는 메시지 버스로서 MQ를 사용할 수 있습니다. 센서들의 값을 큐에 넣고 엑추에이터로 값을 전달해주는 역할을 해줄 수 있습니다. RabbitMQ에서는 IoT를 위한 메시지 프로토콜인 MQTT도 플러그인으로 지원하므로 활용 하기 좋아 보입니다.
참고
- RabbitMQ Tutorials
- MQTT 적용을 통한 중계시스템 개선
- What is message queuing?
- Message Queues & You – 12 Reasons to Use Message Queuing
- Connecting Competing Microservices using RabbitMQ
- RabbitMQ in Microservices
- Exploring Message Brokers: RabbitMQ, Kafka, ActiveMQ, and Kestrel
- Microservices communications. Why you should switch to message queues.