情報学類 分散システム 2008年12月09日
筑波大学システム情報工学研究科
コンピュータサイエンス専攻, 電子・情報工学系
新城 靖
<yas@is.tsukuba.ac.jp>
このページは、次の URL にあります。
http://www.coins.tsukuba.ac.jp/~yas/coins/dsys-2008/2008-12-09
あるいは、次のページから手繰っていくこともできます。
http://www.coins.tsukuba.ac.jp/~yas/
http://www.cs.tsukuba.ac.jp/~yas/
- ファイルやファイルに対するロックが使えるのは、集中システムだから。
分散システムでは、ファイルが使えないこと、ロックがうまく動作しないこと
がある。
- 1人で分散システムを使うこともある。
- 複数人で集中システムを使うこともある。
- プロセス間通信の分類
- marshaling (整列化)
- クライアント・サーバ・モデル(プロセス通信の構造化、よく使うパタン)
資料:
谷口 秀夫 (編),
谷口 秀夫, 佐藤一朗, 佐藤 文明, 柴田 義孝, 新城 靖, 横山 和俊 (著):
"情報処理学会編集 IT Text 分散処理", オーム社 (2005年9月).
ISBN: 4274201333.
第2章 基盤技術 (新城)
2つの重要なパタン
- クライアント・サーバ
- グループ通信(マルチキャスト)
プロセス間通信の構造化。send, receive は、goto 相当。
分散システム: 離れていても心は1つ
ネットワークで接続された複数のコンピュータ上で複数のプロセスを動作させ
る。プロセスは、全体として1つの仕事を成し遂げる。
ノード:プロセス、あるいは、コンピュータ
メッセージ:ノード間で交換されるデータ
分散システムでは、次のような集中システムでは普通に使える共有資源が使えない。
- メモリ
- ファイル
- 名前空間
- イベント
- セキュリティ、主体、認証
分散共有メモリ、分散ファイルシステムが使える場合は
使う方法も検討してもよい。
メッセージを送信したり受信したりするライブラリ関数やシステム・コールを
通信プリミティブという。
最終的には、ハードウェア。
分散プログラムを記述する時には通信プリミティブを呼び出した段階まで考え
ればよい。以後、プログラミング言語の実行時システムやOSが考える。
通信の基本命令
- send()
- メッセージを送信する
- receive()
- メッセージを受信する。
- 信頼性がある/ない
- (同期/非同期)
- (バッファリングあり/なし)
- 結合が作られる/作られない
- (順序が保存される/されない)
- アドレス指定。送り先の指定がプロセス/メール・ボックス
- 単方向/双方向
- マルチキャストあり/なし
- (帯域保証あり/なし、遅延保証あり/なし)
信頼性性があるかないか。専門用語では、程度問題(高い低い)ではなく、有
るか無いか。
信頼性がある通信プリミティブを利用した場合、あるプロセスが送信したメッ
セージは、途中で失われることはなく、有限時間以内に通信相手のプロセスに
送り届けられる。
分散システムでは、メッセージは、失われることがある。
- 伝送媒体に雑音がのってメッセージが壊れる。
- 混んでいるルータでメモリが足りなくなってメッセージが捨て
られる。
-
信頼性に対する態度
- 失われたメッセージを再送するなどして、送り届けるように努力する。
- send() は、何も保証しない。
- send() は、何も保証しない。上のレベルでやる(client-server, RPC)。
- 結合が必要な通信プリミティブ
- 実際に send や receive でメッセージを送受
信する前に結合を確立させる手順を踏む。電話。
- 結合が作られない通信プリミティブ
- 送りたいデータをすぐに send することができる。郵便。
図? 結合が作られる通信プリミティブと結合が作られない通信プリミティブ
接続を作る通信プリミティブでは、send(), receive() で送受信する前に接続
を確立する必要がある。通信の確立では、 電話と似ていて、発信側と着信側に
分かれる。
着信側
make_port(); // 受付端の登録。
accept(); // 実際の受付。connect() と対応。
receive();
send();
receive();
send();
close(); // 接続の切断。
発信側
connect(); // 接続要求。accept() と対応。
send();
receive();
send();
receive();
close(); // 接続の切断。
接続を用いる操作がない。send() と receive() が対応しているだけ。
プロセスA
receive();
send();
receive();
send();
プロセスB
send();
receive();
send();
receive();
- 直接。プロセスを指定する。
- 間接。メール・ボックス。複数のプロセスによって共有されることもされない
こともある。
ほとんどの通信プリミティブは、間接。
TCP/IP は、性質が違う2つのプロトコルから構成されている。
普通にアプリケーションが使うのは、上位の TCP。
IPデータグラム(datagram)転送サービス
- 信頼性がない
- 単方向
- データの送り手と受けての間に結合(通信路)が形成されない
- 送出したデータの順番が途中で変ることや送出したデータが失われるこ
とがある。その場合、システムは何もしない。
- アドレス指定は、IPアドレス。IPv4 で 32ビット。IPv6 で 128ビット。
ストリーム転送サービス
- 信頼性のある(reliable)
- 双方向
- 2つのプロセス間に結合(connection,通信路)が形成される
- 複数回に分けて送り出したデータでも順番が入れ替わらない
- データの区切りは保存されない
- アドレス指定は、結合で指定。結合は、次の4つで区別される。
- 送り手のIPアドレス
- 送り手のポート番号
- 受け手のIPアドレス
- 受け手のポート番号
データの区切りが保存されると、sequenced packet と呼ばれる。
IPと同じく、データグラム(datagram)転送サービス。
IPと違うのは、アドレス指定のみ。
- アドレス指定、IPアドレスとポート番号(16ビット)
分散システムを構築する時に、どの通信プリミティブを使うか
- TCP, UDP が要求に適合していれば、そのまま使う
- 要求になければ、TCP, または、UDP の上位層に独自のプロトコルを
構築する。
独自の例
- 順序付きパケット。
-
ストリームと似ているが、メッセージの区切りが保存される。
TCP で、メッセージ本体の前に、バイト数を送ることで実装できる。
- 信頼性のあるデータグラム
-
通常のデータグラムと似ているが、メッセージが紛失した時に再送する。
- TCP で、実装する。結合は、キャッシュとして使う。
- UDP で実装する。再送のためにメッセージをコピーする。
| TCP | IP | UDP | イーサネット | 電話 | 郵便 |
信頼性 | あり | なし | なし | なし | あり | なし |
アドレス指定 | 間接 | 間接 | 間接 | 間接 | 間接 | 直接 |
結合 | あり | なし | なし | なし | あり | なし |
方向 | 双方向 | 単方向 | 単方向 | 単方向 | 双方向 | 単方向 |
マルチキャスト | 不可 | 可能 | 可能 | 可能 | 可能 | 不可 |
* OS 内。
プログラム中のデータ項目とネットワーク上を流れるメッセージに対応づける。
- marshaling (整列化)
- メモリ中からデータ項目を集めて、ネットワークでメッセージとして
転送するのに適した形式にまとめる。
- unmarshaling (非整列化)
- 逆。
英語の綴りは、l が1つのものと2つのもの(イギリス綴り)がある。教科書によって違う。
図? marshalingとunmarshaling
4個の要素からなる構造体を整列化して送信している。
- 整数
- 文字列
- ビットマップデータ(可変長)のバイト数
- ビットマップデータ(可変長)の本体
整列化する基本的な方法
- 構造体や配列の要素を先頭から順にバッファに追加する。
- 可変長のデータの場合、まず、要素数を追加し、それに続いて本体を追加する。
ネットワークからデータを受け取ると、先頭から解釈して元のデータを再現す
る。
ネットワーク上を流れている時には、整列化された
データの先頭にはネットワークのヘッダが付加されている。
分散プログラムでは、メッセージを送信するプロセスと受信するプロセスが異
なる CPU で実行されることがある。整数をmarshalingする時には、次のような
点を考慮する必要がある。
- ワード(基本的な整数データ)が 8bit/16bit/32bit/64bit と違うことがある。
C 言語の int 型のビット数が違う。
- 1バイトのビット数は、現在は、8ビットのものが主流。
(1バイトが9ビットのものもあった。)
- メモリには、バイト単位で番地が付けられているものが主流。
(ビット単位、ワード単位で番地を付ける方法も考えられる。)
- バイト・オーダが違うことがある。
整数を送るだけでも、バイトオーダに気をつける必要がある。
C言語で扱える整数
- 1 バイト(char)
- 2バイト(short)
- 4バイト(long)
(現在のコンピュータのほとんどは、バイト単位でアドレスを付けているので、
1バイトの整数については、バイトオーダの問題はない。)
2バイト、または、4バイトの整数をメモリに保存する方法
: メモリの下位番地に上位バイトを置くか下位バイトを置くか
- リトルエンディアン
- 下位番地に下位バイトを置く。x86 (Intel Pentium/Core, AMD Athlon/Phenom)。
- ビッグエンディアン。
- 下位番地に上位バイトを置く。PowerPC, SPARC, m68k
PowerPC は、両方切り替え可能だが、ビッグエンディアンで使うことが多い。
図? バイト・オーダー
- リトルエンディアンがよい
- 32ビットの整数のうち、下位 8 ビットや 16 ビットだけが必要な場合、番地の計算をし直す必要がない。
- 多倍長の整数を足し算したい場合は、下位からアクセスする
- ビッグエンディアンがよい
- 送信側、または、受信側で相手に合わせて変換する。バイトオーダが同
じ場合は何もしない。
- 標準的なバイトオーダ(ネットワーク・バイト・オーダ) を定める。送
信側では、ネットワークにデータを流す時には、常に自分自身のバイト・オー
ダ(ホスト・バイト・オーダ)をネットワーク・バイト・オーダに変換する。
受信側では、ネットワーク・バイト・オーダから自分のホスト・バイト・オー
ダに変換する。
現在、ネットワーク・バイト・オーダとしては、ビッグエンディアンが広く
使われている。
- TCP/IP の IP アドレスやポート番号
- XDR
名前 | 方向 | ビット数 |
uint32_t htonl(uint32_t hostlong) | ホストからネットワークへ変換 | 32ビット |
uint16_t htons(uint16_t hostshort) | ホストからネットワークへ変換 | 16ビット |
uint32_t ntohl(uint32_t netlong) | ネットワークからホストへ変換 | 32ビット |
uint16_t ntohs(uint16_t netshort) | ネットワークからホストへ変換 | 16ビット |
unsigned long int hostlong, netlong;
hostlong = 0x12345678 ;
netlong = htonl( hostlong );
send(conn, &netlong, sizeof(netlong), 0);
snprintf() で文字列に直して送り、strtol() や atoi() でもどす方法もある。
文字列文化。インターネットのアプリケーションでよく使われる。
送信側:
char buf[BUFSIZE];
hostlong = 0x12345678 ;
snprintf(buf,BUFSIZE,"%d\n",hostlong );
send(conn, buf, strlen(buf), 0);
思ったほど遅くはない。
注意:sscanf() は、整数をデコードするために使う分には問題ないが、
文字列を受け取るために使うとバッファ・オーバーフローが生じる可能性があるので、
使わない方がよい。
- 文字コードを合わせる。
- 複数バイトの場合、バイト・オーダも合わせる。
Unicode BOM (byte order mark) 0xffef。
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 * を通じて、構造体の読み書き。
- XML でタグ付けすると、値だけでなく、意味まで送れる。
- JSON (JavaScript Object Notation)
- CSV (Comma Separated Values)
- S式
手続き呼出しの形に見えたら RPC (Remote Procedure Call)。
通信を構造化。send()/receive() を直接使うのは、goto (jump) でプログラ
ムを書くようなもの。call/if/while で書きたい。
プロセスを2種類に分類する。通信は、次のパタンを繰り返す。
- クライアント
- 先にメッセージ(要求)を send() 1回、後でメッセージ(応答)を receive() 1回
- サーバ
- 先にメッセージ(要求)を receive() 1回、後でメッセージ(応答)を send() 1回
send() の回数と receive() の回数は同じ。相互に繰り返す。

図? 通信のパタンからみたクライアントとサーバの定義
混沌とした通信を「構造化」してわかりやすくする。

図? 構造化されていないもの

図? 構造化されたもの
構造化プログラミング:分かりにくいgoto文をつかわないで、わかりやすい
goto文だけ使う。
元々の意味
- クライアント(client)
- サービスを受ける方、顧客
- サーバ(server)
- サービス(service)を提供する方

図? サービスの授受によるクライアントとサーバの定義
サービスを提供する方は、1つのプログラム(コンピュータ)で複数の利用者
の面倒をみる。その結果、1台のサーバに複数のクライアントがつながる。
- クライアント
- 一人で使うもの
- サーバ
- 複数人で共有するもの

図? 複数のクライアントによるサーバの共有
TCP/IP の通信では、通信を始める前に、まず、通信路を作る作る必要がある。
これは、電話で話をする前に、まず、電話をかける操作を行うことと似ている。
- クライアント
- 電話を掛ける方に相当する
- サーバ
- 電話を待っている方
以上のように、クライアントとサーバは、いろいろな意味で使われる。これら
の意味は、多くの場合、一致しているが、一致していないこともある。
通信を開始するパタンで、コンピュータ、プログラム、人間は、次の2つに分
類される。
- 能動的(active)
- ほっといても自分でメッセージを発信し始める
- 受動的(passive)、受け身
- 何か言われると答えるが、自分ではメッセージを発信し始めることはない
クライアントとサーバから作られたシステムは、クライアントが能動的になり、
サーバは、受動的になることが多い。

図? 能動的なクライアントと受動的なサーバ
例:WWWサーバは、WWWクライアントから何か要求が来ない限り、ずっと
黙っている。
コンピュータを使う時には、人間が能動的になり、コンピュータが受動的にな
る。
テレビを見ている時には、人間が受動的になり、テレビが能動的になる。
講義形式の授業では、サービスの授受では、教官がサーバで、学生がクライア
ントになる。通信の開始の方法では、教官が能動的になり、学生が受動的にな
る。
大学以上では、学生は、能動的になることが求められている。
P2P (Peer to Peer) という用語の意味は、怪しい。
混沌とした通信を
構造化
してわかりやすくしたものが、クライアント・サーバ・モデルである。
サーバあるシステムでは、サーバが落ちるとシステム全体が動作しなくなる。
このように複数の要素から構成されているシステムで、ある要素が故障した時
に、全体が動作しなくなるような場所を、単一障害個所(single point of
failure) という。
コンピュータサイエンスでは、古くから、単一障害個所を避けるための研究が
行われてきている。もっとも成功している方法は、サーバを複数用意する方法
である。
サーバがないシステムでは、下手に作るとどの要素が故障してもシステム全体
が止まってしまうことになる。
サーバがないシステムで成功している例はある。
- インターネットの基幹のルータ。(IPv4 の BGP (Border Gateway Protocol) は、スケーラビリティ的に厳しい所には来ている。)
- ニュースシステム (後述)
peer は、「対等の仲間」の意味。「通信相手」という意味もある。
検索は、サーバで索引を集めた方が速い。Web 上の検索エンジンなど。
サーバがない方法の利点(特徴)
- うまく作れば、単一障害点がなくなる。
- サーバを維持するコストが不用である。
- サーバを経由しないで通信が行われると、サーバの負荷が減る。
- 無政府的で面白い。
サーバがない方法の問題点
- 下手に作ると、どの要素が故障しても全体が止る
(single point of failure はないが、multiple points of failure になる)
- 検索などは遅い
- 責任の所在が不明になる
- 通信相手が本物かどうか確かめるのがたいへん
Napster
- 1999年起業。
- サーバでは、音楽ファイルの索引を置く。
- 音楽データの交換は、サーバを経由することなく、個々のプログラム間で
行われる。
- 2000年、全米レコード協会が提訴
- 2001年、Napster 敗訴。
- その後、別の会社買収し、ブランド名だけ残る。
今は、独自の著作権管理技術を使っている。
Napster は、学問的には、特に目立った新技術はない。
クライアント・サーバ・モデルに基づくプロセス間通信で、
手続き呼出しの形に見えたら
RPC (Remote Procedure Call)
(
遠隔手続き呼び出し
)
プログラムのパタン。
要求を一度だけ送る場合。クライアントは複数回動作したり、複数のクライア
ントが同時に動くことが多い。
main() {
connect(); // 結合が作られる通信プリミティブを使う時
marshal();
send();
receive();
unmarshal();
close(); // 結合が作られる通信プリミティブを使う時
}
サーバ側は、無限ループを含み、何度でも要求を受け取る。
main()
make_port(); // 結合が作られる通信プリミティブを使う時
while( 1 )
{
accept(); // 結合が作られる通信プリミティブを使う時
receive();
unmarshal();
仕事();
marshal();
send();
close(); // 結合が作られる通信プリミティブを使う時
}
}
Last updated: 2008/12/07 20:15:09
Yasushi Shinjo / <yas@is.tsukuba.ac.jp>