Jiniと分散型プログラミング言語

 並行分散ソフトウェア/並列分散ソフトウェア

                                       電子・情報工学系
                                       新城 靖
                                       <yas@is.tsukuba.ac.jp>

このページは、次の URL にあります。
http://www.cs.tsukuba.ac.jp/~yas/sie/pdsoft-2005/2006-02-17
あるいは、次のページから手繰っていくこともできます。
http://www.cs.tsukuba.ac.jp/~yas/sie/
http://www.cs.tsukuba.ac.jp/~yas/

■今日の重要な話

参考文献

Marko Boger: Java in Distributed Systems: Concurrency, Distribution and Persistence, John Wiley & Sons, 2001. ISBN: 0471498386

http://www.dpunkt.de/buch/3-932588-32-0.html (ドイツ語) jivs code

■Jini

Jini (ジニー)は、Java を中核にした、情報家電製品を相互接続するための通 信技術。

1999年に、サン・マイクロシステムズ社のビル・ジョイらによって開発され発 表された。

Jini の目標は、ネットワークで Plug & Play を実現すること。 機器をネットワークに接続しただけで、特別な設定 をしなくてもすぐに利用可能になること。

目標

サービスには、ハード的なもの(プリンタ、ディジタルカメラ、CD Player) の他に、ソフト的なもの(スペルチェック、翻訳、アドレス帳)がふくまれる。

JavaSpaces は、内部的に Jini のルックアップ・サービスの実現で使われて いる。JavaSpaces も、Jini でアクセス可能なサービスの1つと考えることも できる。

◆UPnP (Universal Plugand Play)

Microsoft の、Jini に対抗した技術。

◆ルックアップ・サービス

Jini中心的な技術が、ルックアップ・サービス。

サービスの登録と検索

ルックアップ・サービス自身も、最初から知られている必要はない。 ネットワーク上で自動的に探される。 Discovery と Join。

◆リース

サービスは、永続的に登録されるではなくて、 特定の時間だけ利用可能になる。

Java のオブジェクトが Lease。

リース期間は、延長することができる。 延長されなかった lease は、ルックアップ・サービスから削除される。 登録されているサービスを明示的に削除する仕組みは、存在しない。

サービスが削除された時には、分散型イベント配送サービスにより関係してい る所に知らされる。

トランザクションのインタフェースは定められているが、具体的な実現は各サー ビスにまかされている。

◆Jiniを使うのに必要とされているもの

IPアドレスの割り当ては、Jiniの一部ではない。

◆サービス

サービスは、Java のオブジェクトで実現される。

サービスの提供者とサービスの利用者の間は、最終的にはに RMI で接続される。

ServiceIDLister インタフェースを implements する。

package com.sun.jini.lookup;
public interface ServiceIDListener extends java.util.EventListener {
    void serviceIDNotify(net.jini.core.lookup.ServiceID serviceID);
}
ルックアップ・サービスからコールバックされる。

◆Discovery と Join

各ネットワークには、ルックアップ・サーバを置く。

Discovery
Jini を使うには、まず、ルックアップ・サーバを探す。
Join
サービスの提供者が、インタフェースと属性をルックアップ・サーバに 登録する。

Discovery の実現方法

ルックアップ・サーバは、起動時、再起動時、224.0.1.84:4160 にMulticast Announcement Protocol で、利用可能性を広告する。

サービスの提供者がネットワーク上のルックアップサービスをマルチキャストで探す。

図1 マルチキャストによる Discovery

サービスの提供者がルックアップサービスにサービスオブジェクトを登録する。

図2 Join

RemoteBall.java Ball.java

◆サービスのグループ

サービスは、1つ以上のグループに属する。

グループは、名前(文字列)で区別される。

名前としては、DNS 風の表記のものが推奨されている。

◆JoinManager(サーバ側)

Discovery と Join は、規格上は、ネットワーク・プロトコルになっている。

Jini パッケージは、JoinManager という参照クラスを含む。

    public JoinManager(Object obj,  Entry[] attrSets,
                       ServiceIDListener callback,
                       LeaseRenewalManager leaseMgr)
        throws IOException
    public JoinManager(Object obj, Entry[] attrSets, String[] groups,
                       LookupLocator[] locators,
                       ServiceIDListener callback,
                       LeaseRenewalManager leaseMgr )
        throws IOException

BallStarter.java

◆Lookup(クライアント側)

クライアントは、サービスを探す。

サービスの利用者がルックアップサービスに対してサービスオブジェクトを検索する。

図3 Lookup

サービスは、次の3つで区別される。 サービスを検索する時に ServiceTemplate のオブジェクトを作成する。 JavaSpaces のように、null を指定すれば、ワイルドカードを意味する。
    public ServiceTemplate(ServiceID serviceID,
                           Class[] serviceTypes,
                           Entry[] attrSetTemplates)
サービス(オブジェクト)の探し方
  1. LookupLocator により、マルチキャスト、または、 ユニキャストで ルックアップ・サービスを探す。
  2. ルックアップ・サービスのプロキシ ServiceRegistrar を作る。
  3. テンプレートを作り、ServiceRegistrar に渡す。
サービスを見つける過程で、サービス(オブジェクト)のRMI のスタブ(クライ アント側スタブ)が転送される。

◆サービスの利用

最終的にクライアントは、サービス・プロバイダを RMI で呼び出す。

Bat.java

サービスの利用者がサービスオブジェクトを通じてサーバを利用する。

図4 Invoke

◆Leasing

信頼性が低いネットワークと、どう戦う方法の1つ。

lease には、期限がある。

期限の長さは、交渉可能。 期限が短い(1分以下、数秒)というのは、あまり想定されていない。

リースの利点

Jini のサービスを提供しているオブジェクトは、Lease インタフェースを実 装している。

public interface Lease {
    long FOREVER = Long.MAX_VALUE;
...
    long getExpiration();
    void renew(long duration)
        throws LeaseDeniedException, UnknownLeaseException, RemoteException;
    void cancel() throws UnknownLeaseException, RemoteException;
...
}
getExpiration() で、リースの残り時間がわかる。ミリ秒単位。

renew() で延長する。 延長できない時には、LeaseDeniedException が返される。

もう使わなくなった時には、cancel() できる。 期限切れと同じことになる。

リースの管理には、LeaseRenewalManager を使う。

◆セキュリティ

本当に、アクセス制御はなくてもいいのか。

■分散型プログラミング言語

プログラミング言語は、ネットワークの存在や通信をさまざまな度合いで隠し ている。

問題:

「socket があれば、分散型プログラミング言語」とは、定義したくない。

◆分散型OSとネットワークOS

ネットワーク・オペレーティング・システム

ネットワークの機能はある。

利用者は、常にどの計算機を使っているのかを意識する必要がある。

コマンド

システムコール

分散型オペレーティング・システム

利用者は、仮想的な1台の計算機を使っているように感じ、計算機と計算機の 境界線が見えなくなる。分散透明性(network transparency)が実現されてい る。

目標

現在の技術

注意: 負荷分散の分散(load sharing/balancing)とこの講義のタイトルの分散 (distributed)は意味が違う。

◆Emerald

初期(1980年代)の分散型言語。オブジェクト指向。

一般的な特徴

Emerald の目標。

分散透明性と移動は、矛盾している。

◆Emeraldの参照

Emerald では、オブジェクトのアクセスは、参照(reference)を通じて行われ る。参照は、ローカルもリモートも区別がない。 (分散透明性が実現されている)。

メソッド呼出しの引数も参照で渡される。オブジェクトの場所が違うと、重た い。コピーの方が速い。

◆Emeraldのオブジェクト・マイグレーション

Emerald には効率を挙げるために、オブジェクトを移動(migrate)させる機能 がある。
move X to Y
オブジェクト X を、オブジェクト Y のあるホストに移動。ヒント (システムは実際には移動させないこともある)。
fix X at Y
オブジェクト X を、オブジェクト Y のあるホストに移動して、 さらに動かないように固定する。
unfix X
オブジェクト X を、再び移動可能にする。
refix X at Z
fix されているオブジェクト X を、オブジェクト Z のあるホストに移 動して、さらに動かないように固定する。全体が atomic に行われる。

Call by reference が重たい。

call by move
引数をオブジェクトの方に移動させる。
call by visit
メソッドがリターンすると、オブジェクトも戻ってくる。
call by move return
結果のオブジェクトも戻ってくる。
移動の粒度が重要。オブジェクトのグループ化。 attached キーワードがついていると、いっしょに移動する。

◆ローカルとリモートの統合

A note on Distributed Computing [Waldo 1994]

この方法論にそって開発されたプログラミング言語もあるが、 そのような言語のアプリケーションの範囲は狭い。

◆ローカルのプログラミングと分散のプログラミングの違い

歴史 単に繋ぐだけでは、分散の難しい問題は、解決されない。

◆分散の難しい問題

例:

◆RMI付Javaは、分散型プログラミング言語か

◆分散型プログラミング言語の要件

  1. 位置と型の直行。
  2. 遠隔オブジェクト生成
  3. ローカルとリモートを区別したい時には区別できる
  4. ローカルとリモートを区別したくない時には区別しないでよい
  5. Garbage colection
  6. オブジェクト・マイグレーション
  7. グループ化
  8. 同期呼出しと非同期呼出しの両方の支援
  9. 分散でも、並行性を言語で支援したい

分散の難しい問題は、まだ汎用的に解ける技術はない。 汎用性がないと、プログラミング言語には採り入れにくい。

◆分散型プログラミング言語で分散システムが作れるか

分散OS上で分散システムが走るか。

■Voyager

Glue の Graham Glass より作成されたJava 用の分散オブジェクト。(Voyager の方が古い。)

Proxy.of(obj) で、リモートリファレンスを生成する。 Mobility.of(obj)で、移動可能なオブジェクトを動的に生成する。

    IMobility mobileObj = Momility.of(obj);
    mobileObj.moveTo("url");
非同期メソッド呼出しがある。
    IA a1 = (IA) Factory.create("A","//sun:8000");
    a1.method(param1,param2);  // 同期 

    Result r1 = Future.invoke(object, "method", // 非同期
        new Object [] {param1,param2});
    if( result.isAvailable() )
    {
       int x = r1.readInt();
    }
メソッド名を文字列で渡す。結果として、Result 型を返す。isAvailable() メソッドで終了を待つ。readInt(), readByte(), readObject() で、int, byte, オブジェクトに戻す。

Voyager Space を使ってマルチキャストができる。

    ISubspace subspace = (ISubspace) Namespace.lookup("//sun:9000/Subspace");

    A a1 = new A();
    subspace.add(a1);

    a1.method1( param1, param2 );

    Object [] params = new Object [] { param1, param2 };
    Multicast.invoke(subspace,"method1",params,"A");

■Dejay

分散Javaの1つ。

◆Dejeyのオブジェクト・マイグレーション

    DjProcessor p1 = new DjProcessor("sun:8000");
    DjHello hello = new DjHello(p1);
    hello.moveTo("mac:9000");

◆DjProcessor

1つ目の仮想プロセッサは、暗黙的に作られる。 2つ目以降は、明示的に作る。
    DjProcessor p1 = new DjProcessor("hostname:port");
これにより、ホスト hostname 上の ポート番号 port で新たな 仮想プロセッサが作られる。 ホスト hostname では、事前に Voyager デーモンを走らせておく必要がある。

◆遠隔オブジェクト

class A (.dj) から、自動的に スタブ(プロキシ)となる class DjA が生成される。 コンストラクタの引数が1個多い。
    DjA a1 = new DjA( Aの引数・・・, DjProcessor );
これで、遠隔の仮想プロセッサでオブジェクトが生成され、 遠隔参照(remote reference)が返される。 通常の参照と同じになるように頑張っているが、 一部違う。

    DjA a2 ;
    a2 = ... ;
    ...
    if( a2 == a1 ) // 遠隔のオブジェクトではなくてローカルのスタブの比較
    {
       ...
    }
equals() メソッドは、遠隔でも働く。

ローカル・オブジェクトを引数にして、 リモート・オブジェクトを呼ぶと、自動的に遠隔にコピーが渡される。 (遠隔オブジェクトが作られて、遠隔参照が渡されるのではない。)

DjX 型のオブジェクトを 遠隔にリターンすることはできる。 DjX がみつからなければ、 Xのコピーが返される。

remote.getCopy() で、ローカルのコピーが得られる。

    DjA a1 = new DjA(p1);
    A a2 = a1.getCopy();
3つのメソッド呼出しのセマンティクスがある。
    DjA a1 = new DjA(p1);
    B b1 = a.method1( 10 );		 // 同期
    B b2 = a.method1( 10, Dejey.ASYNC ); // 非同期
    a.method1( 10, Dejay.ONEWAY );       // 一方向
非同期には、完了待ちの方法が2種類ある
    B b1 = a.method1( 10, Dejey.ASYNC );
    b1.method2(); // wait by nesessity

    B b2 = a.method1( 10, Dejey.ASYNC );
    if( b2.isAvailable() )
    {
        b2.method2();
    }
    else
    {
        // do something
        b2.waitForResult();
        b2.method2();
    }

◆Dejeyの名前サービス

オブジェクトに文字列の名前を付けて、遠隔からアクセスできるように公開す ることができる。

2レベルの名前。

    DjProcessor p1 = new DjProcessor("lin:8000");
    p1.registerByName("p1");
    DjA a1 = new DjA(p1);
    a1.registerByName("a1");
    DjProcessor p1 = Dejay.getProcessorByName("p1");
    DjA a1 = p1.getObjectByName("a1");

◆永続性

分散と永続は、かなり関係している。 Dejay では、仮想プロセッサ単位で永続にできる。 DjProcessor のコンストラクタで、文字列の名前と データベースの名前を取る。
    DjProcessor p1 = new DjProcessor("PersistProc","ProcesssorDB","lin:8000");
    DjA a1 = new DjA();
    if( p1.isPersistable ) {
       p1.persist();
       p1.flush();
    }
persist() を呼ぶと、データベースに保存される。 flush() を呼ぶと、メモリが GC で回収可能になる。

persist() でデータベースに保存されたオブジェクトも、 使われる自動的にデータベースから回復される。

仮想プロセッサ全体がデータベースに保存できる。 次のようにして回復できる。

    DjProcessor p1 = Dejay.getProcessorFromDB("PersistProc",
        "ProcesssorDB","lin:8000");

◆制限


↑[もどる] ←[2月10日] ・[2月17日] →[2月21日]
Last updated: 2006/02/20 19:50:56
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>