view paper/nozomi-master.tex @ 160:e20f743b5418

add reference
author Nozomi Teruya <e125769@ie.u-ryukyu.ac.jp>
date Sat, 03 Feb 2018 15:04:47 +0900
parents cad92fc74613
children cc301066b983
line wrap: on
line source

\documentclass[a4j,12pt]{jreport}
\usepackage{master_paper}
\usepackage{ascmac}
\usepackage{bussproofs}
\usepackage[dvipdfmx]{graphicx}
\usepackage{here}
\usepackage{listings}
\usepackage{comment}
\usepackage[deluxe, multi]{otf}
\usepackage{url}
\usepackage{cite}
\usepackage{listings}
\usepackage{colonequals}
\usepackage[utf8]{inputenc}

%\input{dummy.tex} %% font

\jtitle{分散フレームワークChristieの設計}
\etitle{Design of Distributed framework Christie}
\year{2018年 3月}
\eyear{March 2018}
\author{照屋 のぞみ}
\eauthor{NOZOMI TERUYA}
\chife{指導教員:教授 和田 知久}
\echife{Supervisor: Prof. Tomohisa WADA}

\marklefthead{% 左上に挿入
  \begin{minipage}[b]{.4\textwidth}
    琉球大学大学院学位論文(修士)
\end{minipage}}

\markleftfoot{% 左下に挿入
  \begin{minipage}{.8\textwidth}
    並列分散フレームワークChristieの設計
\end{minipage}}

\newcommand\figref[1]{図 \ref{fig:#1}}
\newcommand\tabref[1]{表 \ref{tab:#1}}
\newcommand{\tblcaption}[1]{\def\@captype{table}\caption{#1}}

\lstset{%
  language={Java},%使用言語
    basicstyle={\small},%書体
  commentstyle={\small\itshape},%コメントの書体
    keywordstyle={\small\bfseries},%キーワードの書体
  %identifierstyle={\small},%
  %ndkeywordstyle={\small},%
  stringstyle={\small},%文字列の書体
    frame={trlb},%外枠
  breaklines=true,%改行
    columns=[l]{fullflexible},%
  xrightmargin=0zw,%
    xleftmargin=3zw,%
  numbers=left,%行番号の表示
    numberstyle={\scriptsize},%行番号の書体
  numbersep=1zw,%
    stepnumber=1,
  lineskip=-0.5ex,%
    captionpos=b,%キャプションの位置
}

\def\lstlistingname{リスト}
\def\lstlistlistingname{リスト目次}


%%% 索引のために以下の2行を追加
\usepackage{makeidx,multicol}
\makeindex
\begin{document}

%rome
\frontmatter

\maketitle
\newpage

\makecommission

%要旨
\input{abstract.tex}

%目次
\tableofcontents

%図目次
\listoffigures

%表目次
\listoftables

%リスト目次
\lstlistoflistings


%arabic
\mainmatter

%chapters

\chapter{分散プログラミングの信頼性向上}
スマートフォンやタブレット端末の普及率が増加している。
それに伴いインターネット利用者数も増加しており、ネットワーク上のサービスには、信頼性とスケーラビリティーが要求される。
ここでいう信頼性とは、定められた環境下で安定して仕様に従った動作を行うことを指す。
またスケーラビリティーとは、分散ソフトウェアに対して単純にノードを追加するだけで性能を線形的に上昇させることができる性質である。
しかし、これらをもつ分散プログラムをユーザーが一から記述することは容易ではない。

これらの問題を解決するために、当研究室ではデータをData Segment、タスクをCode Segmentという単位で記述するプログラミング手法を導入した分散フレームワークAlice を開発した。

Aliceが実用的な分散アプリケーションを記述でき、仕様の変更を抑えた信頼性の高い拡張を可能にするということは、水族館の例題やTreeVNCの例題から確認された。
しかし、AliceにNAT越えの機能を実装しようとした際、Data Segment Managerが1つしか持てないために拡張が困難であることが分かった。
また、AliceではAPI設計が煩雑で、プログラマが処理の順番やデータの型を考慮して書く必要があった。
これではバグを引き起こす可能性が高いため、信頼性を上げるにはより直感的なAPIで再設計すべきだと考えた。

本研究では、Aliceから得られた知見をもとに、分散フレームワークChristieの設計を行う。
Christieでは、シンプルな記述で信頼性の高いスケーラブルな分散プログラムの作成を可能にする。
また、当研究室で開発している言語CbCと互換可能な設計を目指す。


%分散フレームワークへの要求
%・スケーラブルなプログラミングの実現
%   ・記述性の高さ、テストのしやすさがバグをおさえる。
%・信頼性の高い分散トポロジーを意識した通信プロトコル。

% 分散計算の見通しを良くする



\chapter{分散フレームワークAliceの概要}
\section{CodeSegmentとDataSegment}
AliceではCode Segment(以下CS)とData Segment(以下DS)の依存関係を記述することでプログラミングを行う。

CSは実行に必要なDSが全て揃うと実行される。CSを実行するために必要な入力されるDSのことをInputDS、CSが計算を行った後に出力されるDSのことをOutput DSと呼ぶ。

データの依存関係にないCSは並列実行が可能である(図 \ref{fig:CS} )。
CSの実行においてDSが他のCSから変更を受けることはない。そのためAliceではデータが他から変更され整合性がとれなくなることはない。

\begin{figure}[htbp]
    \begin{center}
        \includegraphics{images/dsandcs2.pdf}
    \end{center}
    \caption{CodeSegmentの依存関係 }
    \label{fig:CS}
\end{figure}

\newpage

AliceはJavaで実装されており、DSはJava Objectに相当する。
CSはRunnableなObject(void run()を持つObject)に相当する。
プログラマがCSを記述する際は、CodeSegmentクラスを継承する。

DSは数値や文字列などの基本的なデータの集まりを指し、Aliceが内部にもつデータベースによって管理されている。このデータベースをAliceではDS Managerと呼ぶ。

CSは複数のDS Managerを持っている。DSには対になるString型のkeyが存在し、それぞれのManagerにkeyを指定してDSにアクセスする。
一つのkeyに対して複数のDSをputするとFIFO的に処理される。なのでData Segment Managerは通常のデータベースとは異なる。


\newpage

\section{DataSegmentManager}
DS Manager(以下DSM)にはLocal DSMとRemote DSMが存在する。Local DSMは各ノード固有のデータベースである。

Remote DSMは他ノードのLocal DSMに対応するproxyであり、接続しているノードの数だけ存在する(図 \ref{fig:Remote DSM} )。
他ノードのLocal DSMに書き込みたい場合はRemote DSMに対して書き込めば良い。


\begin{figure}[h]
    \begin{center}
        \includegraphics[width=150mm]{images/remote_datasegment.pdf}
    \end{center}
    \caption{Remote DSMは他のノードのLocal DSMのproxy }
    \label{fig:Remote DSM}
\end{figure}


Remote DSMを立ち上げるには、DataSegmentクラスが提供するconnectメソッドを用いる。
接続したいノードのipアドレスとport番号、そして任意のManager名を指定することで立ちあげられる。
その後はManager名を指定してData Segment APIを用いてDSのやり取りを行うため、プログラマはManager名さえ
意識すればLocalへの操作もRemoteへの操作も同じ様に扱える。


\newpage

\section{Data Segment API}
DSの保存・取得にはAliceが提供するAPIを用いる。
putとupdate、flipはOutput DS APIと呼ばれ、DSをDSMに保存する際に用いる。
peekとtakeはInput DS APIと呼ばれ、DSをDSMから取得する際に使用する。

\begin{itemize}
\item {\ttfamily void put(String managerKey, String key, Object val)}
\end{itemize}
DSをDSMに追加するためのAPIである。第一引数はLocal DSMかRemote DSMかといったManager名を指定する。そし
て第二引数で指定されたkeyに対応するDSとして第三引数の値を追加する。

\begin{itemize}
\item {\ttfamily void update(String managerKey, String key,  Object val)}
\end{itemize}
updateもDSをDSMに追加するためのAPIである。putとの違いは、queueの先頭のDSを削除してからDSを追加するこ
とである。そのためAPI実行前後でqueueの中にあるDSの個数は変わらない。

\begin{itemize}
\item{\ttfamily void flip(String managerKey, String key,  Receiver val)}
\end{itemize}
flipはDSの転送用のAPIである。取得したDSに対して何もせずに別のKeyに対し保存を行いたい場合、一旦値を取
り出すのは無駄である。flipはDSを受け取った形式のまま転送するため無駄なコピーなくDSの保存ができる。

\begin{itemize}
\item {\ttfamily void take(String managerKey, String key)}
\end{itemize}
takeはDSを読み込むためのAPIである。読み込まれたDSは削除される。要求したDSが存在しなければ、CSの待ち合わせ (Blocking)が起こる。putやupdateによりDSに更新があった場合、takeが直ちに実行される。

\begin{itemize}
\item {\ttfamily void peek(String managerKey, String key)}
\end{itemize}
peekもDSを読み込むAPIである。takeとの違いは読み込まれたDSが削除されないことである。



\newpage

\section{CodeSegmentの記述方法}
CSをユーザーが記述する際にはCodeSegmentクラスを継承して記述する(ソースコード \ref{src:StartCodeSegmen
t} , \ref{src:CodeSegment})。

継承することによりCode Segmentで使用するData Segment APIを利用する事ができる。

Alice には、Start CS (ソースコード \ref{src:StartCodeSegment} )というC の main に相当するような最初に
実行される CS がある。
Start CSはどのDSにも依存しない。つまりInput DSを持たない。
このCSをmainメソッド内でnewし、executeメソッドを呼ぶことで実行を開始させることができる。


\lstinputlisting[label=src:StartCodeSegment, caption=StartCodeSegmentの例]{source/StartCodeSegment.java}
\lstinputlisting[label=src:CodeSegment, caption=CodeSegmentの例]{source/TestCodeSegment.java}

\newpage

ソースコード \ref{src:StartCodeSegment} は、5行目で次に実行させたいCS(ソースコード \ref{src:CodeSegment} )を作成している。
8行目でOutput DS APIを通してLocal DSMに対してDSをputしている。
Output DS APIはCSの{\tt ods}というフィールドを用いてアクセスする。
{\tt ods}は{\tt put}と{\tt update}と{\tt flip}を実行することができる。
TestCodeSegmentはこの"cnt"というkeyに対して依存関係があり、8行目でputが行われるとTestCodeSegmentは実
行される。


CSのInput DSは、CSの作成時に指定する必要がある。指定はCommandType(PEEKかTAKE)、DSM名、そしてkey よっ
て行われる。
Input DS API はCSの{\tt ids}というフィールドを用いてアクセスする。
Output DSは、{\tt ods}が提供するput/update/flipメソッドをそのまま呼べばよかったが、Input DSの場合{\tt ids}にpeek/takeメソッドはなく、create/setKeyメソッド内でCommandTypeを指定して実行する。

ソースコード\ref{src:CodeSegment}は、0から9までインクリメントする例題である。
2行目では、Input DS APIがもつcreateメソッドでInput DSを格納する受け皿(Receiver)を作っている。
引数には{\tt PEEK}または{\tt TAKE}を指定する。
\begin{itemize}
\item {\ttfamily Receiver create(CommandType type)}
\end{itemize}

4行目から6行目はコンストラクタである。コンストラクタはオブジェクト指向のプログラミング言語で新たなオ
ブジェクトを生成する際に呼び出されて内容の初期化を行う関数である。

 TestCodeSegmentのコンストラクタが呼ばれた際には、
 \begin{enumerate}
 \item CSが持つフィールド変数 {\tt Receiver input}に{\tt ids.create(CommandType.TAKE)}が行われ、{\tt input}が初期化される。
 \item 5行目にあるTestCodeSegmentのコンストラクタのTAKEが実行される。
 \end{enumerate}

5行目は、2行目のcreateで作られたReceiverが提供するsetKeyメソッドを用いてLocal DSMからDSを取得している。
\begin{itemize}
\item \verb+void setKey(String managerKey, String key)+
\end{itemize}
setKeyメソッドはpeek/takeの実行を行う。どのDSMのどのkeyに対してpeekまたはtakeコマンドを実行させるかを指定できる。コマンドの結果がレスポンスとして届き次第CSは実行される。

\newpage

実行されるrunメソッドの内容は
\begin{enumerate}
\item 10行目で取得されたDSをInteger型に変換してcountに代入する。
\item 12行目でcountをインクリメントする。
\item 16行目で次に実行されるCSを作る。run内の処理を終えたらCSは破棄されるため、処理を繰り返したい場合はこのように新しいくCSを作る必要がある。この時点で次のCSはInput DSの待ち状態に入る。
\item 17行目でcountをLocal DSMにputする。Input DSが揃い待ち状態が解決されたため、次のCSが実行される。
\item 13行目が終了条件であり、countの値が10になれば終了する。
 \end{enumerate}
となっている。

1.で用いられているasInteger()はasClassメソッドの一部であり、asClassはtake/peekで取得したDSをObject型から任意の型で取得するためのAPIである。

\begin{itemize}
    \item {\ttfamily <T> T asClass(Class<T> clazz)}
\end{itemize}

CS内でDSのデータを扱うには、正しい型を意識しながらこのasClassメソッドを使わなければならない。


\newpage


\section{AliceのMeta Computation}
Aliceでは、処理をComputationとMeta Computationに階層化し、コアな仕様と複雑な例外処理に分離する。
AliceのComputationは、keyによりDSを待ち合わせ、DSが揃ったCSを並列に実行する処理と捉えられる。
それに対して、AliceのMeta Computation は、Remoteノードとの通信トポロジーの構成や、通信するデータ形式の変換と言える。

Aliceの機能を追加するということはプログラマ側が使うMeta Computationを追加すると言い換えられる。
AliceではMeta Computationとして分散環境の構築等の機能を提供するため、プログラマはCSを記述する際にトポロジー構成や切断、再接続という状況を予め想定した処理にする必要はない。
プログラマは目的の処理だけ記述し、切断や再接続が起こった場合の処理をMeta Computationとして指定するだけでよい。

このようにプログラムすることで、通常処理と例外処理を分離することができるため、仕様の変更を抑えたシンプルなプログラムを記述できる。
仕様の変更を抑えてプログラムの拡張ができるということは、コードを破壊しないため変更以前の信頼性を保てるということである。

Meta ComputationもCS/DSで作られており、プログラマ側から見えないこれらのCS/DSはMeta CS/Meta DSと呼ばれる。

現在Aliceには、データの圧縮機能、トポロジーの構成・管理機能、ノードの生存確認機能、ノードの切断・再接続時の処理管理機能などのMeta Computationが用意されている。

\newpage

\subsection{Aliceの圧縮機能}
リモートノードに大きなデータを送るために、データを圧縮したい場合がある。
そこで、Aliceは圧縮をサポートしている。
しかし、単に圧縮のメソッドを用意したわけではない。
圧縮データの展開と、圧縮したまま別ノードへの転送を同時に実現したい場合があるため、Meta CSを介すことでDSに圧縮と非圧縮のデータを同時に持てるようにしている(図\ref{fig:compress})。

\begin{figure}[h]
\begin{center}
\includegraphics[width=160mm]{images/compress.pdf}
\end{center}
\caption{DSが圧縮と非圧縮の両方を持つ}
\label{fig:compress}
\end{figure}

1つのDS内にMeta DSとして以下の3つの表現を持たせることでデータに多態性を持たせ、必要に応じた形式でDSを扱う。

\begin{enumerate}
  \item 一般的なJavaのクラスオブジェクト
  \item MessagePack for Java\cite{}でシリアライズ化されたバイナリオブジェクト
  \item 2を圧縮したバイナリオブジェクト
\end{enumerate}

Local DSMにputされた場合は、(1)の一般的なJavaクラスオブジェクトとして追加される。
Remote DSMにputされた場合は、通信時に(2)のbyteArrayに変換されたバイナリオブジェクトに変換されたDSが追加
される。
Local/Remote DSMにDSを圧縮して保存したい場合は(3)の圧縮形式を用いる。

\newpage

データの圧縮を指定するには、putするDSMの名前の前に"compressed"をつけるだけでよい。
\ref{src:before},\ref{src:after}は通常のDSと圧縮のDSを扱う際の記述の例である。

\lstinputlisting[label=src:before, caption=通常のDSを扱うCSの例]{source/beforeCompress.java}
\lstinputlisting[label=src:after,caption=圧縮したDSを扱うCSの例]{source/afterCompress.java}

このようにコードの変更を抑えて圧縮できるため、他の計算部分を変えずにデータ形式が指定できる。
また、DSを取り出す際もasClass()内部で自動で展開が行われるため、コードの変更がなく、プログラマがデータの展開を考える必要がない。


\subsection{TopologyManager}
Aliceでは、ノード間の接続管理やトポロジーの構成管理を、Topology ManagerとTopology NodeというMeta Computationが提供している。
プログラマはトポロジーファイルを用意し、Topology Managerに読み込ませるだけでトポロジーを構成することができる。
トポロジーファイルはDOT Language\cite{}という言語で記述される。
DOT Languageとは、プレーンテキストを用いてデータ構造としてのグラフを表現するためのデータ記述言語の一
つである。
ソースコード\ref{src:topologyfile}は3台のノードでリングトポロジーを組むときのトポロジーファイルの例である。

    \lstinputlisting[label=src:topologyfile, caption=トポロジーファイルの例]{source/TopologyFile.dot}
DOT Languageファイルはdotコマンドを用いてグラフの画像ファイルを生成することができる。そのため、記述したトポロジーが正しいか可視化することが可能である。

Topology Managerはトポロジーファイルを読み込み、参加を表明したクライアント(以下、Topology Node)に接続するべきクライアントのIPアドレスやポート番号、接続名を送る(図\ref{fig:topologymanager})。

\newpage

\begin{figure}[h]
\begin{center}
\includegraphics[width=80mm]{images/topologymanager.pdf}
\end{center}
\caption{Topology Managerが記述に従いトポロジーを構成}
\label{fig:topologymanager}
\end{figure}

トポロジーファイルでlavelとして指定した名前はRemote DSMの名前としてTopology Nodeに渡される。
そのため、Topology NodeはTopology ManagerのIPアドレスさえ知っていれば自分の接続すべきノードのデータを受け取り、ノード間での正しい接続を実現できる。


また、実際の分散アプリケーションでは参加するノードの数が予め決まっているとは限らない。
そのためTopology Managerは動的トポロジーにも対応している。
トポロジーの種類を選択してTopology Managerを立ち上げれば、あとは新しいTopology Nodeが参加表明するたびに、Topology ManagerからTopology Nodeに対して接続すべきTopology Nodeの情報がput
され接続処理が順次行われる。
そしてTopology Managerが持つトポロジー情報が更新される。
現在Topology Managerでは動的なトポロジータイプとして二分木に対応している。
%TopologyNodeとnodenameの説明もう少し




\chapter{Aliceの問題点}
Aliceを拡張していく中でいくつかの問題点が明らかになり、これらを解決するにはAlice自体を再設計する必要があるとわかった。


\section{直感的でないAPI}
2.4で示したように、CSで使うDSをtake/peekのメソッドを直接は呼び出せない。
一度フィールドでReceiverをcreateして、その後Reveiverに対してsetKeyで待ち合わせるkeyを指定しなければならない。
これでは手間がかかる上、コードを読んだ際にどのKeyに対して待ち合わせを行っているのか直感的に分からない。
さらに、setKeyはそのDSを待ち合わせているCS以外からも呼び出せてしまう\ref{src:StartSetKey}。

    \lstinputlisting[label=src:StartSetKey, caption=setKeyを外部から呼び出す例]{source/StartSetKey.java}
    \lstinputlisting[label=src:SetKey]{source/SetKey.java}

    このような書き方をされると、CSだけを見てどのkeyに対して待ち合わせを行っているのかわからないため、setKeyを呼び出しているコードを辿る必要がある。
可読性の低いコードはプログラマの負担となるため、CSが何を待ち合わせているのかそのCSを見ただけで理解できるようにAPIを改善すべきである。


\section{setKeyは最後に呼ばなければならない}
setKeyメソッドをコンストラクタで呼ぶ際、setKeyメソッドを必ず最後に呼ばなければならない。

CSは内部で実行に必要なDSを数えている。DSの取得に成功するとこの値が、デクリメントされ、0になると必要なDSが全て揃ったことと判断されThread poolへ送られる。

setKey移行に処理を記述した場合、その処理が行われない可能性がありThread poolへと送られNullPointerExceptionを引き起こす。

\lstinputlisting[label=src:NullPointerException,caption=NullPointerExceptionになる可能性がある]{source/ShowDataFailed.java}

ソースコード\ref{src:NullPointerException}は、for文でsetKeyとids.createをcntの回数呼び、動的にDSの取得数を決めようとしている。しかし、setKeyが最初に呼ばれた際に、DSの取得に成功すると実行可能と判断されてしまう。runの中でinfoの配列の要素だけ中身を表示させようとしてるが、2回目のasClassでNullPointExceptionを引き起こす。

\newpage

今回の場合、コンストラクタ内をソースコード\ref{src:success}のように記述する必要がある。

\lstinputlisting[label=src:success,caption=NullPointerExceptionにならない記述]{source/ShowData.java}

このように記述の順序を考えながらプログラミングしなければならない設計では、バグを引き起こし信頼性を損なうことに繋がる。より自然に扱えるAPI設計にするべきだと考える。


\section{動的なsetKey}
setKeyはCSのコンストラクタで指定することが多い。
このとき、指定するkeyは引数などから動的に受け取り、セットすることができる。
しかし、その使い方では、putする部分など、該当するkeyを扱う全てコードを変更しなければならない。
現在のAliceではsetKeyが柔軟に使えるがために、慎重に書かなければプログラムの信頼性が保てない。
そのため、動的なsetKeyはできないように制限したほうが良いと考える。


\section{型が推測できない}
inputDSを受け取るReceiverはデータをObject型で持っており、そのデータをCS内で扱うには正しい型にキャストする必要がある。
しかし、inputDSで指定するのはkeyのみであり、そのデータの型までは分からない。
そのため、DSの型を知るにはputしている部分まで辿る必要がある。
辿ってもflipされている可能性もあるため、最初にそのDSをputしている部分を見つけるのは困難である。
従って、待ち合わせているkeyにどのような型のデータが対応しているのかをそのCSを見ただけで分かるようにするべきと考える。

\newpage

\section{key名と変数名の不一致}
2.4のCodeSegmentの例題である通り、key名とそのkeyで待ち合わせたDSを受け取るReceiver名は異なることがある。
もしプログラマが適当に命名してしまえば後々混乱を招くため、待ち合わせるkey名とinput DS の変数名一致を強制させたい。


\section{DataSegmentの明瞭性}
2.5.1で示したように、Aliceに圧縮のMeta Computationを実装した際、DS内に複数の型を同時に持たせるようにした。


しかしこれでは、DSが今どの形式を持っているのか、どの状態にあるのかがわかりづらい。
また、DSがbyteArray型を受け取った場合、データであるObject型として渡されたものなのか、MessagePackや圧縮で変換されたものなのかを判別する処理を入れなければならなかった。
今後DSにより多様な形式を同時に持たせることになれば、さらにその判別の処理が増えることになる。


Alice自体の拡張・デバッグをしやすくするためにも、DSがどの型を持っているのかをひと目で分かるようにしたい。


\section{LocalDataSegmentManagerを複数持てない}
Aliceでは1つのノードにつき1つしかLocalDSMを立ち上げられない作りになっている。
そのために以下のような問題が発生した。

\subsection{1つのノードで複数台DSM同士のテストが行えない}
当研究室では分散データベースJungle\cite{}を開発しており、その分散通信部分にはAliceが用いられている。
Jungleのような分散アプリケーションの開発では、1つのマシン上で複数の疑似ノードを立ててテストを行いたい場合があった。
しかし、Aliceでは一つのアプリケーション内にLocalDSMは一つと決まっていたため、テストに必要なノード数分だけアプリケーションを別で立ち上げなければならないという手間があった。
このためのシェルスクリプトをプログラマが書かなければならないのは本質的な作業ではない。
より気軽にテストができるよう、同一プログラム内でLocalDSMを複数立ち上げられるようにすべきだと考えた。

\subsection{TopologyManagerの拡張が困難}
Aliceではより自由度の高い通信を行うために、TopologyManagerに幾つかの機能を追加すること考えていた。

その一つがNAT越えの機能である。NAT越えは分散アプリケーション構築における課題の1つでもあるが、プログラマにとってその実装は容易ではない。Topology ManagerにNATを越えたノード間通信機能をつけることにより、ネットワークを気にせずに通信が行えるようにしたい。

図 \ref{fig:nat}はTopologyManagerを用いてNAT越えをするための設計である。

\begin{figure}[h]
\begin{center}
\includegraphics[width=180mm]{images/nat.pdf}
\end{center}
\caption{複数のTopologyManagerによるNAT越えの実現}
\label{fig:nat}
\end{figure}

\newpage

また、別トポロジーで立ち上げたアプリケーション同士を接続する機能も追加したいと考えていた。
TreeTopologyのVNCアプリとStarTopologyのチャットアプリを連携したいという要望が生まれたためである。
別トポロジーのアプリケーションが接続可能になれば、VNC画面のスナップショットをChat上に載せたり、VNC上にChatの内容をコメントとして流すといった拡張が容易になる(図 \ref{fig:vncandchat})。

\begin{figure}[h]
\begin{center}
\includegraphics[width=180mm]{images/vncandchat.pdf}
\end{center}
\caption{別トポロジーのアプリケーションの接続}
\label{fig:vncandchat}
\end{figure}

TopologyManagerはネットワークごと、トポロジーごとに存在するため、いずれの機能も複数のTopologyManagerを立ち上げ、連携させることで実現可能となる。

今までのAliceでは、1つのノードに対してTopology Managerは1つと決められていた。
Topology Managerと各ノードのやり取りをするのは、ノードごとに実行されるTopology NodeというMeta Computationである。
Topology Managerは接続されたnodeの情報(nodeNameとIPアドレスのHashMap)を"nodeTable"というKeyに対応するDSとして保存している。
そしてTopology NodeはTopology Managerから割り当てられたnodeNameを"hostname"というKeyに保存する。
つまり、接続するTopology Managerが増えればTopoloyNodeに割り当てられるnodeNameも増えるため、今までのように"hostname"という1つのKeyだけでは対応できない。
1つのノードに複数のTopologyManagerを対応させるには、TopologyNodeが複数のnodeNameを持つ必要がある。
TopologyNodeが複数のTopologyManagerに対応できるようにしなければならない。


そこで、Meta Computationとして、通常のLocal DSMとは別にTopology ManagerごとのMeta Local DSMを立ち上げる方法が考えられる(図 \ref{fig:somehostname})。
\begin{figure}[h]
\begin{center}
\includegraphics[width=120mm]{images/somehostname.pdf}
\end{center}
\caption{複数のTopologyManagerに複数のLocalDSMが対応}
\label{fig:somehostname}
\end{figure}

\newpage

それぞれのTopology Managerに対応するLocalDSMを作り、それぞれに対応したnodeNameを格納することで、DSMを切り替えるだけでTopologyNodeの仕様は変えずに複数のTopology Managerに対応できるという設計である。

しかし、現在のAliceのコードではDSMを管理するclassがstatic classであったため、複数のLocal DSMを持つことはできなかった。
staticを取り除こうとしたところ、Aliceの大部分のコードを修正する必要があることがわかった。
よって、再設計の際にはstatic classのない実装を行い、DSM切り替えによる方式を実現したい。






\chapter{分散フレームワークChristieの設計}

\section{Christieの必要条件}
3章でのAliceの問題点を踏まえ、新たにフレームワークを作り直すべきだと考えた。
本章では、新たに作った分散フレームワークChristieの設計を説明する。
Christieに必要な要件は以下のように考える。

\begin{itemize}
\item {\ttfamily create/setKeyのような煩雑なAPIをシンプルにし可読性を向上させる}
\end{itemize}

\begin{itemize}
\item {\ttfamily プログラマが型を推測しなくとも整合性がとれるように型を解決し、信頼性を向上させる}
\end{itemize}

\begin{itemize}
\item {\ttfamily staticなLocalDSMをなくし、複数のインスタンスを同時に立ち上げられるようにすることでスケーラビリティを向上させる}
\end{itemize}



\section{Christieの基本設計}
基本的にはAliceと同じ、タスクとデータを細かい単位に分割して依存関係を記述し、入力が揃った順から並列実行するというプログラミング手法を用いる。


ChristieはAliceと同じくJavaで書かれている。
しかし将来的に当研究室が開発するGearsOSに取り入れたいため、GearsOSを構成する言語であるContinuation based C(CbC)に互換可能な設計を目指す。


GearsOSではCodeSegment/DataSegmentと同様の概念としてCodeGear/DataGearという名称を用いているため、Christieでもそれに倣いCodeGear/DataGear(以下、CG/DG)と呼ぶこととする。

\newpage

DGはAliceと同様にDataGearManager(以下DGM)が管理する。
DGMはLocalとRemoteがあり、全てのDGMはCodeGearManager(以下CGM)で管理される。
GearsOSではContextという全てのCG/DGを一括管理するプロセスがあり、AliceのCGMもこのContextに相当する。
全てのCGMはThreadPoolと他のCGM全てのリストを共有しているため、全てのCG/DGにアクセス可能である(図\ref{fig:christieClass})。

\begin{figure}[h]
\begin{center}
\includegraphics[width=130mm]{images/ChristieClass.pdf}
\end{center}
\caption{CGMはCGMとDGMを管理する}
\label{fig:christieClass}
\end{figure}

CGを記述する際はAlice同様CodeGear.classを継承する。
CodeGearは

void run(CodeGearManager cgm)を持つclassであり、プログラマはrunメソッド内に処理を記述する。 
インプットで指定したkeyに対応したDGが全て揃ったとき、runに書かれた処理が実行される。
ChristieのAPIにはrunの引数で受け取ったCGMを経由してアクセスする。
GearsOSではCG間でContextを受け渡すことによってCGはDGにアクセスするため、Christieでもその記述方法を採用した。

通常のRunnableクラスではこのように引数をうけとることができないが、CodeGearExecutorというRunnableのMeta Computationを挟んだことでこのようにCGMを受け渡しながらの記述を可能にした。

詳しいCodeGearの記述方法については、4.4章で説明する。

\newpage

\section{APIの改善}
\subsection{TAKE/PEEK}
InputAPIにはAliceと同じくTakeとPeekを用意した。
ChristieではInput DG の指定にはアノテーションを使う。
アノテーションとは、クラスやメソッド、パッケージに対して付加情報を記述できるJavaのMeta Computationである。
先頭に@をつけることで記述でき、オリジナルのアノテーションを定義することもできる。

AliceではInputの受け皿であるReceiverを作り後からkeyをセットしていたが、
ChristieではInputのためのDGを作り、その上にアノテーションでKeyを指定する(\ref{src:take})。

\lstinputlisting[label=src:take, caption=Takeの例]{source/christie/InputDG.java}


アノテーションで指定したInputDGは、CGを生成した際にCodeGear.class内で待ち合わせの処理が行われる。
これにはJavaのreflectionAPIを利用している。
アノテーションの指定はRUNTIMEではできないため、動的なkeyの指定も防ぐことができる。

\ref{src:take}の2行目にあるように、InputDGを宣言する際には必ず型の指定が必要となる。
DataGearは様々な型のデータを扱うためにJavaの総称型で受け取るようにしており、\textless \textgreater 内に指定した型でデータの型を限定できる。
このように記述することで、Christieでは他の部分を辿らなくてもCGを見るだけでインプットされるデータの型が分かるように可読性を向上させた。
また、取得してきたDGが指定と違う型であった場合はエラーとなるため、型の整合性を保ちながら信頼性の高いプログラミングが可能となった。

また、Aliceではkeyと変数名の不一致から可読性が低くなっていた。
しかしChristieではkeyと変数名が一致しないとエラーとなるため、自然と読みやすいコードが書けるようになっている。
この部分に関しては、JavaのメタプログラミングAPIであるjavassist\cite{}を用いてアノテーションから変数の自動生成も試みたが、javassistでは変数生成の前に他のどのクラスも生成してはならないという制限があったため、Christieでは実現できなかった。


リモートノードに対してTake/Peekする際は、RemoteTake/RemotePeekのアノテーションを用いる(\ref{src:remotetake})。
そのため待ち合わせ先がLocalかRemoteかはアノテーションの違いからひと目でわかるようになった。

\lstinputlisting[label=src:remotetake, caption=RemoteTakeの例]{source/christie/RemoteInputDG.java}

\newpage

なお、圧縮のMeta ComputationはAliceと同様で、指定する際にDGM名の前にcompressedをつける(\ref{src:compresslocal})。

\lstinputlisting[label=src:compresslocal, caption=Localへの圧縮の指定の例]{source/christie/CompressLocal.java}

LocalからのTAKEではDGM名の指定がないが、それはLocalでの圧縮は基本想定していないためである。
しかし、Localでの圧縮をしようと思えばRemoteTakeを用いて間接的にすることは可能である。


\subsection{PUT/FLIP}
OutputAPIにはput/flipを用意した。
put/flipのメソッドはDGMに用意されている。
cal.java
CodeGear.classにはDGMを取得するメソッドがあり、それを用いて書き込みたいDGMを指定して直接putする。
そのためLocal/Remoteの切り替えはDGMの切り替えによって行う。
ソースコード\ref{src:put}、\ref{src:remoteput}はLocalとRemoteにputする記述の例である。

\lstinputlisting[label=src:put, caption=Localへputする例]{source/christie/Put.java}
\lstinputlisting[label=src:remoteput, caption=Remoteへputする例]{source/christie/RemotePut.java}

flipも同様にDGMに直接DGを渡す(\ref{src:flip})。

\lstinputlisting[label=src:flip, caption=Remoteへflipする例]{source/christie/Flip.java}


ChristieではDGMに対して直接putするため、AliceのODSにあたる部分はない。
ODSを経由するより直接DGMに書き込むような記述のほうが直感的であると考えたためである。

\newpage

\subsection{getData()}
AliceのasClassに相当するのがgetDataである。
ソースコード\ref{src:getdata}はgetDataを用いてInputDGからデータを取得する例である。

\lstinputlisting[label=src:getdata, caption=getDataの例]{source/christie/GetData.java}

Aliceと違う点は、プログラマが型を指定しなくて良い点である。
4.2.1で示したように、InputDGを生成する際には型を指定する。
この型は内部で保存され、リモートノードと通信する際も保たれる。
このようにgetDataするだけでプログラマが指定しなくとも正しい型で取得できるため、プログラマの負担を減らし信頼性を保証することができる。



\section{CodeGearの記述方法}
以下のコードはLocalDSMにputしたDGを取り出して表示するのを10回繰り返す例題である。

\lstinputlisting[label=src:StartCodeGear, caption=StartCodeGearの例]{source/christie/StartTest.java}
\lstinputlisting[label=src:TestCodeGear, caption=CodeGearの例]{source/christie/TestCodeGear.java}

Alice同様、ChristieでもInputDGを持たないStartCGから処理を開始する。
StartCGはStartCodeGear.classを継承することで記述できる。
AliceではStartCSもCodeSegment.classを継承して書かれていたため、どれがStartCSなのか判別しづらかったが、Christieではその心配はない。

StartCGを記述する際にはcreateCGMメソッドでCGMを生成してコンストラクタに渡す必要がある。
ソースコード\ref{src:StartCodeGear}の8行目でそれが行われている。
createCGMの引数にはリモートノードとソケット通信する際使うポート番号を指定する。
CGMを生成した際にLocalDGMやリモートと通信を行うためのDaemonも作られる。

CGに対してアノテーションから待ち合わせを実行する処理はsetupメソッドが行う。
そのためソースコード\ref{src:StartCodeGear}の13行目、\ref{src:TestCodeGear}の10行目のように、newしたCGをCGMのsetupメソッドに渡す必要がある。
AliceではnewすればCGが待ちに入ったが、Christieでは一度CGをnewしないとアノテーションから待ち合わせを行う処理ができないため、newの後にsetupを行う。
そのため、CGの生成には必ずCGMが必要になる。
runでCGMを受け渡すのはこのためである。
なお、StartCGはインプットを持たないため、setupを行う必要がなく、newされた時点でrunが実行される。

\newpage


\section{DataGearManagerの複数立ち上げ}
AliceではLocalDGMがstaticで書かれていたため複数のLocalDGMを立ち上げることができなかった。
しかしChristieではCGMを2つ生成すればLocalDGMも2つ作られる。
複数のLocalDGM同士のやりとりも、Remoteへの接続と同じようにRemoteDGMをproxyとして立ち上げアクセスする(図\ref{fig:remoteDGM})。

\begin{figure}[h]
\begin{center}
\includegraphics[width=130mm]{images/DGM.pdf}
\end{center}
\caption{RemoteDGMを介して他のLocalDGMを参照}
\label{fig:remoteDGM}
\end{figure}

\newpage

ソースコード\ref{multilocal}は、LocalDSMを2つ立ち上げ、お互いをリモートに見立てて通信する例である。
11行目にあるように、RemoteDGMを立ち上げるにはCGMが持つcreateRemoteDGMメソッドを用いる。
引数にはRemoteDGM名と接続するリモートノードのIPアドレス、ポート番号を渡している。

\lstinputlisting[label=src:multilocal, caption=LocalDGMを2つ作る例]{source/christie/MultiLocal.java}

リモートの場合の同じようにアクセスできることで、コードの変更をせずに、同一マシン上の1つのアプリケーション内で分散アプリケーションのテストができるようになった。

また、CGMは内部にCGMのリストをstaticでもっており、複数生成したCGMを全て管理している。
つまり、メタレベルではRemoteDGMを介さずに各LocalDGMに相互アクセス可能である。
そのため、Christieでは容易にNAT越えが実装できることが期待できる。

\section{DataGearの拡張}
Aliceではデータの多態性を実現するためにDS内に複数のデータ形式を保持していた。
しかしChristieではデータ形式ごとに別のclassに分けている。
DataGearを継承したMessagePackDataGearと、それを更に継承したCompressedDataGearを用意した。
そのため子クラスは親クラスのデータ形式を保持しながら新しいデータ形式を持つ形になっている。
クラスを見るだけで今どの形式を保持しているかわかるようになったため、デバッグがしやすくなった。



\chapter{Christieの評価}
\section{Aliceとの分散性能測定}

\section{他フレームワークとの比較}
\subsection{Akka}
\subsection{Corba}
\subsection{Erlang}
\subsection{Hazelcast}

\chapter{まとめ}


\chapter{今後の課題}
\section{TopologyManagerの実装}
Aliceと同じく、静的・動的なトポロジー管理のできるTopologyManagerの実装が必要である。
Christieでは複数のLocalDSMが立ち上げ可能なため、TopologyManagerでのNAT超えも実装し実用性があるかを検証する
また、通信の信頼性を保証するために、TopologyManagerがダウンした際に新たなTopologyManagerを立ち上げる機能もあるべきだと考える。


\section{実用性の検証}
%Aliceと同等の性能を持っているかを測定する必要がある。

\section{GearsOSへの移行}
GearsOSはまだ開発途中であったため、本論文の作成時点ではChristieのような分散機能を実装することが叶わなかった。
GearsOSではモデル検査機構akasha\cite{}があるため、待ちに入っているkeyのputし忘れなどをコンパイルの段階で見つけることができる。
GearsOS上で分散プログラミングができればより信頼性の高いプログラミングが期待できるため、将来的にはChristieをGearsOSの分散機構として取り込みたい。

GearsOSにChristieを移行するには、GearsOSにJavaのアノテーションに相当するMeta Computationを実装する必要がある。
そしてChristieでは実現できなかったアノテーションからの変数の自動生成が行えれば更にプログラミングしやすいAPIになると考えられる。


\chapter{付録}
\section{独自のアノテーション定義}
Christieのアノテーションの実装方法と、そのアノテーションからtakeを実行する部分を解説する。

ソースコード\ref{src:take}、\ref{src:remotetake}がChristie独自のアノテーションの定義である。

\lstinputlisting[label=src:take, caption=Takeの実装]{source/christie/TakeAnnotation.java}
\lstinputlisting[label=src:remotetake, caption=RemoteTakeの実装]{source/christie/RemoteTakeAnnotation.java}

@Targetや@Retentionはアノテーション定義のためのアノテーション、メタアノテーションである。
@Targetには、フィールドやメソッド、コンストラクタなど、このアノテーションの付加対象となる構文要素が何かを記述する。
@Retentionには、SOURCE・CLASS・RUNTIMEが選択でき、アノテーションで付加された情報がどの段階まで保持されるかを定義する。reflectionAPIを利用するにはRUNTIMEでなければならないため、Christieのアノテーションの@Retentionは全てRUNTIMEである。

\newpage

定義したアノテーションの仕様例がソースコード\ref{src:takeAno}、\ref{src:remotetakeAno}である。

\lstinputlisting[label=src:takeAno, caption=Takeアノテーションの使用例]{source/christie/InputDG.java}
\lstinputlisting[label=src:remotetakeAno, caption=RemoteTakeアノテーションの使用例]{source/christie/RemoteInputDG.java}

アノテーションを使う際、()内に記述する値が\ref{src:take}のvalueや\ref{src:remotetake}のdsmNameといったキーに保存される。
通常キーに対して値を入れる場合は、ソースコード\ref{src:remotetakeAno}のようにkey=の形で記述しなければならないが、Takeのようにキーが1つの場合、キー名をvalueにすることでその記述を省略することができる。

setupメソッド内では生成されたフィールドに対してアノテーションを含めた情報を処理している。
これにはJavaのreflectionAPIが使用されている。
reflectionAPIでは対象となるクラスのフィールドやメソッド、それに対するアノテーションやアノテーションが保持するキーにアクセスすることができる。
ソースコード\ref{src:setup}はsetupメソッド内でreflectionAPIを用いてアノテーションからTakeコマンドを作成する部分である。

\lstinputlisting[label=src:setup, caption=reflectionAPIでフィールドの情報を取得]{source/christie/Setup.java}

フィールドから取得したDGとアノテーションから取得したkeyからインプットコマンド(TAKE/PEEK)を生成し、DGMへ送って実行する。
\newpage

\section{通信フロー}
いくつか例をあげてChristieの通信のフローをシーケンス図を用いて解説する。
図\ref{fig:localSequence}はLocalDGMにTakeを行い、LocalDGM内にDGがあったときの処理の流れである。

\begin{figure}[h]
\begin{center}
\includegraphics[width=160mm]{images/LocalSequence.pdf}
\end{center}
\caption{LocalDGMにTakeしたときのフロー}
\label{fig:localSequence}
\end{figure}

プログラマはmainでCGMとStartCGを生成する。
CGMと同時にLocalDGMは作られる。
CGが生成され、setupメソッドが呼ばれるとアノテーションからTAKEコマンドが作られ実行される。
CGは生成したインプットコマンドの総数を初期値としたカウンタを持っており、コマンドが解決される(InputDGが揃う)たびにカウンタは減っていき、0になるとrun内の処理がThreadPoolへ送られる。


\newpage

図\ref{fig:remotePutSequence}は、LocalDGMにTakeを行うが、LocalDGM内にDGがなかったためにPutの待ち合わせをするときの処理の流れである。
mainなどの最初の処理は図\ref{fig:localSequence}と同様のため省略する。

\begin{figure}[h]
\begin{center}
\includegraphics[width=160mm]{images/RemotePutSequence.pdf}
\end{center}
\caption{RemoteDGMにPutしたときのフロー}
\label{fig:remotePutSequence}
\end{figure}

図\ref{fig:localSequence}と同様に、setupメソッドからTAKEコマンドを生成し実行する。
このとき要求したデータがDGM内にない場合はwaitListに入る。
LocalまたはリモードノードからPUTコマンドが実行された際、もしwaitListにPutしたDGを待っているコマンドがあれば実行される。


\newpage
図\ref{fig:remoteTakeSequence}は、RemoteDGMにTakeを行ったときの処理の流れである。

\begin{figure}[h]
\begin{center}
\includegraphics[width=165mm]{images/RemoteTakeSequence.pdf}
\end{center}
\caption{RemoteDGMにTakeしたときのフロー}
\label{fig:remoteTakeSequence}
\end{figure}

StartCGで事前にRemoteDGMを生成しておく。
RemoteTakeアノテーションからRemoteDGMに対するTakeコマンドを生成し実行する。
RemoteTakeのようにリモートからの応答を待つコマンドはRemoteDGMのwaitListに入る。
そして、MessagePack形式に変換したRemoteCommandを作成し、それをRemoteDGMが参照している別ノードのLocalDGMに送る。

それを受け取った側のLocalDGMは、DGがあればREPLYコマンドを生成して送り返す。
もしDGがなければ、リモートから来たコマンドもローカルの場合と同様にLocalDGMのwaitListに入る。

REPLYを受け取るとRemoteDGMはwaitListに入っていたコマンドを解決する。


\chapter{謝辞}
本研究の遂行、また本論文の作成にあたり、ご多忙にも関わらず終始懇切なる御指導と御
教授を賜わりました河野真治准教授に深く感謝したします。

そして、数々の貴重な御助言と技術的指導を戴いた伊波立樹さん、他フレームワークの調査に協力してくださった清水隆博さん、赤堀貴一さん、浜瀬裕暉さん、大城由也さん、並びに信頼研究室の皆様に感謝いたします。
先行研究であるAlice, Federated Linda, Jungle, TreeVNCがなければ本研究はありませんでした。 これら先行研究の設計や実装に関わった全ての先輩方に感謝いたします。

また、本フレームワークの名前の由来となったクリスティー式戦車の生みの親、ジョン・W・クリスティーに敬意を評します。

最後に、日々の研究生活を支えてくださった米須智子さん、菱田正和さん、情報工学科の方々、そして家族に心より感謝いたします。

 
%参考文献
\nocite{*}
\bibliographystyle{junsrt}
\bibliography{reference}

%発表履歴
\addcontentsline{toc}{chapter}{発表履歴}
%\input{history.tex}

%付録
\addcontentsline{toc}{chapter}{付録}
\appendix
%\input{sources.tex}
\end{document}