안녕하세요? 저는 에임스에서 백엔드 개발 업무를 맡고 있는 김영한 연구원입니다. 에임스로 이직 후 처음으로 맡게 된 프로젝트에서 MQTT 프로토콜을 알게 됐는데, HTTP에 익숙하던 터라 처음 MQTT 프로토콜을 이해하는 데에 어려움이 있었습니다. 그래서 MQTT 프로토콜을 이해하는 데에 필요한 개념들에 대해서 정리하려고 합니다.
MQTT란?
먼저 위키피디아에 있는 MQTT의 정의 를 살펴보겠습니다.
MQTT(메시지 큐잉 텔레메트리 트랜스포트, Message Queuing Telemetry Transport)는 ISO 표준(ISO/IEC PRF 20922) 발행-구독 기반의 메시징 프로토콜이다.
TCP/IP 프로토콜 위에서 동작한다. "작은 코드 공간"(small code footprint)이 필요하거나 네트워크 대역폭이 제한되는 원격 위치와의 연결을 위해 설계되어 있다. 발행-구독 메시징 패턴은 메시지 브로커가 필요하다.
위 정의에서 MQTT를 이해하기 위해 알아야 할 주요 개념은 ‘메시지 큐’, ‘발행 - 구독 메시징 패턴’, ‘메시지 브로커’입니다. 세 개념에 대해 살펴보도록 하겠습니다.
메시지 큐란?
메시지 큐에 대해 알아보실 때 위키피디아에 있는 메시지 큐의 정의 를 메시지 큐의 정의로 착각하시면 안됩니다.
위키피디아는 “키보드나 마우스를 통해 발생하는 사용자의 입력을 메시지로 전달하는 윈도우즈 시스템에서 어떤 프로세스에 대한 메시지를 저장하기 위해 할당된 큐”를 메시지 큐로 정의하고 있습니다.
하지만 메시지 큐는 메시지 지향 미들웨어(응용 소프트웨어 간의 비동기 데이터 통신을 위한 소프트웨어, Message-oriented middleware(MOM)) 를 구현한 시스템을 아우르는 개념입니다.
사실 메시지 큐라는 것은 이 글의 주제인 MQTT보다 어려운(어렵다기보다는 관련된 내용이 많은?) 개념이기 때문에, 이 글에서 깊게 다루는 것은 적절하지 못할 거 같습니다. 다만, MQTT를 이해하기 위해서는 위의 그림과 아래의 메시지 큐의 특징 정도는 기억하는 것이 좋습니다.
메시지 발행 클라이언트와 메시지 소비 클라이언트의 중개자 역할을 하게 됨으로써
마이크로서비스의 특징인 ‘비동기성’, ‘느슨한 결합’, ‘유연성’, ‘확장성’을 제공하게 된다.
① 비동기성(Asynchronous): Queue에 넣기 때문에 나중에 처리할 수 있다.
② 느슨한 결합(Decoupling): 애플리케이션과 분리할 수 있다.
③ 유연성(Resilience): 일부가 실패 시 전체에 영향을 받지 않는다.
④ 확장성(Scalable): 다수의 프로세스들이 큐에 메시지를 보낼 수 있다.
발행-구독 메시징 패턴 && 브로커란?
발행-구독 메시징 패턴
아래는 발행-구독 모델 위키피디아의 정의입니다.
발행-구독 모델은 비동기 메시징 패러다임이다.
발행-구독 모델에서 발신자의 메시지는 특별한 수신자가 정해져 있지 않다.
대신 발행된 메시지는 정해진 토픽에 따라, 각 토픽에 대한 구독을 신청한 수신자에게 전달된다.
수신자는 발행자에 대한 지식이 없어도 원하는 메시지만을 수신할 수 있다.
이러한 발행자와 구독자의 디커플링은 더 다이나믹한 네트워크 토폴로지와 높은 확장성을 허용한다.
여기까지 글을 읽으신 분들 중 몇몇 분들은 느끼셨겠지만, 메시지 큐의 정의에서 나온 비동기라는 단어가 여기서도 등장합니다. 이 글의 주제인 MQTT뿐만 아니라 메시지 큐, 발행-구독 메시징 패턴, 브로커와 같은 개념들이 비동기(한 작업 단위 내에 요청과 결과가 동시에 일어나지 않음)를 위한 것이라고 이해하셔도 무방하다고 생각합니다.
다시 본론으로 돌아오면 발행-구독 모델에는 구독과 발행자, 수신자라는 개념이 있습니다. 이로 인해, 단일 클라이언트 간의 통신과 달리 “더 다이나믹한 네트워크 토폴로지와 높은 확장성을 허용” 할 수 있습니다.
다소 어렵게 느껴질 수 있지만, 유튜브의 채널 구독 시스템과 비슷한 개념이라고 보시면 되겠습니다. 가령, 제가 ‘에임스TV’라는 유튜브 채널을 구독했다면 저는 ‘에임스TV’가 영상을 올릴 때마다 해당 영상을 구독 탭에서 볼 수 있습니다. 또한 이 채널을 여러 명이 구독했다면, 구독한 사람이 몇 명이든지 간에 해당 영상을 구독 탭에서 볼 수 있습니다. 발행-구독 모델도 이와 비슷하다고 생각하시면 되겠습니다.
메시지 브로커
아래는 역시 위키피디아의 메시지 브로커 에 대한 정의입니다.
메시지 브로커(message broker), 인터페이스 엔진(interface engine)은
송신자의 이전 메시지 프로토콜로부터의 메시지를 수신자의 이전 메시지 프로토콜로 변환하는
중간 컴퓨터 프로그램 모듈이다.
브로커는 쉽게 정의하자면 발행자, 수신자 사이의 중개자입니다. 다만, 이후의 심도있는 학습을 위해서는 ‘메시지 큐’와 ‘메시지 브로커’가 약간 다른 개념이라는 것을 염두에 두실 필요가 있습니다. 대부분의 메시지 지향 미들웨어는 ‘메시지 큐’를 기반으로 구현되어 있고, ‘메시지 브로커’는 메시지 지향 미들웨어의 빌딩 블록입니다. 즉, 메시지 브로커는 메시지 큐를 기반으로 하고 있습니다. 이렇다 보니 요즘에는 메시지 큐와 메시지 브로커를 혼용해서 쓰는 경우가 많은 거 같습니다.
QoS란?
추가로, MQTT의 정의에 명시된 내용은 아니지만 MQTT를 보다 보면 만나게 되는 QoS라는 개념에 대해 알아보겠습니다. QoS는 Quality of Service의 약자로 ‘MQTT에서 메시지의 수신 여부를 체크하는 정도’라고 생각하시면 되겠습니다. 출처
Qos 0은 메시지 수신 여부 체크를 하지 않는 것(without QoS)입니다. 전송 효율이 가장 높으나 메시지 수신 여부를 체크하지 않으므로 네트워크 환경에 따라 메시지가 도착하지 않을 수도 있습니다. 메시지가 한 번쯤은 수신되지 않아도 되는 상황(단순 성능 or 로그 메시지)이나 네트워크 환경이 매우 안정적인 상황에서 사용하는 것이 좋습니다.
Qos 1은 발행자가 구독자로부터 메시지 수신 여부를 받을 때까지 최소 한 번 이상 메시지를 발행하는 것을 말합니다. 적절한 전송 효율과 메시지 수신이 보장되지만 같은 메시지를 여러 번 발행, 수신할 수 있다는 단점이 있습니다.
Qos 2는 메시지가 정확히 한 번 발행되는 것을 말합니다.
Qos 1과 비교했을 때, “Qos 1은 메시지를 여러 번 발행할 수 있고 Qos 2는 메시지를 정확히 한 번 발행하기 때문에 Qos 1의 전송 효율이 Qos 2보다 더 안좋은 것 아닌가?”라는 생각을 하실 수도 있습니다.
그러나, Qos 2에서는 정확히 메시지를 한 번 발행하기 위해 더 복잡한 handshake가 일어나기 때문에 Qos 2의 전송 효율이 Qos 1의 전송 효율보다 더 낮습니다. 그러나, 메시지 수신 여부가 가장 완벽히 보장되기 때문에 은행, 소방, 항공 등의 분야에 사용됩니다.
글을 마치며
사실 MQTT 프로토콜 자체를 이해하는 것은 그렇게 어렵지 않았지만, 위에서 설명한 메시지 큐, 발행-구독 모델, 메시지 브로커 등의 개념을 이해하는 것은 좀 더 어려웠습니다. 그래서 제 나름대로 이해한 바를 적어봤는데, 누군가가 이 개념들을 이해하는데 도움이 되었으면 좋겠습니다. 그럼 글을 마치겠습니다.
다음 작성자는 저희 소프트웨어 책임 연구원이신 김병규 책임 연구원입니다.