본문 바로가기

6. With IT/6.7 Network

MQTT란???

출처 : http://helloworld.naver.com/helloworld/1846

Facebook은 2011년 3월 그룹 메시징 앱을 개발한 Beluga를 인수하여 같은 해 8월 Facebook Messenger 앱을 출시하였습니다. Messenger 앱을 출시하며 자사 블로그 'Facebook Engineerings Notes'에 Beluga를 만들었을 당시의 배경을 다음과 같이 소개하고 있는데요.

 a group of us were meeting up for a movie at the Tribeca Film Festival in New York City but the hour leading up the movie was a total communication failure. I had a friend texting to tell me another friend was running late. We were saving a ticket for another friend, but he decided not to come and no one knew. It wasn't until hours later when I returned home that I saw an IM from the friend who was late and an email from the friend who had bailed."

(친구 여럿이서 뉴욕 Tribeca 영화제에서 상영하는 영화를 같이 보기로 약속을 했습니다. 그런데 영화 시작 전에 친구들과 연락이 잘 되지 않았어요. 누군가 나에게 다른 친구가 늦는다고 문자를 보냈습니다. 우리는 늦는 친구를 위해 영화표를 예매해 놓았습니다. 헌데 당사자는 영화를 보러 오지 않기로 결정했고 우리 중 누구도 이 사실을 알지 못했습니다. 집에 돌아와서 알았습니다. 약속 시간에 늦은 친구가 메신저로 메시지를 보냈었고, 약속을 어긴 그 친구는 이메일을 보냈었더군요.)

이메일이나 SMS 등은 일대일 커뮤니케이션에는 적합합니다. 하지만, 다자간 커뮤니케이션에는 수신 확인의 어려움이 있고, 나중에 대화에 참여한 사람들에게 이전 내용을 공유할 수 없다는 불편함 등이 있습니다.

'이전 대화 내용을 공유할 수 있어야 한다'에 대한 요구는 개인마다 호/불호가 갈리기도 합니다. 위 예화의 경우, 이전 대화 내용이 새로운 친구에게 공개되면 누가 참석하고 누가 불참하는지 명확하게 파악할 수 있어 장점으로 작용할 것입니다. 하지만 나중에 참여한 멤버가 알면 곤란한 내용이 오고 갈 수도 있는 상황을 고려하면 '이전 대화 내용 공유' 기능은 단점으로 작용할 수 있습니다.

  • Facebook 메신저의 푸시와 MQTT

    대부분의 모바일 환경에서 사용하는 메시징 앱에는 메시지를 전달하는 방식이 푸시(push)로 구현되어 있는 반면 iOS 환경의 앱에는 Apple의 APNS(Apple Push Notification Service)를 사용하여 구현되어 있다. Android는 Google의 C2DM(Cloud to Device Messaging)을 사용할 수 있으나, Google의 전송량 제한 정책으로 인해 다음 그림에서 보는 바와 같이 별도의 푸시 서비스를 만들어 배포한다.

    122811_0619_FacebookM1.png

    그림 1. Android에서 앱별로 설치된 푸시 서비스

    Facebook에서 배포한 Android용 Messenger 앱도 MqttPushService라는 서비스가 백그라운드에서 실행된다.

    위와 같은 푸시 서비스들은 서버와 TCP 통신을 하나 열고 일정 주기마다 heartbeat 패킷을 주고 받으며 TCP 통신이 끊어지지 않게 유지하다가 해당 TCP 통신채널을 통해 서버가 메시지를 푸시하는 경우 메시지를 받아 앱에 전달하는 역할을 한다. 이렇게 구현하면 주기적으로 폴링(polling)하는 데 비해 배터리 및 패킷 소모량이 적다는 장점이 있다.

    Facebook 담당자는 수억 명의 회원이 가입한 Facebook 서비스에서 수많은 사용자가 동시에 메시지를 전송하더라도 짧은 시간 내에 메시지가 전송될 수 있는 구조를 개발하는 데 주력했으며, 이를 위해 Beluga 서비스에 도입했던 MQTT(Message Queue for Telemetry Transport) 프로토콜 방식을 Facebook Messenger 앱에도 도입했다고 밝혔다. MQTT 방식의 도입을 통해 수 초 걸리던 폰 간(phone-to-phone) 전송 속도를 수백밀리 초로 단축할 수 있었다고 한다.

  • MQTT의 두 가지 특징

    MQTT는 발행/구독(publish/subscribe) 방식의 메시지 큐(message queue)로, 원격 검침(telemetry) 영역에 사용하기 위해 개발되었다[1]. 원격 검침기는 대부분 소형이며 통신 대역폭과 전원이 한정적인 환경에서 동작한다. 이는 배터리 용량이 제한적이고 통신 품질을 일정 수준으로 유지하기 어렵다는 점에서 스마트폰 환경과 매우 유사하다.

  • MQTT 특징 1: 발행/구독 및 토픽 중개 구조

    MQTT는 이러한 원격 검침기가 측정한 데이터를 송신하고 수신하기 위해 다음과 같은 구조로 구성된다.

    122811_0619_FacebookM2.png

    그림 2 MQTT의 일반적 구조

    발행자는(Pub) 토픽을 발행하고, 구독자(Sub)는 관심 있는 토픽을 구독하는 구조이다. 예를 들어, RDU 공항과 LHR 공항의 비행기 출발 및 도착 시간은 다음과 같이 계층적인 토픽으로 발행할 수 있다.

    122811_0619_FacebookM3.png

    그림 3 계층적으로 구성된 토픽 예제[3]

    사용자는 브로커에 그림 4와 같이 LHR 공항에 도착하는 Air Freedom 항공사의 1024편이 연착하거나 취소되지 않았는지 등 도착과 관련된 정보 구독을 요청한다.

    122811_0619_FacebookM4.png

    그림 4 항공사 1024편의 도착 정보를 구독하는 예[3]

    항공사 1024편의 도착 정보를 발행하는 다른 클라이언트는 관련 정보를 'Flight Times/LHR/Air Freedom/Arrivals/Flight 1024' 토픽으로 발행한다.

    122811_0619_FacebookM5.png

    그림 5 항공사 512편의 도착 정보를 발행하는 예[3]

    브로커는 해당 토픽을 구독하는 클라이언트 전체로 관련 정보를 푸시한다.

    122811_0619_FacebookM6.png

    그림 6 도착 정보가 발행됐을 때 이를 구독하는 클라이언트로 푸시하는 과정[3]

    토픽에는 '#, +'와 같은 와일드카드 사용도 가능하다. 예를 들어, 'Flight Times/LHR/#'과 같이 구독하면 LHR 공항을 이용하는 모든 항공사의 출발 및 도착 정보를 구독하게 되며, 'Flight Times/LHR/Air Freedom/+/Flight 1024'와 같이 구독하면 LHR 공항을 이용하는 Air Freedom 항공사의 1024편의 출발 및 도착 정보를 구독하게 된다.

  • MQTT 특징 2: Quality-of-Service의 지정

    MQTT 개발 시 고려한 원격 검침 환경에서는 온도, 경보 등의 검침 정보가 주기적으로 발생된다. 예를 들어 10분 간격으로 온도를 검침하여 발행하는 검침 환경을 가정해 보자. 오류로 인해 10분 전 정보와 현재 시점의 검침 정보가 동시에 브로커에게 전달된다면 일반적인 검침 환경에서 최신 정보가 우선한다는 가정 하에 양쪽 정보를 모두 구독자에게 전달하는 것보다는 현재 정보만을 전달하는 것이 효율적일 것이다. 이러한 구조를 구현하기 위해 MQTT에서는 QoS(Quality of Service) 수준을 0, 1, 2의 세 단계로 정의한다.

    • QoS 0: 한 번만 전달하고 전달 여부는 확인하지 않음
    • QoS 1: 적어도 한 번 이상 전달하고 전달 여부 확인
    • QoS 2: 4단계의 핸드셰이킹(handshaking)을 통해 정확히 한 번만 전달

    발행자와 구독자 모두 QoS를 지정할 수 있으나 발행자가 지정한 최대 QoS 수준이 우선시된다. 예를 들어 아래 그림과 같이 'Pub X'가 QoS 수준을'2'로 지정했다면, 'Sub A'나 'Sub B'는 0, 1, 2 중 어떤 수준으로도 구독할 수 있다.122811_0619_FacebookM7.png

    그림 7 발행자가 지정한 QoS 수준이 2인 경우

    하지만 아래 그림과 같이 'Pub Y'가 QoS 수준을 '0'으로 지정했다면, 'Sub C'가 QoS 수준을 2로 지정했다 하더라도 이는 브로커에 의해 무시되고 'QoS 0' 수준의 서비스를 받게된다.

    122811_0619_FacebookM8.png

    그림 8 발행자가 지정한 QoS 수준이 0인 경우

    위의 온도 검침 사례에서처럼, 데이터의 최신성이 중요한 토픽은 QoS 수준을 낮게 설정하고 브로커는 토픽의 QoS와 발행 시간을 보고 최신 토픽만 구독자에게 전달하도록 개발할 수 있다. 이와 달리 서버의 오류 로그처럼 반드시 기록되어야 하는 정보는 QoS 수준을 높게 설정하여 전송 시간이 오래 걸리더라도 구독자에게 반드시 전달되도록 개발할 수도 있다.

  • Facebook은 MQTT를 어디에 사용하였나

    Facebook Messenger도 Android 단말과 푸시 서버 간의 통신을 위해 다른 Android 앱처럼 별도 서비스(MqttPushService)가 백그라운드에서 실행하도록 개발되었다.

    그런데 다음 그림에서 보듯이 iOS용 Facebook Messenger 앱의 라이선스(Licenses)에 오픈소스 MQTT 브로커 소프트웨어인 mosquito[2]를 사용했다는 내용이 나오는 것으로 보아, 앱과 푸시 서버 간 전송 외에 Facebook 웹과 모바일 간 전송 등 서로 다른 플랫폼 간에도 여러 명의 사용자가 동시에 채팅할 수 있도록 MQTT를 도입한 것으로 보인다.

    122811_0619_FacebookM9.png

    그림 9 iOS용 Facebook Messenger 앱의 라이선스 화면

  • 다음은 일반적인 채팅 서비스의 시퀀스 다이어그램을 나타낸다.

    122811_0619_FacebookM10.gif

    그림 10 일반적인 채팅 서비스의 시퀀스 다이어그램

    일반적인 채팅 서비스에서는 각 채팅방의 세션을 관리하고, 해당 방에 참여한 사용자로부터 메시지를 받으며, 이를 다시 클라이언트로 전달하는 역할을 서버가 담당한다.

    그런데 Facebook은 일반적인 채팅 서비스 방식을 도입하지 않았다. 이는 수억 명의 사용자를 보유한 Facebook 서비스의 경우, 서버에 세션을 만들고 세션에 참여한 사용자를 관리하는 것만으로도 상당량의 서버 부하가 발생할 수 있기 때문이다.

    이와 같은 이유로 Facebook은 MQTT를 도입했다. MQTT 방식은 다자간 채팅 환경에서 각 채팅방을 하나의 토픽으로 지정하고, 채팅에 참여한 사용자를 각각 발행자와 구독자로 메시지를 전달하게 한 뒤 MQTT 브로커가 메시지 전달을 책임지게 하는 구조로, 세션 관리에 대한 부하를 분산할 수 있다.

    또한 웹과 비교했을 때 모바일 환경에서는 3G 연결이 자주 끊기고 재전송이 빈번하게 발생한다. 이런 경우 일반적인 채팅 서비스에서는 연결이 끊긴 사용자의 메시지를 서버에 저장해 보관하고 나중에 연결되면 다시 전달하거나 아니면 연결 끊김이 확인되었을 때 바로 채팅방을 떠나도록 기능이 구현되어야 한다. 하지만 MQTT의 발행/구독 구조로 구현하면 웹 사용자가 모바일 사용자에게 발행한 메시지를 모바일 사용자가 연결되는 시점에 브로커가 푸시하도록 구현할 수 있다.

    122811_0619_FacebookM11.png

    그림 11. 발행/구독 구조가 구현된 Facebook 메신저 서비스[3]

    이렇게 하면 채팅 참여자는 채팅방 토픽을 구독하고 채팅을 시작하면 토픽을 발행하다가 채팅방을 떠날 때 구독을 해제(unsubscribe)하기만 하면 된다.

    다만 위와 같은 구조로 개발하면 발행되는 모든 메시지의 순서를 브로커가 관리해야 한다. 따라서 완성도 높은 채팅 서비스를 제공하려면 브로커 구현에 공을 많이 들여야 할 것이다. 실제 Facebook Messenger 앱으로 채팅하던 도중 모바일 네트워크를 잠시 끊었다가 복귀했을 때 웹에서 보낸 메시지 순서가 뒤바뀌어 들어오는 경우가 있었다.

    122811_0619_FacebookM12.png

    그림 12. Facebook 메신저에서 보낸 메시지 순서가 뒤바뀌어 들어온 사례

  • 마치며

    서버의 로그 기록 등 메시지 순서가 중요한 서비스의 경우 브로커 구현에 많은 공을 들여야 한다. 하지만 Facebook 메신저의 경우 특정 환경에서 메시지 순서가 뒤바뀔 수 있다는 단점을 감수하더라도 수억 명의 사용자가 웹/모바일 환경 양쪽에서 채팅할 수 있는 서비스 구현을 제일 목표로 삼은 것으로 보인다. 이에 따라 성능 향상을 위한 최우선 방안으로 발행/구독 구조를 선택한 것으로 판단된다. 결론적으로 다양한 사용자 환경을 고려해야 하는 실시간 글로벌 서비스에서는 MQTT와 같은 발행/구독 구조의 도입을 검토해 볼 수 있다고 생각한다.

  • 참고 웹 사이트

    이 글의 내용은 다음 웹 사이트를 참고했다.

    [1] MQTT: MQ Telemetry Transport, http://mqtt.org.
    [2] Mosquitto: An Open Source MQTT 3.1 Broker, http://mosquitto.org.
    [3] Push notifications for mobile apps, http://dalelane.co.uk/blog/?p=938.


  • '6. With IT > 6.7 Network' 카테고리의 다른 글

    Soap코딩 - iOS  (0) 2013.04.05
    RESTfull서비스?  (0) 2013.04.05