ZeroMQ: 複数のEndpointに接続する

f:id:dfukunaga:20170419234028p:plain

ちゃんとドキュメントを読めという話かもしれないが、ZeroMQ のソケットが 複数のEndpointにbind/connectできることを最近知った。そこで、複数のEndpointに対してのbind/connectを 使ったメッセージングのパターンをいくつか考えてみた。

1. ローカル/リモート共用ソケット

f:id:dfukunaga:20170418233138p:plain

同じプロセス内でのソケット間通信をするなら、inprocを使ったほうが ローカルループバックに対するtcpを使うよりも圧倒的に速い。このパターンでは、 一つのソケットに同一プロセスからの接続用のアドレス(ローカル: inproc)と、 別マシンからの接続用のアドレス(リモート: tcp)の二つをbindし、接続するソケットの位置 によってconnectするアドレスを使い分ける。これにより、ローカルのソケット間通信はより高速に行われ、また、 受信する側では、ローカルから来たメッセージとリモートから来たメッセージを区別することなく処理を行うことができる。

2. ブロードキャストクラスタ

f:id:dfukunaga:20170418233145p:plain

各ノードでZMQ_PUBZMQ_SUBを一つずつ用意します。 ZMQ_PUBはbindしてZMQ_SUBは各ノードのZMQ_PUBにconnectすると(逆でもたぶんOK)、 ZMQ_PUBにsendすることで他の全ノードにメッセージが送信されるようになります。 複数のソケットを用意すれば同じことが実現できますが、一つのソケットで複数のEndpointにconnectした方が、 recv/pollするのが一つのソケットで済むので楽になるかと思います。 このパターンを実装するときはZMQ_SUBSCRIBEを設定するのを忘れずに。

3. P2Pクラスタ

f:id:dfukunaga:20170418233158p:plain

bindとconnectを併用することもできます。このパターンでは、各ノードにZMQ_ROUTERを一つ用意し、 一つのアドレスに対してbindするのと同時に、他のノードのZMQ_ROUTERにconnectします。 このように繋ぐことで、ZMQ_ROUTERのルーティング機能を使えばクラスタ内のどのノードへも メッセージを送信することができます。ZMQ_ROUTER同士を繋ぐときはidentityの設定が厄介ですが、 bindする前にZMQ_IDENTITYを設定し、connectする際にZMQ_CONNECT_RIDを設定しておけば問題ないでしょう。

以上、複数のEndpointへのbind/connectを用いたメッセージングパターンでした。