dRuby

注意! drb-1.3.6に作者の意図に反しprivateのメソッドを外部から呼び出せる 不具合が見つかりました (2002-09-03)。 drb-1.3.8を使って下さい。 → drb-1.3.8.tar.gz

分散Ruby。 マシン、プロセスの異なるRubyスクリプト間でメッセージを交換できます。 お手軽です。JavaのRMI風。


変更点


用語

本ページで使用する用語を説明します。

dRuby
分散Rubyの仕組みの名前
DRb
dRubyの実装。モジュール名。
dRubyサービス
他局からのメッセージを受信し、評価、結果を戻すサービス。 DRb.start_service()で起動される。 dRubyではどのスクリプトもdRubyサービスを提供する。
他局
他のプロセス、マシンで実行されているRubyスクリプト、dRubyサービス
自局
自Rubyスクリプト、dRubyサービス

仕組み

DRbObject

dRubyでは、DRbObjectというオブジェクトの参照へメッセージを送ることで 他局のオブジェクトのメソッドを呼び出します。

DRb

DRbは他局からのリクエストを処理するモジュールです。 自局が特にサービスを提供しない場合でも、 メソッドを処理する過程で呼び出されることがあるので 初期化が必要です。

自局を示す文字列のフォーマットは次の通り。 hostnameは他のマシンからもわかるホスト名、 portはポート番号を示す整数。

"druby:\/\/#{hostname}:#{port}"
例)
druby://yourhost:7640
start_service(uri, front=nil)
dRubyサービスを起動する。 他局からのメッセージを受信するためのスレッドが起動される。 uriは自局のホスト名とポート番号からなる文字列。 frontはリモートオブジェクトが指定されなかった場合に デフォルトでメッセージを受信するオブジェクト。
ポート番号をシステムに選ばせることも可能です。 start_service()へ渡す uri は、次のような不完全なURIを指定できます。 start_service()後、DRb.uri で完全なURIを参照できます。
uri
自局のURIを返す
thread
dRubyサービスのスレッドを返す。 他局にサービスを提供するサーバー型のスクリプトの場合、 スクリプトの最後にこのスレッドをjoinすることが多い。
front
デフォルトでメッセージを受信するオブジェクトを返す。
install_id_conv(f)
DRbObjectとObjectの参照idの変換器をインストールする。 デフォルトの変換器は、参照idとしてObject.idを用いる DRbIdConvのインスタンスである。 参照idとしてもっと永続的(?)な名前を用いるような変換器を 使うチャンスを与えます。

DRb.front

DRbObject.new(nil, サーバ名)としてデフォルトのオブジェクトを参照する DRbObjectを生成できます。 デフォルトのオブジェクトとは、DRb.start_serviceで渡すオブジェクトで、 DRb.frontで参照できます。。 スクリプト起動時には他局の名前しかわかりませんから、 通信はこのオブジェクトへのメッセージ送信をきっかけに始まります。

単純なサービスだけを他局に提供する場合は、そのオブジェクトをDRb.frontと すれば良いでしょう。例えば dqueue.rb のでは Queue.new したインスタンスを DRb.frontにしています。

より複雑なアプリケーションの場合には、 サービス種などの名前からオブジェクトに変換する機能や、 簡単な認証などを行なう「受け付け」をDRb.frontにすることになると思います。

DRbUndumped

DRbUndumpedはマーシャリングが失敗する mix-inです。 オブジェクトの複製のかわりにリモートオブジェクトを 他局に渡したいときのためにincludeして使用する。

既存のスクリプトをdRuby化するには

スレッドセーフに書かれているクラスであれば、おそろくそのまま DRb.frontにするだけでそのオブジェクトを複数のスクリプトから 共有できます。dqueue.rbではそれだけで複数のスクリプトを 同期できるQueueが実現します。


サンプル

01: require 'drb/drb'
02: 
03: class DRbEx
04:   def initialize
05:     @hello = 'hello'
06:   end
07: 
08:   def hello
09:     @hello
10:   end
11: 
12:   def sample(a, b, c)
13:     a.to_i + b.to_i + c.to_i
14:   end
15: end
16: 
17: DRb.start_service(nil, DRbEx.new)
18: puts DRb.uri
19: DRb.thread.join

サンプルサーバー drbs.rb 省略版

01: require 'drb/drb'
02: 
03: class DRbEx2
04:   include DRbUndumped
05: 
06:   def initialize(n)
07:     @n = n
08:   end
09: 
10:   def to_i
11:     @n.to_i
12:   end
13: end
14: 
15: 
16: there = ARGV.shift
17: DRb.start_service()
18: ro = DRbObject.new(nil, there)
19: p ro.hello
20: p ro.sample(DRbEx2.new(1), 2, 3)
21: p ro.sample(1, ro.sample(DRbEx2.new(1), 2, 3), DRbEx2.new(3))

サンプルクライアント drbc.rb 省略版


イテレータ

ブロック引数付きのメッセージに対応しています。 ブロック引数を DRbObject にしてリモートに送出します。 次のようなことができます。(サンプル darrayc.rb 抜粋)

01:  ro = DRbObject.new(nil, there)
02:  # remote iterator!!
03:  a = ro.collect { |x|
04:    x + x
05:  }
06:  p a

m_seki@mva.biglobe.ne.jp

$Id: druby_old.html,v 1.1 2003/02/23 14:16:13 mas Exp $