MQTT 프로토콜 상세 설명: 발행/구독 모델, 3단계 QoS 및 5.0 신기능

IoT 프로젝트를 해본 적이 있다면 아마 이 단어를 피하기 어렵다: MQTT. 집 안의 스마트 전구부터 밭의 토양 센서, 생산라인의 공작기계부터 길가의 공유 자전거까지, 수십억 대의 장치가 1999년에 태어난 이 프로토콜로 서로 통신하고 있다. 무엇이 MQTT를 IoT의 사실상 표준으로 만들었을까? HTTP와 비교하면 정확히 무엇이 더 뛰어난 걸까? 이 글에서는 발행/구독 모델부터 QoS 3단계, 유언 메시지, MQTT 5.0의 새로운 기능까지 설명하고, 프로토콜 비교와 바로 실행할 수 있는 Python 코드까지 함께 소개해 MQTT를 한 번에 정리해 보겠다.

1. 스마트 온실에서 시작해 보자: IoT가 HTTP만으로는 부족한 이유

전형적인 스마트 농업 온실을 상상해 보자. 수백 개의 온·습도, 조도, 토양 수분 센서가 밭 곳곳에 흩어져 있고, 배터리와 태양광 패널로 전원을 공급받으며, 상태가 들쭉날쭉한 4G 네트워크를 통해 데이터를 클라우드로 업로드한다. 클라우드는 실시간 데이터를 바탕으로 말아 올리는 커튼, 팬, 관개 밸브를 원격으로 제어해야 한다.

솔루션 검토 때 개발팀의 첫 반응은 대개 이렇다: “HTTP 쓰면 되잖아. POST 한 번 날리면 끝이야.” 틀린 생각은 아니다. 하지만 약한 네트워크 환경, 수백·수천 대의 장치, 7×24시간 온라인 상태를 요구하는 실제 장면에서는 HTTP의 단점이 모두 드러난다:

  • 클라우드에서 능동적으로 푸시할 수 없다. HTTP는 요청/응답 모델이다. 클라우드가 "팬을 켜서 온도를 낮춰"라는 명령을 내리려면 장치가 다음에 폴링할 때까지 기다려야 한다. 폴링 간격을 길게 잡으면 명령 지연이 심하고, 짧게 잡으면 수천 대의 장치가 동시에 폴링하면서 서버와 네트워크가 쓸데없는 요청으로 가득 차 버린다.
  • 헤더 오버헤드가 너무 크다. HTTP 요청 한 번은 헤더만 해도 수백 바이트가 될 수 있지만, 장치가 실제로 보낼 데이터는 십수 바이트뿐일 수 있다. 예를 들어 "26.5"라는 온도값 하나를 보내는 건, 택배용 큰 상자에 쪽지 한 장을 넣어 보내는 것과 같다.
  • 전력 소모를 견디기 어렵다. 통신할 때마다 완전한 TCP + TLS 핸드셰이크가 필요하다. 배터리로 작동하는 센서 입장에서는 무선 모듈이 1초 더 동작하는 것만으로도 비용이 늘어나는 셈이다.

이건 농업 시나리오만의 문제가 아니라 IoT 산업 전체의 공통 과제다: 방대한 수의 장치, 불안정한 네트워크, 저전력 제약, 양방향 실시간 통신. HTTP는 사람이 웹페이지를 보도록 설계된 것이지, 기계끼리 수다를 떨도록 설계된 것이 아니다. 그리고 MQTT는 바로 이런 목적을 위해 태어났다.

2. MQTT란 무엇인가: "비용 절감"을 위해 태어난 프로토콜

MQTT는 원래 Message Queuing Telemetry Transport(메시지 큐 원격 측정 전송)의 약자였다. 하지만 지금은 공식적으로 약자로 해석하지 않는다. 프로토콜 내부에는 사실 전통적인 의미의 메시지 큐가 없고, 이 이름은 역사적 유산에 가깝다.

탄생 배경만 봐도 그 목적이 분명하다. 1999년 IBM의 Andy Stanford-Clark와 Arcom의 Arlen Nipper가 이 프로토콜을 설계했는데, 당시 사용 장면은 위성 링크를 통해 황무지를 가로지르는 석유 파이프라인을 감시하는 것이었다. 위성 통신은 트래픽량에 따라 요금이 부과되고 대역폭은 매우 좁으며 지연도 크고,沿线 감시 장치들은 배터리로 작동했다. 그래서 설계 목표는 매우 단순했다: 패킷은 작아야 하고, 프로토콜은 전력을 아껴야 하며, 네트워크가 끊겨도 버틸 수 있어야 한다.

이 세 가지 단순한 목표가 MQTT가 지금까지 이어온 DNA를 만들었다:

  • 매우 작은 패킷: 고정 헤더는 최소 2바이트뿐이다. HTTP의 수백 바이트짜리 텍스트 헤더와 비교하면 극한까지 절감했다.
  • 가벼움: TCP 위에서 동작한다(기본 포트 1883, TLS 암호화는 8883). 수십 KB 메모리의 마이크로컨트롤러에서도 MQTT 클라이언트를 실행할 수 있다.
  • 불안정한 네트워크를 위해 설계됨: 하트비트, 유언 메시지, 단계별 QoS 등 “연결이 끊겨도 스스로를 보호하는” 일련의 메커니즘을 내장했다.

IBM은 2013년경 MQTT를 OASIS 표준 기구에 제출했고, 2014년 MQTT 3.1.1이 OASIS 공식 표준이 되었으며, 이후 ISO 국제 표준(ISO/IEC 20922)으로 채택되었다. 현재 주류 버전은 MQTT 3.1.1MQTT 5.0(2019년 출시)이다. 5.0은 현재 권장 버전이며, 뒤에서 따로 다루겠다.

eeClub-전자 엔지니어 커뮤니티: https://bbs.eeclub.top/

전자/마이크로컨트롤러 기술 교류 QQ 그룹: 2169025065

3. 핵심 아키텍처: "전화하기"가 아니라 “신문 구독하기”

MQTT를 이해하려면 가장 중요한 것은 통신 모델, 즉 **발행/구독 모델(Publish/Subscribe)**을 이해하는 것이다.

HTTP의 요청/응답 모델은 전화와 비슷하다. 상대방 번호로 전화를 걸어 직접 대화하며, 양쪽이 동시에 온라인 상태여야 하고 서로의 "번호"를 알고 있어야 한다.

발행/구독 모델은 신문 구독과 비슷하다. 신문사(발행자)가 신문을 찍어 우체국(Broker)에 보내면, 독자(구독자)는 미리 우체국에 "저는 과학면을 구독합니다"라고 등록해 둔다. 매일 신문이 도착하면 우체국은 등록 명단에 따라 배달한다. 신문사는 독자가 누구인지 알 필요가 없고, 독자도 신문사의 전화번호를 알 필요가 없다. 양쪽은 완전히 결합이 해제되며, 우체국이 유일한 허브다.

이 모델에는 세 가지 핵심 역할이 있다:

  • Publisher(발행자): 메시지를 생성하는 장치나 프로그램. 예를 들어 온도를 보고하는 센서.
  • Broker(브로커 서버): 전체 시스템의 “우체국”. 메시지를 받고 주제에 따라 모든 구독자에게 배포하며, 연결, 세션, 보관 메시지 같은 잡무도 관리한다. 인터넷에서 도달 가능해야 하는 유일한 역할이다.
  • Subscriber(구독자): 특정 유형의 메시지에 관심 있는 장치나 프로그램. 예를 들어 모바일 앱, 데이터 대시보드.

주의할 점은 발행자와 구독자는 논리적 역할일 뿐이라는 것이다. 같은 장치가 두 역할을 동시에 수행할 수도 있다. 카메라는 클라우드에 경보를 발행하면서 동시에 클라우드가 내려보내는 제어 명령을 구독할 수 있다. 또한 장치는 Broker로 외부 연결을 능동적으로만 하면 되므로, 자체적으로 공용 IP를 가질 필요가 없고 어떤 포트도 열 필요가 없다. 이렇게 하면 NAT와 방화벽 문제를 자연스럽게 피할 수 있다. 이 역시 MQTT가 “장치가 포트를 열고 연결을 기다리는” 방식보다 더 널리 쓰이는 중요한 이유다.

Topic: 우체국 안의 “사서함 번호”

메시지는 무엇으로 배포될까? 바로 **Topic(주제)**이다. Topic은 UTF-8 문자열이며 /로 계층을 나누고, 파일 경로처럼 보인다:

home/livingroom/temperature
home/livingroom/humidity
home/bedroom/temperature

구독할 때는 두 가지 와일드카드를 사용할 수 있다:

  • + 단일 계층 와일드카드: 정확히 한 계층과 매칭된다. 예를 들어 home/+/temperature는 거실과 침실의 온도를 모두 받을 수 있다.
  • # 다중 계층 와일드카드: 이후의 임의의 여러 계층과 매칭되며, 반드시 맨 끝에 와야 한다. 예를 들어 home/#는 home 아래의 모든 메시지를 받을 수 있다.

4. 핵심 기능 하나씩 깊이 보기

MQTT가 약한 네트워크 환경에서도 버틸 수 있는 이유는 정교하게 설계된 메커니즘 덕분이다. 아래 기능들은 면접과 실제 업무에서 가장 자주 등장하는 핵심 포인트다.

1. QoS: 메시지 전달의 세 가지 “택배 서비스”

MQTT는 메시지 전달 품질(Quality of Service)을 세 단계로 나눈다. 세 가지 택배 서비스로 이해하면 쉽다:

  • QoS 0 — 최대 한 번(At most once): 일반 우편과 비슷하다. 보내기만 하면 끝이며, 확인도 없고 재전송도 없다. 유실될 수는 있지만 중복되지는 않는다. 초당 한 번씩 보고되는 실시간 값처럼, 빈도가 높고 잃어버려도 상관없는 데이터에 적합하다. 이번 프레임이 날아가도 다음 초에 새 값이 온다.
  • QoS 1 — 최소 한 번(At least once): 등기우편과 비슷하다. 수신자는 PUBACK으로 확인해야 하며, 발송자는 확인을 받지 못하면 재전송한다. 도달은 보장되지만 중복될 수 있다. 확인 패킷이 길에서 사라지면 발송자가 다시 한 통을 보내기 때문이다. 경보나 상태 변경처럼 “중복되더라도 잃어버리면 안 되는” 메시지에 적합하며, 수신 측에서는 멱등 처리를 해야 한다.
  • QoS 2 — 정확히 한 번(Exactly once): 양쪽이 직접 서명하는 전용 택배와 비슷하다. PUBREC, PUBREL, PUBCOMP 네 단계의 핸드셰이크를 통해 중복도 없고 유실도 없도록 보장한다. 대신 오버헤드가 가장 크고 속도도 가장 느리다. 결제처럼 "1달러만 더 공제돼도 사고"인 상황에 적합하다.

규칙은 간단하다: QoS가 높을수록 신뢰성은 강해지지만, 오버헤드와 지연도 커진다. 엔지니어링 관점에서는 보통 QoS 1이 가장 합리적인 절충안이다.

또 하나 놓치기 쉬운 점이 있다. QoS는 발행자와 구독자가 각각 선언하며, Broker가 실제로 전달할 때는 둘 중 낮은 값을 사용한다. 발행자가 QoS 2로 보내도 구독자가 QoS 0으로 구독했다면, 메시지는 결국 QoS 0으로 전달된다. 따라서 “왜 내 고 QoS 메시지가 유실되지?” 같은 문제를排查할 때는 양쪽을 모두 확인해야 한다.

2. 보관 메시지(Retained): 사서함에 붙여 둔 메모

일반 메시지는 “읽으면 사라진다”. 구독자가 온라인이 아니면 메시지는 보내진 뒤 사라진다. 하지만 발행할 때 Retain 플래그를 설정하면 Broker는 해당 Topic의 마지막 보관 메시지를 저장해 두고, 이후 새 구독자가 그 주제를 구독하는 즉시 바로 받을 수 있게 한다.

대표적인 사용법은 장치가 온라인이 된 뒤 자신의 상태(예: “online”, 현재 스위치 상태)를 Retained 방식으로 발행하는 것이다. 이렇게 하면 앱이 언제 열리든 장치의 최신 상태를 바로 볼 수 있고, 다음 보고를 기다릴 필요가 없다. 참고로 보관 메시지는 주제마다 하나만 저장되며, 새 메시지가 들어오면 기존 메시지를 덮어쓴다. 특정 주제의 보관 메시지를 지우고 싶다면 해당 주제에 빈 페이로드의 Retained 메시지를 발행하면 된다.

3. 유언 메시지(LWT): 장치가 남기는 “마지막 말”

**Last Will and Testament(유언 메시지)**은 MQTT에서 가장 인간적인 설계다. 클라이언트가 Broker에 연결할 때 미리 등록해 둘 수 있다: “내가 갑자기 죽으면(비정상적으로 연결이 끊기면), 이 메시지를 대신 보내 주세요.”

예를 들어 카메라가 연결될 때 유언 camera/01/status = "offline"(Retained)을 등록한다. 장치가 전원이나 네트워크 문제로 비정상 연결이 끊기면 Broker가 대신 유언 메시지를 발행하고, 모든 구독자는 즉시 "이 장치가 죽었다"는 사실을 알게 된다. Retained와 함께 사용하면 나중에 앱을 연 사용자도 오프라인 상태를 확인할 수 있다.

4. Keep Alive: 서로 아직 살아 있는지 확인하는 하트비트

TCP는 상대방의 "가짜 죽음"을 감지하는 데 느리다. MQTT는 애플리케이션 계층에 하트비트를 추가했다. 클라이언트가 연결할 때 Keep Alive 간격(예: 60초)을 정해 두고, 유휴 상태일 때 매우 작은 PINGREQ 패킷을 보내면 Broker는 PINGRESP로 답한다. Broker가 Keep Alive 시간의 1.5배 안에 클라이언트로부터 아무 메시지도 받지 못하면 사망으로 판단하고 연결을 끊으며, 유언 메시지를 트리거한다.

5. Clean Session: 재연결 후에도 나를 기억할까

클라이언트는 Clean Session 플래그를 통해 Broker에게 세션을 유지할지 말지 알려준다. 0(영구 세션)으로 설정하면 Broker는 해당 클라이언트의 구독 관계와 오프라인 기간 동안 놓친 QoS 1/2 메시지를 기억했다가 재연결 후 보충해 준다. 1로 설정하면 재연결 후 모든 것이 처음부터 시작된다.

MQTT 5.0은 이 메커니즘을 Clean Start(새롭게 시작할지 여부)와 Session Expiry Interval(세션 만료 시간)로 분리했다. 표현이 더 정밀해졌으며, 예를 들어 세션을 24시간 유지하도록 지정할 수 있다. 단순한 "영구 유지/유지하지 않음"보다 훨씬 유연하다.

6. 패킷 구조: 2바이트부터 시작하는 극한의 압축

MQTT 패킷은 고정 헤더 + 가변 헤더 + 페이로드 세 부분으로 구성된다. 고정 헤더의 첫 번째 바이트 상위 4비트는 메시지 유형(CONNECT, PUBLISH, SUBSCRIBE, PINGREQ 등 총 14종)이고, 하위 4비트는 플래그다. 이후에는 가변 길이로 인코딩된 “남은 길이” 필드가 있으며, 최소 1바이트만 차지한다. 즉, 하트비트 패킷 하나는 총 2바이트뿐이다. 이것이 바로 MQTT가 "가볍다"고 말할 수 있는 근거다.

5. MQTT 5.0: 진심이 담긴 업그레이드

2019년에 출시된 MQTT 5.0은 가벼움을 유지하면서도 많은 엔지니어링 부족분을 채웠다:

  • 이유 코드(Reason Code): 거의 모든 응답 패킷에 표준화된 이유 코드가 붙었다. 연결 거부, 구독 실패가 더 이상 막연한 "실패"가 아니라 왜 실패했는지 명확히 알려준다.
  • 속성 시스템(Properties): 패킷이 유연한 메타데이터 키-값 쌍을 운반할 수 있게 되었고, 많은 새 기능이 이 메커니즘 위에 구축되었다.
  • 공유 구독(Shared Subscription): 여러 구독자가 소비 그룹(예: $share/group1/topic)을 구성하면 같은 메시지는 그룹 내 한 명에게만 전달된다. 자연스럽게 부하 분산을 실현한다. 이는 3.1.1 시대에는 꽤 우회해야 가능했던 일이다.
  • 메시지 만료(Message Expiry Interval): 발행할 때 메시지에 유효기간을 설정할 수 있다. 만료된 오프라인 메시지는 더 이상 보충되지 않아, 장치가 온라인이 되었을 때 오래된 명령들로 폭격당하는 일을 피할 수 있다.
  • 기타 개선: 짧은 번호로 긴 주제명을 대체해 트래픽을 줄이는 주제 별칭, Receive Maximum 트래픽 제어, 서버가 능동적으로 연결을 끊는 알림, Response Topic 기반 요청-응답 모델 지원 등.

한마디로 정리하면: 3.1.1은 충분하고, 5.0은 쓰기 좋다. 신규 프로젝트라면 바로 5.0을 쓰는 것을 추천한다.

6. 수평 비교: MQTT vs HTTP vs CoAP vs WebSocket

MQTT가 좋다고만 말하는 것만으로는 부족하다. 프로토콜 무리에 넣어 비교해 보면 위치가 더 선명해진다:

차원 MQTT HTTP CoAP WebSocket
통신 모델 발행/구독 요청/응답 요청/응답(REST 유사) 양방향 데이터 스트림
전송 계층 TCP TCP UDP TCP
최소 패킷 오버헤드 2바이트 헤더 수백 바이트 4바이트 프레임 헤더 2바이트 이상
클라우드 능동 푸시 기본 지원 미지원(폴링 개조 필요) Observe 필요 지원
메시지 신뢰성 메커니즘 내장 3단계 QoS TCP 의존 선택적 확인/재전송 없음, 직접 구축 필요
저전력 적합성 우수 낮음 우수(UDP가 더 전력 효율적) 보통
대표적인 사용 장면 장치-클라우드, 원격 측정, 원격 제어 웹페이지, 공개 API, 파일 전송 극도로 제한된 센서 네트워크 웹 실시간 상호작용, 채팅룸

한마디로 위치를 정리하면: HTTP는 사람을 위한 것이고, WebSocket은 브라우저를 위한 것이고, CoAP는 극도로 제한된 장치를 위한 것이고, MQTT는 “방대한 장치 + 약한 네트워크 + 양방향 실시간” 장면을 위한 것이다.

7. 대표적인 사용 장면: 매일 쓰고 있을지도 모른다

  • 스마트 홈: MQTT의 가장 큰 기본盤. 오픈소스 플랫폼 Home Assistant에서는 많은 장치가 MQTT를 통해 연결된다. 집 안의 조명, 콘센트, 온습도계가 아마 지금도 어떤 Broker와 긴 연결을 유지하고 있을 가능성이 크다.
  • 산업 IoT(IIoT): 생산라인의 PLC, 공작기계, 계측기가 데이터를 공장급 Broker로 업로드하고, MES 시스템과 모니터링 대시보드가 필요한 만큼 구독한다. 알리바바 클라우드 IoT, AWS IoT Core 같은 클라우드 플랫폼도 장치 접속 계층의 주 프로토콜은 MQTT다.
  • 차량联网: 차량 관리 플랫폼은 MQTT를 통해 수천 대의 차량에 명령을 내리고 차량 상태를 수집한다. QoS 단계는 "위치 보고는 유실되어도 되지만, 원격 잠금은 반드시 도착해야 한다"는 차등 요구와 잘 맞는다.
  • 환경 및 농업 모니터링: 밭의 토양 센서, 저수지 옆의 수질 관측소는 배터리와 태양광으로 운영된다. MQTT의 저전력 특성과 연결 끊김 후 캐시 능력이 필수적이다.

8. 실전 입문: 10분 안에 첫 MQTT 메시지 실행하기

책으로만 배우면 부족하다. 실제로 해 보는 문턱은 사실 매우 낮다.

Broker 선택

  • EMQX: 중국산 오픈소스. 성능이 강력하고 문서가 중국어에 친화적이며, 온라인 공개 테스트 Broker broker.emqx.io도 제공한다. 연습용으로 가장 좋다.
  • Mosquitto: Eclipse 재단 프로젝트. C 언어로 작성되었고 매우 가볍다. 라즈베리 파이에서도 실행할 수 있어 로컬 디버깅에 적합하다.
  • HiveMQ: Java 계열의 엔터프라이즈급 솔루션. 상용 지원이 잘 갖춰져 있다.

클라이언트 도구 선택

  • MQTTX: EMQ에서 만든 크로스플랫폼 데스크톱 클라이언트(CLI와 웹 버전도 있음). 인터페이스가 직관적이라 프로토콜 조정에는 필수다.
  • mqtt-cli / mosquitto_pub, mosquitto_sub: 명령줄 사용자에게 잘 맞는 도구.

바로 실행 가능한 Python 예제

의존성 설치: pip install paho-mqtt

구독자(subscriber.py):

import paho.mqtt.client as mqtt

def on_connect(client, userdata, flags, reason_code, properties):
    print("연결됨:", reason_code)
    client.subscribe("home/livingroom/temperature", qos=1)

def on_message(client, userdata, msg):
    print(f"수신 [{msg.topic}] {msg.payload.decode()}")

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.on_connect = on_connect
client.on_message = on_message
client.connect("broker.emqx.io", 1883, 60)
client.loop_forever()

발행자(publisher.py):

import paho.mqtt.client as mqtt

client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2)
client.connect("broker.emqx.io", 1883, 60)
client.publish("home/livingroom/temperature", "26.5", qos=1)
client.disconnect()
print("발송 완료")

먼저 구독자를 실행하고, 그다음 발행자를 실행하면 구독자의 터미널에서 "26.5"라는 메시지를 볼 수 있다. 이것이 바로 IoT 세계의 가장 작은 "하트비트"다.

마지막으로 한 가지 당부: 공개 테스트 Broker는 모두가 공유하는 곳이므로 민감한 데이터를 절대 올리지 마라. 실제 프로젝트에서는 Broker 서비스를 직접 구축하거나 구매하고, 반드시 TLS 암호화와 계정 인증을 활성화해야 한다.

9. 요약

MQTT의 성공은 얼마나 진보적인가에 있지 않다. 핵심은 극도로 절제되어 있다는 점이다. “석유 파이프라인 + 위성 링크” 같은 가혹한 환경에서 강요되다시피 태어난 작은 패킷, 저전력, 약한 네트워크에서의 회복력은 천문학적인 수의 IoT 장치의 핵심 요구와 정확히 맞아떨어졌다. 발행/구독의 결합 해제 모델, 3단계 QoS의 유연한 신뢰성, 유언과 보관 메시지처럼 "장치는 연결이 끊길 수 있다"는 현실을 바탕으로 한 실용적인 설계 덕분에 MQTT는 오늘날 IoT의 사실상 표준 프로토콜이 되었다.

스마트 하드웨어나 백엔드 개발을 하고 있다면 제 조언은 이렇습니다: 먼저 공개 Broker와 MQTTX로 게시/구독을 한 번 돌려 보고, 그다음 QoS와 세션 메커니즘을 차분히 다시 읽어 보세요. 이 두 부분을 제대로 익히면 MQTT의 80%는 이미 손에 넣은 셈입니다.

30년 전 황야를 가로지르던 그 석유 파이프라인은 아마도 자신들을 위해 설계된 작은 프로토콜이 오늘날 수십억 대의 장치에서 돌아가리라고는 상상하지 못했을 겁니다. 기술의 생명력은 흔히 이런 “딱 적당한” 설계 속에 숨어 있습니다.

추가 학습 자료

추천 읽을거리

English Version of the Article: https://blog.zeruns.top/archives/96.html