BLOGTIMES
2012/02/09

ØMQ ( zeromq ) 事始め

  zeromq  ruby  mom 
このエントリーをはてなブックマークに追加

ØMQ がちょっと面白そうだったので、サンプルを書いて動作確認してみました。
MQ という名前がついているので MOM の一種かと思うのですが、ちょっしたキューの機能はあるものの、メッセージの永続化やトランザクション機能を持っていないので、下記の解説にもあるとおり使いやすいソケットライブラリと考えた方が良さそうです。

The Intelligent Transport Layer - zeromq

ØMQ \zeromq\:
 Ø  The socket library that acts as a concurrency framework.
 Ø  Faster than TCP, for clustered products and supercomputing.
 Ø  Carries messages across inproc, IPC, TCP, and multicast.
 Ø  Connect N-to-N via fanout, pubsub, pipeline, request-reply.
 Ø  Asynch I/O for scalable multicore message-passing apps.
 Ø  Large and active open source community.
 Ø  30+ languages including C, C++, Java, .NET, Python.
 Ø  Most OSes including Linux, Windows, OS X.
 Ø  LGPL free software with full commercial support from iMatix.

以下、動作確認メモ。

インストール

今回のインストール対象は SL6 ですが EPEL を使えるようにしておけば yum でインストールできます。

# yum -y install zeromq-devel

あとは Ruby から呼び出すための ffi-rzmq を gem でインストールしておきます。

$ gem install ffi-rzmq

サンプルプログラム

極簡単なPublish-Subscribe モデルを実装します。
送信用の pub.rb と受信用の sub.rb をそれぞれ下記のような感じで作ってみました。

pub.rb

#!/bin/env ruby require 'rubygems' require 'ffi-rzmq' ctx = ZMQ::Context.new sock = ctx.socket(ZMQ::PUB) sock.bind("tcp://127.0.0.1:9999") #sleep 0.5 n = 0 loop do msg = "#{n}, #{$$}" sock.send_string(msg) puts msg n += 1 sleep 1 end

sub.rb

#!/bin/env ruby require 'rubygems' require 'ffi-rzmq' ctx = ZMQ::Context.new sock = ctx.socket(ZMQ::SUB) sock.setsockopt(ZMQ::SUBSCRIBE, '') sock.connect("tcp://127.0.0.1:9999") loop do msg = "" sock.recv_string(msg) puts "#{msg} ,#{$$}" end

それぞれを起動すると送信されたメッセージが受信側でも表示されるのが確認できます。
普通のソケットであればサーバ側を先に起動しないといけませんが、このライブラリが不思議なのはどちらを先に起動しても大丈夫というところでしょうか。

slow joiner syndrome にハマる

動作確認をしていくうちに上記のプログラムには欠陥があることに気づきました。
n は 0 からスタートしているはずなのですが、最初 ( n = 0 ) のメッセージがどうやっても受信できないのです。
単純なポカミスをしているんではないかと何度も見直しても分からないので、ググって調べたら FAQ 的な問題みたいです。

MQ - The Guide - MQ - The Guide

There is one more important thing to know about PUB-SUB sockets: you do not know precisely when a subscriber starts to get messages. Even if you start a subscriber, wait a while, and then start the publisher, the subscriber will always miss the first messages that the publisher sends. This is because as the subscriber connects to the publisher (something that takes a small but non-zero time), the publisher may already be sending messages out.

上記の解説をしっかり読むと分かりますが、今回の例で作ったような Pub-Sub モデルは zeromq には適さないようですね。

下位のレイヤで起きていることを考えると Sub 側が実際に connect 出来るのは Pub 側が bind をした後になるわけですが、そのタイムラグの間(少しだけど、0ではないと書かれている)に Pub 側でメッセージの送信が終わってしまうと Sub 側ではそのメッセージを受信できないということのようです。これは気をつけなければいけませんね。今回は本質的ではありませんが、 sleep を入れて正常動作を確認しました。本格的なプログラムを開発する際にはこのあたりはもうちょっと考えないとアーキテクチャ的にはかなりまずいです。どうすればいいかは上記のドキュメントを読んで応用すれば大丈夫かと思います。


    トラックバックについて
    Trackback URL:
    お気軽にどうぞ。トラックバック前にポリシーをお読みください。[policy]
    このエントリへのTrackbackにはこのURLが必要です→https://blog.cles.jp/item/4757
    Trackbacks
    このエントリにトラックバックはありません
    Comments
    愛のあるツッコミをお気軽にどうぞ。[policy]
    古いエントリについてはコメント制御しているため、即時に反映されないことがあります。
    コメントはありません
    Comments Form

    コメントは承認後の表示となります。
    OpenIDでログインすると、即時に公開されます。

    OpenID を使ってログインすることができます。

    Identity URL: Yahoo! JAPAN IDでログイン