dRuby
注意! drb-1.3.6に作者の意図に反しprivateのメソッドを外部から呼び出せる
不具合が見つかりました (2002-09-03)。
drb-1.3.8を使って下さい。
→ drb-1.3.8.tar.gz
分散Ruby。
マシン、プロセスの異なるRubyスクリプト間でメッセージを交換できます。
お手軽です。JavaのRMI風。
- 1.3.8
- argc_limit/loda_limitをデフォルトでnil (制限なし) にした
- NameErrorのメッセージストリングを適切にした
- trojan msg_idを検査するようにした
- insecure_methodでは __send__ だけを例外とするようにした
- 1.3.7
- privateなメソッドを呼び出せるバグを修正した。
- 1.3.6
- untaintするタイミングを間違っていた。($SAFE=1対応)
- 1.3.5
- ExtServManager#registのインターフェイスが変更されました。
- ut_port.rbのポート番号を変更しました。
- DRbServer.verbose等を新設して警告の出力を抑制しました。
- Object.idでなく__id__を使用するように変更しました。
- 1.3.4.2
- 本体は変わりません。
- drb over httpをlibからsampleへ移動
- drbunit.rbのbugを修正
- 1.3.4
- サンプルの追加ー分散cdbiff
- yieldの引数を間違えるbugの修正
- 大きなメッセージの交換に失敗するbugの修正 (sysread/syswriteから
read/writeへ戻した)
- SOL_TCPへの対応
- DRbObserverの追加
- 1.3.3
- コネクションをできるだけ再利用するようにした(高速化)
- DRbObjectのURIがリモートと一致する時、オブジェクトを返すようにした
- DRbUnknownErrorが往復できるようにした
- drb/eq.rbにhash, eql?を追加
- close on execフラグを追加
- 1.3.2
- TCP/IPインターフェイスを指定してサービス可能
- rindaの修正
- イテレータからのbreakによる脱出対応
- drb/eq.rbの追加
- イテレータからのbreakによる脱出対応
- サンプルの修正(name.rb等)
- timeridconvの修正
- 1.3.1
- ScriptError対応 (例: 処理できないメソッドのとき、NameErrorを返すとか)
- DRbUnknown修正。loadできないオブジェクトはDRbUnknownに変換する。
DRbUnknownをdump/loadすると、load時にもう一度もとのオブジェクトに
復元できるか試す。(sample/dqlib.rb, dqueue, dqin, dqoutを試して下さい)
- 1.3
- 1.3b3
- load時にパケットの長さの検査を行う → TypeError。エラーが適切でない?
- requestの引数の数の検査を行う → ArgumentError。エラーが適切でない?
- DRbServerにdefault_argc_limit, default_load_limit を追加
- runit修正
- 1.3b2
- 本体は変更なし
- runit追加
- drb/extserv修正
- 1.3b1
- DRbServerの役割を明確にして複数のDRbServerを起動できるようにした
- プライマリ・サーバというのができた
- drb/extserv というサービス・プロセスの起動ライブラリを書いてみた
- 危険なメソッド(eg. :instance_eval)を NameError にするようにした。
- 1.3d2
- DRbUnknownError, DRbUnknown#exception の導入
- 1.3d0
- 開発版の最初の公開。
- socketに流すメッセージの先頭にメッセージの長さを追加した。
このため、1.2系のスクリプトは動くが、
1.2系の局と1.3系の局は混在できない。
- 名前空間の変更。モジュール DRb の中にクラスを移動した。
- $SAFE=1の環境 (mod_ruby等)への対応
- DRbUnknown の導入
- 1.2.2
- require 'marshal' を削除
- socket を shutdown() するようにしてみた。
この辺、自信がないのです。大丈夫かなぁ。
- DRbObject#to_a, to_s を追加して、リモート(本物)のオブジェクトに
転送するようにしました。
- 時限つきGCのサンプルを追加しました。
- 1.2.1
- DRbObject の @ref の初期化忘れを直しました。
ruby -v のときの@refに関する警告がでないようになります。
- instance_eval を使うと Marshal できなくなるので、@ref を参照する
メソッドを追加しました。
- 1.2
- 1.2b2と同じです。ruby-talkで少しだけ話題になったので1.2にしました。
- 1.2b2
- 1.2b1
- drbというサブディレクトリの下に drb.rb を置くように変更。
require 'drb/drb'
で使う。
require 'drb'
も可。
- イテレータでbreak, next, redo, retry が使えるようになった。
- 1.1
- DRbObjectとObjectのidの変換方法を差し替えられるようになった。
- 自局のURIを自動生成できるようになった。→ ポート番号をシステムが選ぶ。
- (限定的に)イテレータが使えるようになった。
本ページで使用する用語を説明します。
- dRuby
- 分散Rubyの仕組みの名前
- DRb
- dRubyの実装。モジュール名。
- dRubyサービス
- 他局からのメッセージを受信し、評価、結果を戻すサービス。
DRb.start_service()で起動される。
dRubyではどのスクリプトもdRubyサービスを提供する。
- 他局
- 他のプロセス、マシンで実行されているRubyスクリプト、dRubyサービス
- 自局
- 自Rubyスクリプト、dRubyサービス
DRbObject
dRubyでは、DRbObjectというオブジェクトの参照へメッセージを送ることで
他局のオブジェクトのメソッドを呼び出します。
- メッセージの引数はマーシャリングされて渡されますが、
マーシャリング出来ないオブジェクトはDRbObjectに変換されて渡されます。
- メッセージの戻り値もマーシャリングされて返されますが、
マーシャリング出来ないオブジェクトはDRbObjectに変換されて返されます。
- DRbObjectは、他局からのメッセージの引数や戻り値として取得するほか、
他局の名前からデフォルトのオブジェクトを参照する
DRbObjectを生成することもできます。
- 他局からアクセスされるのはDRbObjectだけなので、
他局に見せても良いものだけをDRbObjectにすることで内部へのアクセスを制限します。
DRbは他局からのリクエストを処理するモジュールです。
自局が特にサービスを提供しない場合でも、
メソッドを処理する過程で呼び出されることがあるので
初期化が必要です。
自局を示す文字列のフォーマットは次の通り。
hostnameは他のマシンからもわかるホスト名、
portはポート番号を示す整数。
"druby:\/\/#{hostname}:#{port}"
例)
druby://yourhost:7640
- start_service(uri, front=nil)
-
dRubyサービスを起動する。
他局からのメッセージを受信するためのスレッドが起動される。
uriは自局のホスト名とポート番号からなる文字列。
frontはリモートオブジェクトが指定されなかった場合に
デフォルトでメッセージを受信するオブジェクト。
ポート番号をシステムに選ばせることも可能です。
start_service()へ渡す uri は、次のような不完全なURIを指定できます。
- "druby://yourhost:0" → システムがポートを選ぶ。
- "druby://:0" → システムがポートを選ぶし、ホスト名も調べる。
- nil → システムがポートを選ぶし、ホスト名も調べる。
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はマーシャリングが失敗する 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: 'drb/drb'をrequireします。
- 03: DRbExはこのスクリプト中にしか定義されません。
他のスクリプトはこの定義を知りません。
- 12: sampleは、三つのオブジェクトを整数化(to_i)したものの合計を返します。
- 17: dRubyサービスを起動します。自局の名前はシステムに決定させます。
デフォルトのオブジェクトは DRbEx.new です。
- 18: 自局の名前を印字します。
- 19: スクリプトが終了してしまわないようにサービスを行なうスレッドに
joinします。
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 省略版
- 03: DRbEx2はこのスクリプト中にしか定義されません。
他のスクリプトはこの定義を知りません。
- 04: DRbUndumpをincludeすることで
DRbEx2 が常にDRbObjectとして渡されるようにします。
- 17: dRubyサービスを起動します。
デフォルトのオブジェクトはありません。
- 18: there のデフォルトのオブジェクトを示すDRbObjectを作ります。
- 19: ro.hello は他局(drbs.rb)へ送られます。'hello'が返ります。
- 20: ro.sample は他局へ送られます。
このとき最初の引数DRbEx2.new(1)だけはマーシャリングできないので
DRbObjectが他局に渡ります。
DRbEx.sample では、受信した各引数に対し to_i を送りますが、
最初の引数がDRbObjectなので、drbc.rb の 10: to_i が
起動されます。
ブロック引数付きのメッセージに対応しています。
ブロック引数を 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 $