IoTの導入にあたりMQTTを使うケースは多いと思います。導入機器が増えてくると、MQTTへのトラフィックが増えてくるので、ブローカーの負荷分散をしたいとか、ブローカーが落ちてメッセージを処理できない事態を避けたいという要件が出てきます。
ブローカーとしてAWSなどのクラウドで提供されているIoTサービスを活用するのであれば問題ありませんが、自分で立てたサーバにMosquittoなどを導入してブローカーとして使用している場合です。
Mosquittoにはブリッジという機能があり、自分のところにきたメッセージを、そのまま別のブローカーに連携することはできます。ただ、これは負荷分散のための機能ではありません。
他に目につくような機能もないし…。もともと、MosquittoはMQTTのリファレンス実装として開発されているものであり、MQTTの仕様にある機能についてはスピーディに実装されますが、そうでないものについては実装されません。負荷分散の機能は、MQTTの仕様にないので、実装されていないのは当たり前ともいえます。
Nginxを使って負荷分散クラスタを構成する
今回構成するのは負荷分散クラスタです。複数のブローカーを起動させ、平常時は負荷分散でメッセージを処理します。そして、あるブローカーが落ちてしまった場合は、残りのブローカーでメッセージを落とさず処理を継続します。
まず、複数のマシンを準備して、それぞれにMosquittoをインストールしてブローカーを常時起動させます。ここでは、192.168.10.253
と192.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です。
ここまでの設定では負荷分散はデフォルトのラウンドロビンで行われます。
また、片方のブローカーが落ちた場合は、もう片側のブローカーですべての処理が行われ、復帰すると再びラウンドロビンで処理されるようになります。