Mosquittoの負荷分散クラスタをNginxで構成する

IoTの導入にあたりMQTTを使うケースは多いと思います。導入機器が増えてくると、MQTTへのトラフィックが増えてくるので、ブローカーの負荷分散をしたいとか、ブローカーが落ちてメッセージを処理できない事態を避けたいという要件が出てきます。

ブローカーとしてAWSなどのクラウドで提供されているIoTサービスを活用するのであれば問題ありませんが、自分で立てたサーバにMosquittoなどを導入してブローカーとして使用している場合です。

Mosquittoにはブリッジという機能があり、自分のところにきたメッセージを、そのまま別のブローカーに連携することはできます。ただ、これは負荷分散のための機能ではありません。
他に目につくような機能もないし…。もともと、MosquittoはMQTTのリファレンス実装として開発されているものであり、MQTTの仕様にある機能についてはスピーディに実装されますが、そうでないものについては実装されません。負荷分散の機能は、MQTTの仕様にないので、実装されていないのは当たり前ともいえます。

Nginxを使って負荷分散クラスタを構成する

今回構成するのは負荷分散クラスタです。複数のブローカーを起動させ、平常時は負荷分散でメッセージを処理します。そして、あるブローカーが落ちてしまった場合は、残りのブローカーでメッセージを落とさず処理を継続します。

まず、複数のマシンを準備して、それぞれにMosquittoをインストールしてブローカーを常時起動させます。ここでは、192.168.10.253192.168.10.254にそれぞれブローカーを起動させ、ポート1883番で待ち受けさせます。
ブローカーにログインなどの設定をしている場合は、どちらのブローカーにも同じ設定をします。

Nginxの設定は、まず/etc/nginx/modules-available/mqtt.confを作成し、下記のようにします。

stream {
  upstream mqtt {
    server 192.168.10.254:1883;
    server 192.168.10.253:1883;
  }

  server {
    listen 1884;
    proxy_pass mqtt;
  }
}

streamの設定は、Nginxの設定上、httpと同じレベルにしなければなりません。Ubuntu 18.04 LTSにaptで導入したNginxでは、nginx.confにおいてhttpと同じレベルで/etc/nginx/modules-enabled/*.confのインクルードが設定されているので、この場所にしました。(あまり正しい場所ではないかもしれません。)

最後に、シンボリックリンクを作成して、有効にしてからNginxをreloadします。

cd /etc/nginx/modules-enabled
ln -s ../modules-available/mqtt.conf
systemctl reload nginx

これだけでOKです。

ここまでの設定では負荷分散はデフォルトのラウンドロビンで行われます。
また、片方のブローカーが落ちた場合は、もう片側のブローカーですべての処理が行われ、復帰すると再びラウンドロビンで処理されるようになります。

この記事を書いた人

井上 研一

経済産業省推進資格ITコーディネータ/ITエンジニア。株式会社ビビンコ代表取締役。コールセンターへのAI導入プロジェクトに参画したことをきっかけに、AI・IoTに強いITコーディネータとして活動。株式会社ビビンコでは、IoTソリューションの開発・導入や、画像認識モデルを活用したアプリの開発などを行っている。近著に「使ってわかった AWSのAI」、「ワトソンで体感する人工知能」。日本全国でセミナー・研修講師としての登壇も多数。