MQTT는 경량의 Publish/Subscribe(Pub/Sub) 메시징 프로토콜이다. M2M(machine-to-machine)와 IoT(Internet of things)에서의 사용하려고 만들었다. IoT를 위해서 낮은 전력, 낮은 대역폭 환경에서도 사용할 수 있도록 설계됐다.
IoT 관련 일들을 하고 있는데, 저전력/소규모 디바이스를 위한 통신 프로토콜들을 살피면서 자연스럽게 관심을 가지게 됐다.
가전기기, 빌딩, 도시, 산업, 개인 등 다양한 영역에서의 센서정보를 수집할 수 있다. 네트워크 영역으로 보자면 LAN(가정/소규모 오피스), PAN(개인 네트워크), BAN(빌딩 네트워크), MAN(도시영역 네트워크)등에서 사용할 수 있다.
개인적으로 건강과 질병관리 분야에 관심이 간다. 지금 당장 서비스를 개발하기에는 센서장비의 품질 개선이 필요한 것 같다. 지금의 헬스케어 센서들은 "건강한 사람을 위한 악세사리"정도 인것 같다. 이런 용도로 사용하기에는 센서 품질이 별로 중요하지 않겠지만 질병/건강관리를 위해서 본격적으로 사용하려면 품질개선이 필요 할 것 같다.
MQTT 프로토콜은 메시지를 발행(publishing) 하고, 관심 있는 주제를 구독(subscribe) 하는 것을 기본 원칙으로 한다.
Publisher과 Subscriber은 모두 Broker에 대한 클라이언트로 작동한다. Publisher는 토픽을 발행하기 위한 목적으로 Subscriber은 토픽을 구독하기 위한 목적으로 Broker 서버에 연결한다. 하나 이상의 Pub와 Sub가 브로커에 연결해서 토픽을 발행 하거나 구독할 수 있다. 또한 다수의 클라이언트가 하나의 주제를 구독할 수도 있다.
MQTT는 메시지 버스 시스템이다. MQTT Broker가 메시지 버스를 만들고 여기에 메시지를 흘려보내면, 버스에 붙은 애플리케이션들이 메시지를 읽어가는 방식이다. 메시지 버스에는 다양한 주제의 메시지들이 흐를 수 있는데, 메시지를 구분하기 위해서 "Topic"을 이름으로 하는 메시지 채널을 만든다.
애플리케이션들은 Message Bus에 연결하고 관심있는 토픽(Topic)을 등록 해서 메시지를 구독(SUB)하거나 발행(PUB)한다.
0 : 메시지는 한번만 전달하며, 전달여부를 확인하지 않는다. Fire and Forget 타입이다.
1 : 메시지는 반드시 한번 이상 전달된다. 하지만 메시지의 핸드셰이킹 과정을 엄밀하게 추적하지 않기 때문에, 중복전송될 수도 있다.
2 : 메시지는 한번만 전달된다. 메시지의 핸드셰이킹 과정을 추적한다. 높은 품질을 보장하지만 성능의 희생이 따른다.
서비스의 종류에 따라서 적당한 QoS 레벨을 선택해야 한다.
No TCP/IP와 TCP/IP가 섞여있는 로컬 네트워크에서는 QoS 1, 2를 선택하는게 좋을 것 같다. 네트워크 구간을 신뢰할 수 없으며, 메시지 전송이 실패 했을 때, 메시지 박스에 저장하는 일을 하는 소프트웨어 시스템을 구축하기가 쉽지 않기 때문이다.
원격 네트워크에서는 0번이 좋을 것 같다. QoS 1이 적당할 것 같지만, 1이나 2를 선택할 경우 메시지 관리가 힘들어진다. 예를들어 offline 모드에서의 메시징을 지원하기 위해서 메시지 박스 서비스를 제공한다고 가정해 보자. QoS 1로 설정을 하면, 다음 연결에 메시지를 보내기 위해서 자체 queue에 저장을 한다. 그러면 시스템 입장에서는 MQTT queue에 있는 메시지를 읽어야 하는데, 메시지 박스에서 읽어야 하는지를 판단해야 한다.
또한 클라이언트는 MQTT queue에 있는 메시지를 읽기 위해서 이전에 연결했던 MQTT에 연결을 해야 하는데, 이러한 요구사항은 클러스터 구성을 어렵게 한다. 설계 관점에서도 비슷한 일을 하는 두 개의 모듈을 두는 것은 좋지 않은 설계다. 그냥 QoS 레벨은 0으로 하고, 소프트웨어에서 QoS를 처리하는게 깔끔할 것 같다.
MQTT 서버라고 하지 않고 중개인(브로커)라고 하는 이유는 MQTT가 발행인과 구독자가 메시지를 주고 받을 수 있도록 다리를 놔주는 역할만을 하기 때문이다. 다른 기능들은 중계를 도와주는 부가 기능일 뿐이다. 다양한 종류의 브로커들이 있는데, 여기에서 확인하자.
내가 경험한 브로커들만 간단히 정리한다.
MQTT 전용 브로커로 매우 가벼우며, MQTT 브로커가 가져야 할 대부분의 기능을 충실히 지원한다는 장점이 있다. 소형기기에 올려서 사용하기에 적당하다.
()현재 최신 안정 버전 1.3.5는 아직 WebSocket을 지원하지 않는다. 1.4에서 지원하는데, 지금은 직접 빌드해서 사용해야 한다. 클러스터를 지원하지 않는 것도 단점이다. 대규모의 메시징 시스템을 구축하려면 노가다를 뛰어야 한다. 메시징 서비스 인프라에 고가용성은 필수 요소이기 때문에 중요한 문제가 될 수 있다.
AMQP를 지원하는 메시지 큐 서버로 플러그인(Plug-in)방식으로 MQTT를 지원한다. AMQP를 이용한 범용 메시징 서버라서 좀 무겁기는 하지만 클러스터링을 지원하고 다양한 플러그인을 이용해서 기능을 확장할 수 있다. STOMP, 웹 소켓, HTTP(S)등 다양한 통신 프로토콜을 지원하기 때문에, 메시징 서버 인프라의 개발에 적당하다.
RabbitMQ는 범용 메시징 서버로 다양한 메시징 방식을 제공한다. AMQP, MQTT 프로토콜을 지원하며 HTTP(S), STOMP, 웹소켓, JSONRPC 등의 다양한 통신 방식을 지원한다. 다양한 활용이 가능하다는 것은 장점이라고 볼 수 있겠는데, 기능이 많은 만큼 무겁다. 자원이 빈약한 소형기기에 사용하기에는 무리가 있다. 메시징 인프라 구축에는 RabbitMQ, 소형기기의 메시징 브로커로는 모스키토의 사용을 고려해 봄직하다.
서비스 마다 달라질 수 있겠다. IoT를 기준으로 제안한다.
서버 인프라는 가용성과 확장성이 유리한 RabbitMQ로 구축한다. 모스키토로도 구축할 수 있기는 하지만 노가다를 뛰어야 한다. 기타 보안, 인증, 다양한 프로토콜 지원, 플러그인 개발 등을 고려해보면 RabbitMQ를 선택해야 할 것 같다.
기기들은 모스키토를 이용한다. 가볍고 간단해서 소형기기에 집어 넣기에 적당하다.
MQTT를 이용한 Pub/Sub 테스트는 끝냈으니, 이제 좀 그럴 듯한 서비스를 만들어봐야 겠다. MQTT를 이용한 chatting 프로그램을 개발할려고 한다. 이 chatting 프로그램은 아래의 기능을 지원한다.
채팅방 생성 : 채팅방을 Topic으로 하면 된다. Topic을 늘리는 것으로 여러 개의 채팅방을 운용할 수도 있을 거다. 채팅방을 임의로 만들게 하는 건 귀찮으니.. 그냥 "chat/public", "chat/private" 두개의 채팅방만 만들기로 했다.
채팅방 Join : 원래는 채팅방 목록을 확인해서 Join해야겠으나 귀찮으니, chat/public, chat/private 모두를 sub 하는 걸로 join을 대신하겠다. 유저는 nickname을 만들어서 두개의 topic에서 메시지를 받아본다.
채팅 클라이언트 프로그램은 Sub와 Pub를 모두 해야 하니 멀티 쓰레드로 작동해야 한다.
MQTT 브로커로는 앞서 다룬 모스키토를 사용했다.
쓰레드 하나는 Sub 전용이다. 토픽으로 받은 정보를 화면에 출력한다.
chat/public : 공개 채널의 메시지를 받기 위해서 사용한다.
chat/public/nickname : 자신의 nicname 토픽에 메시지를 받기 위함.
쓰레드 하나는 Pub 전용이다. 표준입력을 토픽에 publishing 한다.
chat/public : 공개 채널에 publishing 한다.
chat/public/other : 특정 유저에게 publishing 하기 위해서 사용한다.
헤더를 위한 2바이트가 필수 정보고, 나머지는 옵션이다. PING 메시지는 단지 2byte의 데이터만 필요하며, 메시지의 타입과 데이터의 크기에 따라서 헤더 크기가 변한다. 저전력, 낮은 대역폭에서의 작동을 위해서, 단 1 바이트의 데이터를 아끼려고 노력한 프로토콜이다.
Remaining Length는 variable header를 포함한 전체 메시지의 크기를 계산하기 위해서 사용한다. 1에서 부터 4바이트를 사용하는데, 데이터의 크기에 따라서 가변적이다. 1바이트라도 아끼기 위한 눈물겨운 노력의 결정체라고 볼 수 있겠다.
1byte는 255까지 저장할 수 있다. 이중 첫 번째 bit를 "다음 remaining byte를 사용할 건지 결정하기 위해서" 사용한다.
Byte 2만 사용할 경우 127 byte 크기의 메시지를 다룰 수 있다. 만약 127 byte를 초과 한다면
Byte 3를 사용해야 한다. 마찬가지로 1개 bit는 reamining byte를 사용할 건지 결정하기 위해서 남겨둬야 한다. 전체 2바이트 에서 2개의 비트를 예약 했으니 16383까지 표현할 수 있다.
Byte 4도 같은 방법으로 계산 하면 2,097,151 까지 표현할 수 있다.
Byte 5는 최대 268,435,455를 사용할 수 있다. 4개의 비트를 사용할 수 없으니 2^28 - 1 = 268435455이다.
MQTT가 다룰 수 있는 최대 메시지의 크기가 256M로 제한되는 이유다. 작은 크기의 센서 데이터를 다루는 MQTT의 목적에 비추어 생각해 보면, 합리적인 선택이라고 할 수 있다.
Local에서의 기기 연결을 위한 이렇다한 표준이 없는 상태다. 퀄컴과 LG가 주도하는 Allseen 얼라이언스의 Alljoyn, 인텔과 삼성이 주도하는 OIC(Open Interconnect Consortium) 등이 경쟁하는 양상. 애플은 HomeKit이 있긴한데, Allseen과 OIC와는 적용 범위가 좀 다른 것 같고, 어차피 독고다이로 나갈 느낌이라서 제외.
나와 좀 관련이 있는 Alljoyn을 기준으로 보자면, 로컬 discovery와 통신 모두 기존의 프로토콜을 사용하지 않고 새로 구현해서 사용하고 있다. No TCP/IP영역에서의 센서수집에 MQTT를 사용 할 수는 있겠지만 주요한 프로토콜은 아니다.개인적으로 DNS-SD와 MQTT 같은 (거의)표준기술을 이용하는게 나을 것 같다. 굳이 새로운 프로토콜을 만들 필요가 있었을까라는 의문이 든다.
아래와 같은 모양이 되지 않을까 ?
소형 장비의 센서를 수집하고 제어하기 위한 Gateway가 있을 수 있다.
AllSeen 혹은 OIC Gateway가 있다. 이들은 Local의 기기를 discovery하고, 메시지를 중계하는 브로커 역할을 한다. 그리고 IoT Internet Infra로의 연결을 위한 인터넷 게이트웨이 역할을 한다.
IoT Internet Infra의 연결에 MQTT를 사용한다.
실제 Alljoyn gateway에 MQTT 플러그인을 올릴 계획도 있으니, 그럭저럭 현실적인 구성이라고 볼 수 있다.
Contents
1. MQTT
2. 응용 분야
2.1. 센서(Sensor) 정보 수집
2.2. 제어
2.3. Message Push Server
3. MQTT 특징
3.1. Publish/Subscribe
3.2. 토픽
3.3. 메시지 버스
3.4. QoS
4. MQTT 브로커들
4.1. Mosquitto MQTT broker
4.1.1. 테스트 환경
4.1.2. Mosquitto 브로커 설치
4.1.3. Mosquitto 클라이언트 설치
4.1.4. Pub/Sub 테스트
4.1.5. 장점과 단점
4.2. RabbitMQ
4.2.1. MQTT Plugin 실행
4.2.2. 장점과 단점
4.3. 메시징 서비스 인프라 제안
5. Chatting 프로그램
5.1. 개발 환경
6. MQTT 포맷 분석
6.1. Fixed Header
6.1.1. Message Type
6.1.2. Flags
6.1.3. QoS
6.1.4. Remaining Length
6.2. Variable header
6.2.1. protocol name
6.2.2. Protocol version
6.2.3. Topic name
7. IoT connectivity를 위한 MQTT
7.1. Local connectivity
7.2. Remote connectivity
7.3. 인터넷 애플리케이션과의 연동
8. 참고
1. MQTT
2. 응용 분야
2.1. 센서(Sensor) 정보 수집
2.2. 제어
2.3. Message Push Server
3. MQTT 특징
3.1. Publish/Subscribe
3.2. 토픽
3.3. 메시지 버스
3.4. QoS
4. MQTT 브로커들
4.1. Mosquitto MQTT broker
4.1.1. 테스트 환경
4.1.2. Mosquitto 브로커 설치
4.1.3. Mosquitto 클라이언트 설치
4.1.4. Pub/Sub 테스트
4.1.5. 장점과 단점
4.2. RabbitMQ
4.2.1. MQTT Plugin 실행
4.2.2. 장점과 단점
4.3. 메시징 서비스 인프라 제안
5. Chatting 프로그램
5.1. 개발 환경
6. MQTT 포맷 분석
6.1. Fixed Header
6.1.1. Message Type
6.1.2. Flags
6.1.3. QoS
6.1.4. Remaining Length
6.2. Variable header
6.2.1. protocol name
6.2.2. Protocol version
6.2.3. Topic name
7. IoT connectivity를 위한 MQTT
7.1. Local connectivity
7.2. Remote connectivity
7.3. 인터넷 애플리케이션과의 연동
8. 참고
Recent Posts
Archive Posts
Tags