2014年8月10日

MQTT with RabbitMQ

RabbitMQ的底層是實作AMQP,如果想透過它來跑MQTT,必須先安裝RabbitMQ MQTT Adapter,只要在安裝完RabbitMQ之後,執行以下指令即安裝完成:
rabbitmq-plugins enable rabbitmq_mqtt
RabbitMQ的MQTT Adapter是基於RabbitMQ本身的Exchange和Queue上來實現的。預設RabbitMQ會把收到的MQTT訊息送到預設的topic exchange,也就是"amp.topic"這個exchange。當Client執行訂閱(subscribe)時,RabbitMQ會先為此Client建立一條Queue,可以參考下圖:

其中名稱mqtt-subscription-XXXXqos1為RabbitMQ幫你建立的Queue,而XXXX為你傳入的clientId。
接著他會為此條Queue和amp.topic建立起routing key,routing key就是你Subscribe時傳過來的topic name,只是他會將 "/"換成".",比如說你Subscribe時是寫"rec/mayer",則他會把routing key換成"rec.mayer"。可以參考下圖:

Client發送對某個MQTT的Topic 發佈(publish)訊息時,首先RabbitMQ會把此訊息送到amq.topic內,接著amq.topic將此訊息要送到的topic name取出來,把它當成routing key送給相對應的queue。這樣一來,訊息就能正確的發送給訂閱者。

修改MQTT預設exchange

預設exchange可以透過config檔案修改,首先先到/etc/rabbitmq/目錄底下,建立rabbitmq.config檔案,然後貼上以下設定檔,其中rabbitmq_mqtt[]裡面的exchange設定,就是預設要使用哪個exchange,不過在使用時必須先把該exchange建立起來。
[{rabbit,        [{tcp_listeners,    [5672]}]},
 {rabbitmq_mqtt, [{default_user,     <<"guest">>},
                  {default_pass,     <<"guest">>},
                  {allow_anonymous,  true},
                  {vhost,            <<"/">>},
                  {exchange,         <<"foo.topic">>},
                  {subscription_ttl, 1800000},
                  {prefetch,         10},
                  {ssl_listeners,    []},
                  %% Default MQTT with TLS port is 8883
                  %% {ssl_listeners,    [8883]}
                  {tcp_listeners,    [1883]},
                  {tcp_listen_options, [binary,
                                        {packet,    raw},
                                        {reuseaddr, true},
                                        {backlog,   128},
                                        {nodelay,   true}]}]}
].

Rabbit MQTT Adapter遺珠

使用RabbitMQ來當MQTT broker,要注意他只實現MQTT 3.1的一些特性:
  • QoS0 and QoS1 publish & consume
  • Last Will and Testament (LWT)
  • SSL
  • Session stickiness
由於AMQP 0-9-1沒有支援QoS 2的特性,因此這邊沒有實作,所以要注意的是如果你想用MQTT的QoS 2來實作服務時,你就不能使用RabbitMQ。關於QoS 2的特性,可以參考MQTT(二)Message Type and Flows - Publish Flows這篇的說明。
另外他也沒有實現Retain Message,當遇到時,RabbitMQ會將他默默的忽略掉。關於Retain Message可以參考 MQTT(四)PUBLISH Message之前我貼的文章來了解其作用。

參考

RabbitMQ-MQTT
RabbitMQ Blog-MQTTAdapter