並列分散ソフトウェア
電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.hlla.is.tsukuba.ac.jp/~yas/sie/pdsoft-2001/2002-01-10
あるいは、次のページから手繰っていくこともできます。
http://www.hlla.is.tsukuba.ac.jp/~yas/sie/
http://www.is.tsukuba.ac.jp/~yas/index-j.html
http://www.hlla.is.tsukuba.ac.jp/~yas/index-j.html
通信プリミティブの分類
- 同期か非同期か。
- アドレス指定。送り先の指定がプロセスかメール・ボックスか。
- 信頼性があるかないか。
- 結合が作られる/作られない
- 順序が保存される/されない
- バッファリングあり/なし
- 単方向/双方向
- 受け手が1つ/複数(マルチキャスト)
クライアント・サーバ型の通信。
- 3つの基本命令
- get_request()
- send_reply()
- do_operation()
- クライアント・サーバ型の通信、RPCの障害への対応
- セマンティクスとトレードオフ
- idempotent冪等な操作
- 無状態サーバ
グループ通信(マルチキャスト)の実現
- 動的なグループ生成、メンバの追加への対応
- アトミックをどこまでやるかトレードオフ
- アドレス指定
資料:
A.S.タネンバウム著、水野忠則、鈴木健二、西宮洋太郎、佐藤文明訳、分
散オペレーティングシステム、プレンティスホール (1996)
第2章 分散システムにおける通信
2つの重要なパタン
- クライアント・サーバ
- グループ通信(マルチキャスト)
プロセス間通信の構造化。send, receive は、goto 相当。
プログラム中のデータ項目とネットワーク上を流れるメッセージに対応づける。
- marshaling
- メモリ中からデータ項目を集めて、ネットワークでメッセージとして
転送するのに適した形式にまとめる。
- unmarshaling
- 逆。
英語の綴りは、l が1つのものと2つのものがある。教科書によって違う。
◆XDR
SunRPC で使われているデータ形式。バイナリ文化。
rpcgen というスタブ・コンパイラがある。
marshaling 部分の自動生成。
SunRPC を使わなくて、XDR だけを使う方法もある。
- xdrmem_create(XDR *, const caddr_t, const uint_t, const enum xdr_op)
- メモリの指定されたの番地に保存/回復/メモリの解放。
- void xdrstdio_create(XDR *, FILE *, const enum xdr_op)
- FILE * を通じて、構造体の読み書き。
xdr_int.c、
Sun RPC examples
◆sprintf()/sscanf()
文字列に直して送る方法もある。文字列文化。インターネットのアプリケーショ
ンでよく使われる。
思ったほど遅くはない。
通信の基本命令
- 同期か非同期か
- アドレス指定。送り先の指定がプロセスかメール・ボックスか
- 信頼性があるかないか
- バッファリングあり/なし
- 受け手が1つ/複数
- 結合が作られる/作られない
- 単方向/双方向
- 順序が保存される/されない
- 同期型(synchronous)(ブロッキング型(blocking))
- 非同期型(asynchronous)(非ブロッキング型(nonblocking))
図
send,receive それぞれ2種類ある。
- 同期send
- 非同期send
- 同期receive
- 非同期receive。バッファの位置だけ先にわかる。完了は、wait() 命令、ポーリング、条件receive、select()、時間切れ。
非同期の方が、並列性が高い。しかし、、、
- 転送完了までメッセージ・バッファを書き換えられない
- 送信側は、転送が終了したかわからない
1. は、バッファリングで解決可能。しかし、無駄なコピー、フロー制御の問
題がある。
2. は、転送完了割り込みで解決可能。プログラミングが難しい。
割り込みよりは、マルチスレッドがよい。
プログラミングの選択
- 同期送信プリミティブ(CPUが遊ぶ)
- バッファリング付きの非同期通信プリミティブ(コピーのオーバヘッド)
- 割り込みと非同期通信プリミティブ(プログラミングが難しい)
時間切れ(timeout)。同期で使われる。
コピーするかしないか。
同期、非同期とは直行しているとも言えるが、普通は同期の場合にはバッファ
リングを省略してコピーを減らす。
メールボックスには、しばしば有限のバッファがもうけられる。
バッファがいっぱいだった時にどうするか。
いっぱいの時にだけ送信側をブロックさせる、という方法でいいのか。
- 直接。プロセスを指定する。
- 間接。メール・ボックス。複数のプロセスによって共有されることもされない
こともある。
直接アドレス指定では、receiveする前にsendされると、どのプロセスにメッ
セージを送っていいのかわからない。
解決
- 待たせる、タイムアウト
- メールボックス(mailbox)。受信の宛先だけを通信システムに事前に登録。
- (送らせない)
分散システムでは、メッセージは、失われることがある。
- send() は、何も保証しない。
- システムで ack を出す。
- 上のレベルでやる(client-server, RPC)。
IPデータグラム(datagram)転送サービス
- 信頼性がない
- 単方向
- データの送り手と受けての間に結合(通信路)が形成されない
- 送出したデータの順番が途中で変ることや送出したデータが失われるこ
とがある。その場合、システムは何もしない。
- アドレス指定は、IPアドレス。IPv4 で 32ビット。IPv6 で 128ビット。
ストリーム転送サービス
- 信頼性のある(reliable)
- 双方向
- 2つのプロセス間に結合(connection,通信路)が形成される
- 複数回に分けて送り出したデータでも順番が入れ替わらない
- データの区切りは保存されない
- アドレス指定は、結合で指定。結合は、次の4つで区別される。
- 送り手のIPアドレス
- 送り手のポート番号
- 受け手のIPアドレス
- 受け手のポート番号
データの区切りが保存されると、sequenced packet と呼ばれる。
IP層は、転送サービスとして信頼性のないデータグラムを提供する。TCP
層の仕事は、それを使って、双方向のストリーム転送サービス提供することで
ある。そのために、「再転送付き肯定確認応答(positive acknowledgement
with retransmission)」という、一般的によく用いられている技術が使われ
ている。この技術では、データの受け手は、データを受け取る度に、送り手に
確認応答(acknowledgement, しばしば ack と省略される)を返す。データの
送り手は、確認応答を受け付けると、次のデータを送る。ある時間がたっても
確認応答が来なかった場合、データの送り手は、再転送(retransmit)する。
ストリームを実現する技術として、TCPは、スライディング・ウィンドウ
(sliding window)と呼ばれる技術を用いている。この技術では、ウィンドウと
呼ばれる範囲を設定して、確認応答が来る前に、次々とウィンドウ内のパケッ
トを送出す。確認応答を受け取ると、ウィンドウを「スライド」させ、次のパ
ケットを送り出す。
フロー制御
受け手のバッファ(メモリ)は、有限である。送り手は、受け手消費する速度
に合わせてパケットを送出さなければならない。このような制御をフロー制御
という。TCPでは、スライディング・ウィンドウを用いてフロー制御を行って
いる。
手続き呼出しの形に見えたら RPC (Remote Procedure Call)。
通信を構造化。send()/receive() を直接使うのは、goto (jump) でプログラ
ムを書くようなもの。call/if/while で書きたい。
プロセスを2種類に分類する。通信は、次のパタンを繰り返す。
- クライアント
- 先にメッセージ(要求)を送る、後でメッセージ(応答)を受け取る
- サーバ
- 先にメッセージ(要求)を受け取る、後でメッセージ(応答)を返す
図? 通信のパタンからみたクライアントとサーバの定義
- get_request(port_t serviceport,message_t request/*in*/): サーバ・プロセスにより使われる。クライアント・プロ
セスから送られてくる要求メッセージを待つ。
- send_reply(port_t client,message_t reply): サーバ・プロセスにより使われる。クライアント・プロ
セスに対して応答メッセージを送る。
- do_operation(port_t server,message_t request/*out*/, message_t reply/*in*/): クライアント・プロセスにより使われる。サーバへ要
求を送り、サーバからの応答が返ってくるまで待つ。
サーバは、普通、get_request() で、クライアントから何か要求メッセージが
届くのを待っている。
クライアントが何かサーバにして欲しい時には、do_operation() で、サーバ
に要求メッセージを送る。そして、サーバからの応答メッセージを待つ。
サーバは、要求メッセージを受けとると、何か仕事をして、send_reply() で、
クライアントに応答メッセージを返す。そして、再び次の要求メッセージ
を待つ。
1つのサーバに複数のクライアントがアクセスすることがある。1つのクライ
アントも、複数のサーバに同時にアクセスすることもできる。
図? クライアント・サーバ・モデルに基づく通信で使う3つの命令
例1:7種類のメッセージを使う方法
- REQ
- REP
- ACK
- AYA (Are You Alive) -- 忙しいのか死んでいるか
- IAA (I Am Alive)
- TA (Try Again) -- receive() が呼び出されていない
- AU (Address Unknown)
図
例2:3種類(回数)
- Request
- Request-Reply
- Request-Reply-Acknowledge
RPC (Remote Procedure Call)
(
遠隔手続き呼び出し
)
は、分散システムを構築する時に広く使われている「プロセス間通信」の方法。
NFS (Network File System) を始めとする分散ファイル・システムの構築や、
や
NIS (Network Information Service) (パスワード・ファイルなどの共有)
で使われている。
(<−>文化的には、TCP/IP上のテキストベースのプロトコルとは対照。)
◆RPCの特徴
TCP/IP で提供されているストリームや UDP/IP で提供されているデー
タグラムと比較して、RPC には次のような特徴がある。
- プロセス間通信におけるクライアント・サーバ・モデルに基づいている。
(TCP/IPやUDP/IPでも上位プロトコルではクライアント・サーバ・モデルを使っ
ているのがほとんど。)
- 普通の手続き呼出し(C言語では関数呼出し)と似た方法で通信を行うこ
とができる。
- 結合(connection)が作られない。(UDP/IP のデータグラムと同じ。)
- 同期式の通信を提供する。
- 双方向の通信プリミティブである。(TCP/IPと同じ。UDP/IPでも双方向が普通。)
RPCで「遠隔(remote)」というのは、もともとはネットワークに接続された別
のコンピュータという意味であったが、最近では、同じコンピュータの内部で
もRPCが使われる。「遠隔(remote)」とは、「別のコンピュータ」という意味
ではなく、「別のアドレス空間」という意味もある。
RPCでは、別のアドレス空間の間でデータがやり取りされるので、基本的に
「ポインタ」を受け渡しすることはできない。しかし、SunRPC では、ポイン
タの先を再帰的に「コピー」する機能がある。
◆RPCを実現する基本命令
下位層では、上であげた3つの基本命令が使われている。
このRPCの3つの命令は、システムコール、または、ライブラリで実現される。
SunRPCには、get_request() に相当する命令が定義されていない。
◆スタブとスタブ生成器
RPCでプログラムを作成するときには、3つの基本命令を利用することは、ほ
とんどない。
スタブ生成器(stub generator)
を使えば、インタフェースの定義から3つの基本命令を呼び出すようなプログ
ラムが自動生成される(lex、yacc )。
スタブ(stub)
は、プロセス間通信を普通の手続き呼出しと全く同じ形式で行なうことができ
るようにするためのプログラム。
もともとは木の切株の意味。
スタブの分類
- クライアント側スタブ
- 手続き呼出しの形で呼び出される。do_operation() 命令を実行する。
- サーバ側スタブ
- 無限ループを持つプログラム。 get_request() でクライアントからのメッ
セージを受け取り、対応する手続きを呼び出し、結果をsend_reply() により
返す。
スタブでは、パラメタ(引数と結果)の
整列化(marshalling)
(
パック
)
と
非整列化(unmarshalling)
(
アンパック
)
も行なわれる。SunRPC では、
XDR (eXternal Data Representation)
と呼ばれている方法を使っている。
クライアントとサーバを結び付ける。
RPC では、動的(dynamic)になる。
ローカルの手続き呼出しでは、リンク時に固定される。
クライアントとサーバは1対1ではない。
- 1つのサーバは、複数のクライアントにサービスを提供するのが普通である。
- 1つのクライアントは、利用可能な複数のサーバの中から
選択して利用することが多い(同時に複数のサーバを使うことは少ない)。
binding のための命令
- 登録、export (サーバ側)
- 削除 (サーバ側)
- 検索 (クライアント側)
(RPCを実現する上での問題)
- サーバが応答しなかったらどうするか
- 重複する要求の処理
- 応答が失われた時
- メッセージの削減。1つの要求・応答メッセージを複数のデータグラムで運ぶ
- クライアントがサーバを見つけられない
- 要求メッセージが紛失
- 応答メッセージが紛失
- 要求受信後、サーバがクラッシュ
- 要求送信後、クライアントがクラッシュ
-
◆クライアントがサーバを見つけられない
◆要求メッセージが紛失
時間切れ再要求。簡単。
◆応答メッセージが紛失
難しい。単純な時間切れだとまずい。
例: 銀行預金転送。
対策:
- 操作を idempotent にする。
- クライアントから最後のメッセージ番号を保持して、再要求を拒否する。
- 再要求を示すフラグを付ける。
◆要求受信後、サーバがクラッシュ
番号では対応できない。要求実行前と実行後を区別できない。
図。
RPCのセマンティクス
- exactly once semantics。実現不可能。
- at least once semantis。応答するまで要求し続ける。
- at most once semantics。失敗したらあきらめる。
- なにもしない。
集中だと、クライアントもサーバもいっしょに死ぬので、問題はない。
孤児問題(orphan problem)。
親(クライアント)がいない計算を孤児という。
対応方法
- 根絶(extermination)。
- RPC 前にログに書く。クラッシュしたらログを見て根絶する。重たい。
孫の孤児(grandorphan)問題がある。
- 再生(reincarnation)
- リブートすると、タイムスタンプをサーバに投げる。サーバは、
それより古いメッセージを消去する。
- 穏和な再生(gentle reincarnation)
- タイムスタンプを受信すると、親を探し、見つからない時だけ消去する。
- 期限切れ(expiration)
- RPC に標準時間Tを与え、その時間内に終了しないものを消去する。
それ以上かかる時には、明示的に要求する。クラッシュ後、サーバがTだけ待てば
孤児は消える。
孤児が、ロックを持っていたら、孤児を消しただけでは話を終わらない。
冪等(idempotent)な操作とは、
その操作を何回繰り返しても、1回だけ実行した時と同じ結果になるもの。
例:
- 足し算。関数でもある(値の書換えがない、引数だけで結果が決まる)。
- 位置を指定したファイルの読み込み(pread())
- 位置を指定したファイルの書き込み(pwrite())
idempotentではない操作
- 変数を1つ増やす
- 位置を指定しないファイルの読み込み(Unix stream風read())
- 位置を指定しないファイルの書き込み(Unix stream風write())
無状態サーバ(stateless server)
とは、サーバ内部に状態を保持しないようなサーバ。
状態の例
- Unix のカーネル内部で持っているファイルを読み書きする位置(シー
ク・ポインタ)
RPCで冪等な操作や無状態サーバを実現すると、クラッシュに強いシステムを
作れる。クライアントは、サーバから応答がない場合、何度要求を再送信して
もよい。
例:NFS Version 2
サーバは、ファイルに対する書き込み要求を受け付けると、ディスクへ
の書き込みを完了してから応答を返す。
応答が返ってきた要求は、
ディスクへの書き込みが完了したことが保証されている。
この段階でサーバがクラッシュしたとしても、なにも失われない。
しかし、、、重たい。NFS Version 3 では、状態付きのサーバになった。
表? NFSで使われているRPCの手続き
--------------------------------------------------------------------------------
手続き名 意味 関連するコマンド、 システムコール
--------------------------------------------------------------------------------
null() 何もしない rpcinfo -u hostname nfs
コマンド
getattr() 属性の読み出し ls -l
コマンド, stat
システムコール , open
システムコール
setattr() 属性の設定 chmod
, chown
コマンド
lookup() ファイルの検索 open
システムコール
readlink() シンボリックリンクの読み出し
ls -l
コマンド, readlink
システムコール
read() ファイルの読み出し read
システムコール
write() ファイルの書き込み write
システムコール
create() ファイルの作成 creat
システムコール, open
システムコール
remove() ハードリンクの削除 rm
コマンド, unlink
システムコール
rename() ファイル名前の変更 mv
コマンド, rename
システムコール
link() ハードリンクの作成 ln
コマンド, link
システムコール
symlink() シンボリックリンクの作成
ln -s
コマンド, symlink
システムコール
mkdir() ディレクトリの作成 mkdir
コマンド
rmdir() ディレクトリの削除 rmdir
コマンド
readdir() ディレクトリの読み出し ls
コマンド
statfs() ファイルシステムの利用状況
df
コマンド, statfs
システムコール
commit()* ディスクへの書き込み fsync
システムコール
access()* アクセス権のチェック access
システムコール
--------------------------------------------------------------------------------
は、NFS Version 3 の新しい手続き。
RPC のようにコネクションが作られない
通信サービスを使う時に
冪等や無状態といった性質を実現する時に必要になる技術。
例:NFSでのディレクトリの読み込み手続き nfsproc_readdir() で、1回の
RPC で全部のデータを返せないことが起きる。
ディレクトリのどの位置まで読み込んだかを
示す中間状態を
クッキー(cookie)
という形でクライアントに返す。
クライアントは、次の RPC の呼び出しで、
前回受けとった応答の中のクッキーを、サーバへの要求に含めて送す。
/usr/include/rpcsvc/nfs_prot.x:
const NFS_COOKIESIZE = 4;
typedef opaque nfscookie[NFS_COOKIESIZE];
/*
* Arguments to readdir
*/
struct readdirargs {
nfs_fh dir; /* directory handle */
nfscookie cookie;
unsigned count; /* number of directory bytes to read */
};
struct entry {
unsigned fileid;
filename name;
nfscookie cookie;
entry *nextentry;
};
struct dirlist {
entry *entries;
bool eof;
};
union readdirres switch (nfsstat status) {
case NFS_OK:
dirlist reply;
default:
void;
};
nfsproc_readdir() で、1回目と2回目の RPC の間にディレクトリの内容が
更新された場合、どのような結果になるのか不明。
HTTP では、
TCP/IP というコネクションが作られる通信サービスが使われいるが、
1ページ1ページを転送する度にコネクションを切っているので、
複数ページ
のアクセスの時にはコネクションが作られない通信サービスを使っているのと
論理的に同じ。
HTTP でも、クライアントの状態をサーバ側で保存するためにクッキーが使わ
れることがある。
問題点
- プライバシの侵害。サーバ側にページを見
た個人を識別する情報が残る。
ダイアルアップでIPアドレスが変わってしまっても追跡可能。
- クライアント側でクッキーを保存するためのファイルがふくれる。
- メッセージ数の削減。まとめて ack。
- コピーの削減。scatter-gather。
- タイムアウト処理
RPC向きのものと向いていないもの。
通信の分類
- one-to-many, multicast
- one-to-one, point-to-point, unicast
放送は、特定の(物理的な)ネットワークに属するプロセス「全部」に送る。
何に使えるか
- いろいろな分散アルゴリズムでよく使われる、論理クロックの同期と同様に
グループ通信で何が難しいか
- グループが動的
- 使えるハードウェア。
下のネットワークで放送やマルチキャストがサポートされているか。
なければ、unicast で実現される。
- バッファリング。再転送のためのコピーをいつまで持つか。
- atomicuty。all or nothing。望ましいが、難しい。
- クローズ/オープン。グループ外から送れるか。
- 同等/階層(コーディネータ付き)
並列処理では、クローズが多い。
IP MBone のように、オープンでないとどうしようもないものもある。
対等だと、クラッシュに強い(single point of failure がない)が、何をす
るにもすぐ投票が必要になる。
グループサーバを持つか持たないか。
難しいのは、メンバのプロセスがクラッシュした時。
何も言わずにグループから抜ける。
- プロセスの名前付けと同じように、1つのアドレスで指定する(直接、間接)
- 個々のアドレスのリストを使う。メンバの管理を呼出し側でやる。
- 述語アドレス指定。全部に送られるが、メッセージに含まれている述語が真の時だけ受け取られる。
one-to-oneの通信と同じにしたい。しかし、
- RPC の意味。SunRPC の放送型RPC。
- atomicity
- メッセージの順番
障害がなければ、簡単。
- 送信プロセスが、下位層の放送機能などを使って
グループ内のプロセスに
メッセージを送る。(メッセージは落ちるかもしれない。)
タイマを設定し、必要に応じて再転送する。
- 各プロセスは、メッセージを受け取ると、始めて受け取ったものならば、
グループの他のプロセスに送る。タイマを設定し、必要に応じて再転送する。
一度受け取ったものなら、なにもしない。
one-to-one でも問題があるのに、group 通信だとさらに複雑。
total ordering は、グループ通信では実現が難しすぎる。弱いものが実現さ
れる。
プロセスが複数のグループに属していると、1つのメッセージについての順序
だけ考えていてはすまなくなる。
数が増えた時に動くか。
ネットワークのダウンに対応するには、ネットワークを冗長に
しないといけない。冗長性があると、メッセージの重複を
うまく扱う必要がでてくる。
下手をすると、メッセージが増幅しながいつまでもぐるぐる回る。
分散アプリケーションのためのツールキット。
コーネル大学。
- 同期システム(synchronous system)
-
イベント(マルチキャスト)の順序が厳密に逐次的に発生する。オーバーラップしない。
イベント(マルチキャストを含む)は、完了までの時間は、0。
実現不可能。
- 緩やかな同期システム(loosly synchronous system)
- イベントは有限。
- 仮想的な同期システム(virtually synchronous system)
- 因果関係が成り立つようにがんばる。(並行なものは、手抜き。)
- ABCAST
- 緩やかな同期
- CBCAST
- 仮想的な同期
- GBCAST
- 仮想的な同期(グループのメンバシップ用)
最初の実現:2相コミットによる ABCAST 。重すぎる。
- 送信者は、タイムスタンプを含むメッセージを全てのメンバに送る。
- 各メンバは、送信、または、受信したメッセージで最大のものを最初の送信者に送る。
- 送信者は、全ての返事を受け取ると、最大のものを選び、メンバにコミット・メッセージを送る。コミット・メッセージは、タイムスタンプの順に届けられる。
CBCASTの実現
メンバの数:n
各プロセスは、グループごとに、長さnのベクトルVを持つ。
i番目の要素は、プロセスiから正しい順序で受信したメッセージの最後の番号。
0に初期化される。
- プロセスは、送信すべきメッセージがあると、
ベクトルの自分のスロットを増加させ、メッセージの一部として送信する。
- メッセージのベクトルをV、メモリ中のベクトルをLとする。
メッセージがjから送られてきたものとすると、次の条件の時に受け取る。
そうでないものは、この条件が満たされるまでバッファリングされる。
マルチキャストの実装。
- atomic ではない。
- 因果律も満たさない。
- 非常に高いスケーラビリティを持つ。
- 冗長性が実現できる。
↑[もどる]
←[12月20日]
・[1月10日]
→[12月13日]
Last updated: 2002/01/09 23:43:45
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>