library drb

[edit]

要約

分散オブジェクトプログラミングのためのライブラリです。

Ruby のプロセスから他のRubyプロセスにあるオブジェクトのメソッドを呼びだすことができます。他のマシン上のプロセスにもアクセスできます。

概要

dRuby は Ruby 専用の分散オブジェクトシステムです。 Ruby のみで記述され、TCP socket のような Ruby 本体が提供する通信手段があれば追加のインストール物なしに利用可能です。独自のプロトコルで通信し、他の分散オブジェクトシステム (CORBA, RMI, .NETなど)との相互運用性はありません。

dRuby は

ができます。これらはすべて透過的に行われます。

リモートプロセスにあるオブジェクトはローカルには DRb::DRbObject のインスタンスとして表現されます。このオブジェクトはリモートオブジェクトの proxy のように振舞います。つまり、このオブジェクトのメソッドを呼び出すとリモートオブジェクトに転送されます。 CORBA の IDL のようなリモートオブジェクトのインターフェースを静的に宣言する必要はなく、すべては実行時に解決されます。

リモートプロセスからのメソッド呼出しはそれを受け取ったプロセスの DRb::DRbServer オブジェクトが処理します。受け取ったメッセージからメソッド呼出し情報を取り出し、ローカルにあるオブジェクトを特定し、そのメソッドを呼び出し、返り値をリモートの呼び出し元に送ります。どのようなオブジェクトのメソッドも呼びだすことができます。何か特別なインターフェースを実装したり、特別な mixin を必要としたりはしません。オブジェクトの特定は DRb::DRbServer が自動でします。そのためオブジェクトの登録のようなことは通常必要ありません。

DRb::DRbServer に URI(例: druby://example.com:8787)を関連付けることで、他のプロセスからの通信(リモートメソッド呼び出し)ができるようになります (逆に言うと、URIを指定しないことで、他のプロセスからのリモートメソッド呼び出しを拒否することができます)。また、DRb::DRbServer に「フロントオブジェクト」を登録しておくと、サーバの URI からそのオブジェクトをリモートオブジェクトとして取り出すことができます。通常はこのオブジェクトから辿って必要な(リモート)オブジェクトを取り出します。

リモートメソッド呼び出しはかなりの部分、同じプロセス内のオブジェクトのメソッドを呼び出すのと同じ動作をします。ブロック付きのメソッド呼び出しもできますし、リモートプロセス上で生じた例外はローカルプロセス上に転送されます。DRb 関連の例外は DRb::DRbError のサブクラスです。

リモートメソッド呼び出しの引数や返り値には任意の Ruby オブジェクトが使えます。デフォルトではオブジェクトをマーシャリングして渡され、受け取った側が元のオブジェクトに戻します。つまりオブジェクトはコピーされます。これは通常の同一プロセス上でのメソッド呼び出しと大きく異なる点です(通常のメソッド呼び出しではオブジェクトへのリファレンスが渡されます)。

ただし、マーシャリング不可能なオブジェクトは dRuby によってある種のリファレンスとして取り扱われます。これは DRb::DRbObject のインスタンスとして表現されます。これはリモートオブジェクトの proxy として動作し、proxy のメソッドを呼び出すと上に説明した通りの方法でリモートオブジェクトのメソッドを呼び出します。

マーシャリング可能なオブジェクトを DRbObject でリファレンスとして渡したい、つまりコピーでなくリファレンスで渡したい場合はそのオブジェクトに DRb::DRbUndumpedModule#include します。

dRuby はブロック付きのメソッド呼び出しをサポートしていますが、 Proc はマーシャリング不可能なので、ブロックの中身は (リモート側でなく)ローカルプロセス上で実行されます。リモート側がブロックを呼び出そうとすると、ブロックの引数がリモート側からローカル側に(上で説明したようにコピーもしくは dRuby のリファレンスオブジェクトとして)渡され、ブロックが実行され、その返り値がリモート側に送られます。

セキュリティ

dRuby でインターネット上に公開するサービスを作るべきではありません。イントラネットのサービスとして動かす場合もセキュリティには気を使う必要があるでしょう。

あるオブジェクトへの外部からのアクセスを許可すると、単にそのオブジェクトのメソッドを外部から呼び出せるだけでなく、任意の Ruby のコードを実行できてしまいます。例えば以下のようなことができます。

# !! 危険 !!
ro = DRbObject.new_with_uri("druby://your.server.com:8989")
class << ro
  # リモートオブジェクトの instance_eval を呼ぶため
  # ローカルオブジェクトの instance_eval を取り除く
  undef :instance_eval
end
ro.instance_eval("DANGEROUS RUBY CODE!")

このような instance_eval による危険性は $SAFE を 1 にすることで防げます。 DRb.#start_service の :safe_level オプションでリモートからのメソッド呼び出しのコンテキストで指定されるセーフレベルを指定できます。

また、DRb::DRbServer にはアクセスコントロールリスト(アクセスを許可/拒否する IP のリスト)によりアクセス制御をすることができます。この機能は ACL で実現されています。このアクセス制御は単体で使うのではなく、適切なファイアウォールと併用すべきです。

リファレンス

Example

単純なクライアント-サーバシステムの例。

ターミナルを2つサーバ側/クライアント側として起動して、サーバ側を先に動かしてください。

サーバ側コード

require 'drb/drb'

# 通信を待ち受ける URI
SERVER_URI="druby://localhost:8787"

class TimeServer

  def get_current_time
    return Time.now
  end

end

# サーバ側でリクエストを受け付けるオブジェクト
FRONT_OBJECT=TimeServer.new

# サーバを起動する
DRb.start_service(SERVER_URI, FRONT_OBJECT, :safe_level => 1)
# DRb のスレッドが終了するのを待つ
DRb.thread.join

クライアント側コード

require 'drb/drb'

# 接続先の URI
SERVER_URI="druby://localhost:8787"

# DRbサーバを起動する
# この例には必要ないが、front オブジェクト以外の
# リモートオブジェクトのメソッドを呼び出す時には必要
DRb.start_service
# リモートオブジェクトの取得
timeserver = DRbObject.new_with_uri(SERVER_URI)
# リモートメソッドの呼び出し
puts timeserver.get_current_time

クラス

DRb::DRbIdConv

オブジェクトと識別子を相互に変換するクラスです。

DRb::DRbObject

リモートの dRuby オブジェクトを表すオブジェクトです。

DRb::DRbServer

dRuby サーバクラス。

DRb::DRbUnknown

リモートプロセスからマーシャリングされて送られてきたオブジェクトで、そのクラスがローカルプロセス内では不明であるようなものを表すクラス。

DRbIdConv

Alias of DRb::DRbIdConv

DRbObject

Alias of DRb::DRbObject

モジュール

DRb

drb ライブラリの名前空間となるモジュール。

DRb::DRbProtocol

drb で使われる通信プロトコルを取り扱うモジュールです。

DRb::DRbUndumped

このモジュールをインクルードしたクラスのインスタンスはネットワーク越しに参照渡しで渡されるようになります。値渡し出来ないオブジェクトを drb と一緒に使う時に有用です。

DRbUndumped

Alias of DRb::DRbUndumped

例外クラス

DRb::DRbError

drb ライブラリ固有の例外を表すクラス

  DRb::DRbBadScheme

プロトコルクラスが受け取った URI の schema がそのクラスでサポートされていないことを、伝えるための例外。

  DRb::DRbBadURI

URI に含まれている schema をサポートしているプロトコルが見付からないことを意味する例外クラス。

  DRb::DRbConnError

通信エラーが発生したことを意味する例外クラス。

  DRb::DRbRemoteError

例外オブジェクトを wrap したクラス

  DRb::DRbServerNotFound

カレントサーバが見付からない場合に発生する例外のクラス

  DRb::DRbUnknownError

DRb::DRbUnknown をラップする例外クラスです。

サブライブラリ

drb/acl

drb で用いる ACL(Access Control List)を定義するライブラリ。

drb/extserv

DRb::ExtServ を定義しているライブラリ。

drb/extservm

DRb::ExtServManager を定義しているライブラリ。

drb/gw

drb 通信を中継するゲートウェイ(DRb::GW)と、中継に必要なオブジェクト識別子変換クラス(DRb::GWIdConv)、および DRb::DRbObject への拡張が含まれています。

drb/observer

DRb 用の修正をした Observable (DRb::DRbObservable) を定義するライブラリ。

drb/ssl

DRb のプロトコルとして SSL/TLS 上で通信する drbssl が使えるようになります。

drb/timeridconv

DRb::DRbIdConv の拡張 DRb::TimerIdConv を定義するライブラリ。 DRb::DRbIdConv の GC 問題をタイムアウトを定めることで部分的に解決します。

drb/unix

DRb のプロトコルとして UNIX ドメインソケット経由で通信する drbunix が使えるようになります。