Mercurial > hg > Papers > 2015 > sugi-master
view paper/chapter3.tex @ 17:675939a7f983
change experiment picture
author | sugi |
---|---|
date | Fri, 23 Jan 2015 16:43:48 +0900 |
parents | b9b3f2241ab4 |
children | fd43827452ad |
line wrap: on
line source
\chapter{Aliceの新機能} \label{chapter:chapter3} 水族館の例題によって、Aliceを用いて分散プログラムを記述可能であることが証明された。 しかし、実用的なアプリケーションを記述するには、まだ機能が足りないと予測される。 そこで、当研究室で開発を行っているTreeVNCをAlice上で実装することで、Aliceに必要な機能を洗い出した。 \section{Dynamic Topologyへの対応} 第2章で示したように分散フレームワークAliceはTopology Fileを読み込むことでTopologyを構成する。 つまり、予め参加するノードの台数が決まっている必要がある。また、Topologyに全ノードが参加するまでアプリケーションが起動しない。 しかし、実際のアプリケーションでは、参加するノードの数は決まっていないため、Topologyを動的に変化させる必要がある。 そこで、Topology Fileの代わりにTopologyを指定して起動させた場合(ソースコード \ref{src:DynamicTopologyManager})、ノードがTopologyに従い、順次追加されるようにTopology Managerに機能を追加した。 \begin{table}[htbp] \lstinputlisting[label=src:DynamicTopologyManager, caption=Dynamic Topology Managerの起動方法]{source/TopologyManager.sh} \end{table} 現在は、TreeVNCのTopologyである木構造のみ指定可能である。引数Childの後に子供の数を指定することで2分木だけではなく3分木などのTopologyを作ることができる。デフォルトでは2分木になっている。 \subsection{Dynamic Topology Managerの参加表明処理} トポロジーファイルを指定して起動した場合は、図 \ref{fig:topologymanagerandnode}で示したように、アプリケーションが起動する前に全ての接続すべきTopology Nodeの情報がTopology Nodeにputされ、接続処理が行われる。 Dynamic Topologyの場合は、新しくTopology Nodeがアプリケーションに参加するたびにTopology ManagerからTopology Nodeに対して、接続すべきTopology Nodeの情報がputされ、接続処理が行われる。(図 \ref{fig:DynamicTopology})。 Dynamic Topologyへの参加表明の方法は、従来の方法と同じく、Topology Nodeの起動時にコマンドライン引数からTopology ManagerのIPアドレスとポート番号を指定するだけでよい。 \begin{figure}[htbp] \begin{center} \includegraphics[width=100mm]{images/DynamicTopologymanagerandnode.pdf} \end{center} \caption{Dynamic Topology ManagerとTopology Node間の通信} \label{fig:DynamicTopology} \end{figure} \section{Keep Alive} ノード間の通信は、Remote Data Segmentに対してputやpeekを行うことでのみ発生する。従って、Code Segmentの実装次第では、長時間通信が行われない可能性がある。通信が行われない間にRemote Data Segmentとの接続が切れた場合、次の通信が行われるまで切断を発見することができない。また、接続状態ではあるが問題が発生し、応答に時間がかかる場合も考えられる。 以上の問題を検知するためにアプリケーションではKeep Aliveという、定期的にheart beatを送り生存確認を行う機能を持つことが望ましい。そこで、Alice自体にKeep Aliveの機能を実装した。 一定時間内にノードから応答がない場合、Keep Aliveにより、そのノードのRemote Data Segmentが切断される。 図 \ref{fig:keepAlive}は、keepAliveの処理をコミュニケーションダイアグラムで示したものである。 keepAliveは、タスクとタスクを実行するTaskExecuterと実行順序を管理するSchedulerによって実装されている。 タスクの種類には、{\tt PING}、{\tt CLOSE}、{\tt CREATE}があり、TaskExecuterは、タスクの種類に従って処理を行なう。 {\tt PING}は、指定されたRemote Data Segmentに対してheartbeatを送信する。 {\tt CLOSE}は、指定されたRemote Data Segmentを削除する。 {\tt CREATE}は{\tt PING}のタスクを作成し、Schedulerに登録する。 タスクを作成する際に実行時間の指定をする。Schedulerにタスクを登録すると、Schedulerはタスクの実行時間に従って、タスクを実行順に並び替える。 \begin{figure}[htbp] \begin{center} \includegraphics{images/keepAlive.pdf} \end{center} \caption{keepAliveの仕組み} \label{fig:keepAlive} \end{figure} \subsubsection{処理の流れ} \begin{enumerate} \item CreateTask(Code Segment)により{\tt PING}タスクが投入される。\label{enum:putPingTask} \item TaskExecuterはSchedulerから次に実行すべき{\tt PING}タスクを受け取る。 \item 指定された時間が訪れるとheartbeatがRemote Data Segment(Node B)に送信される。\label{enum:send} \item \ref{enum:send}と同時にheartbeatを送信したRemote Data Segmentとの接続を切断する{\tt CLOSE}タスクが投入される。\label{enum:putCloseTask} \item \ref{enum:putCloseTask}で投入された{\tt CLOSE}タスクが実行されるまでに、Remote Data Segment(Node B)からのレスポンスがあった場合、RemoveTask(Code Segment)により{\tt CLOSE}タスクが削除される。 %\item \ref{enum:putPingTask}に戻る。 \end{enumerate} \ref{enum:putPingTask}で作られる{\tt PING}タスクは、接続しているRemote Data Segmentの数だけ投入される。 "\_CLSIT"というkeyには、アクセス可能なRemote Data Segmentのkeyの一覧が保存されている。 CreateTaskは、この一欄により動的にタスクを作成している。 以上で説明した処理の流れは、接続状態に問題がない場合である。 接続状態に問題があり、{\tt CLOSE}タスクの実行されるまでにレスポンスがない場合は、{\tt CLOSE}タスクによりRemote Data Segmentが削除される。 heartbeatは、Node AからNode Bに一方向に送られる訳ではなく、Node BからNode Aにも送られている。 \section{切断時の処理} MMORPGでは、試合の最中にサーバーからユーザーが切断された場合、自動的にユーザーが操作するキャラクターをゲーム開始時の位置に戻すという処理が実行される。 同様にTreeVNCでは切断を検知した場合、LostParentというメッセージがトップノードに対して送信される。 以上の例のように、アプリケーションはノードの切断に対する処理を用意したい場合がある。 しかし、Aliceを用いたアプリケーションの場合、アプリケーション側で検知するのは難しい。 切断自体は、Remote Data Segmentに対してwriteまたはreadを行った際に出るExceptionにより判断することができる。 だが、I/O の処理はCode Segmentを実行するThreadで行われない。専用のI/O Threadによって行われるため、Code Segment内でExceptionを捕まえられず、例外処理を行なうことができない。 そこで、Aliceが切断を検知した際に、任意のCode Segmentを実行できる機能 (ClosedEventManager)を追加した。 ユーザはClosedEventManagerにCode Segmentを登録することで、切断時の処理として実行するCode Segmentを指定できる。 \begin{table}[htbp] \lstinputlisting[label=src:registerEvent, caption=切断時に実行されるCode Segmentの登録方法]{source/RegisterEvent.java} \end{table} また、切断したRemote Data Segmentの情報を利用したい場合は、Code Segmentをextends する代わりにClosed Event Code Segmentをextendsし、用意されているMethodを使うことで取得可能である(ソースコード \ref{src:CatchClosedEvent})。 \begin{table}[htbp] \lstinputlisting[label=src:CatchClosedEvent, caption=CloseEventCodeSegmentを継承したCodeSegment]{source/CatchClosedEvent.java} \end{table} ClosedEventCodeSegmentを継承したCode Segmentに、Input Data Segmentを追加記述する事ができる。 その際は、もちろんInput Data Segmentが全て揃うまでCode Segmentは実行されない。 \section{Topologyの再構成} ノードは永続的にアプリケーションに参加し続ける訳ではない。目的を果たすとアプリケーションから離脱する。 Topology次第では、アプリケーションに支障をきたす。 例えば、AliceVNCは木構造であるため、子ノードを持つノードがアプリケーションから離脱した場合、その子ノードに対してデータを送信することができなくなる。 この問題を解決するには、アプリケーションからノードが切断するたびにTopologyの再構成を行なう必要がある。そこで、Dynamic Topology Managerに、Topologyの再構成を行う機能を追加した。 図 \ref{fig:TopologyFIx}、 \ref{fig:TopologyFIx2}、\ref{fig:TopologyFIx3}はTopologyの再構成をコラボレーションダイアグラムで表したものである。 \begin{figure}[htbp] \begin{center} \includegraphics[width=120mm]{images/TopologyFIx.pdf} \end{center} \caption{切断ノードの検知} \label{fig:TopologyFIx} \end{figure} \begin{enumerate} \item Keep AliveがNode1の切断を検知すると、Node3からTopology Managerに対して切断したノードの情報がputされる。keep Aliveは各ノードで動いているため、実際にはNode0とNode4もTopology Managerに対してNode1の情報をputする。 \item Topology Managerは最後にアプリケーションに参加したNode6とその親Node2に対して互いを切断するための準備を行わせる、CLOSEMESSAGEをputする。 \item 切断する準備ができるとお互いに準備完了を知らせるCLOSEREADYをputする。 \item \label {tb:last}CLOSEREADYを受け取ると切断を行い、Remote Data Segmentが使用不可能になる。 \end{enumerate} \begin{figure}[htbp] \begin{minipage}{0.5\hsize} \begin{center} \includegraphics[width=90mm]{images/TopologyFix2.pdf} \end{center} \caption{接続すべきノード情報の送信} \label{fig:TopologyFIx2} \end{minipage} \begin{minipage}{0.5\hsize} \begin{center} \includegraphics[width=80mm]{images/TopologyFix3.pdf} \end{center} \caption{再構成の完了} \label{fig:TopologyFIx3} \end{minipage} \end{figure} \begin{enumerate} \setcounter{enumi}{4} \item Node1、Node3、Node4に対してNode6の情報を送り、接続を行わせる。 \item Node6に対して、Node1、Node3、Node4の情報を送り、接続を行わせる。 \item お互いにRemote Data Segmentの名前を贈り合い、Remote Data Segmentが利用可能になる。 \end{enumerate} \section{再接続の処理} MMORPGでは、試合の最中に障害などによりサーバーから離脱したユーザーが、試合が終わるまでに再びサーバーに接続してきた場合に、再びその試合に参加できるような再接続の処理が用意されている。 分散にアプリケーションでは、MMORPGの例のように再接続してきたノードに対して通常の処理とは別の処理を行わせたい場合がある。そこで、Aliceに再接続してきたノードに、任意のCode Segmentを実行できる機能を追加した。ユーザーはconfigにCode Segmentを継承したClassを登録することで、再接続時に実行されるCode Segmentを指定することができる。 \begin{table}[htbp] \lstinputlisting[label=src:StartAquarium, caption=再接続に実行するCode Segmentの登録方法]{source/StartAquariumFX.java} \end{table} \section{Multicast Data Segment} TreeVNCには、Multicastを利用して起動しているTreeVNCのRoot Nodeの情報の一覧にして表示する接続先自動検索システムという機能がある。この機能によりTreeVNCの起動の際にIPアドレスを入力する手間を省くことができる。 現在のAliceは起動時にTopology ManagerのIPアドレスを入力する必要があり、TreeVNCの接続先自動検索機能が必要と考えられる。 その機能を実現するためにはMulticastに対応する必要がある。そこで、同じマルチキャストアドレスを持つ端末を1つのData Segmentとして扱うMuticast Data Segmentを追加した。 Multicast Data Segmentも他のData Segment同様、Data Segment APIを用いて扱う。 \begin{figure}[htbp] \begin{center} \includegraphics[width=120mm]{images/multicast.pdf} \end{center} \caption{Multicast Data Segment} \label{fig:multicast} \end{figure} 図 \ref{fig:multicast}はMulticast Data Segmentを図で表したものである。Multicast Data Segmentに対してputを行うとnode D、node E、node Fの3つのnodeに対してデータがputされる。同様にTakeを行うと3つのnodeからreplyが来る。 \subsection{Multicast Data Segmentの制限} Multicast Data SegmentはUDPを用いて実装されている。1つのUDPのパケットで運ぶことのできるデータが、65507bytes(65535bytesからIPヘッダの最低サイズ20bytesとUDPのヘッダのサイズ8bytesを引いた大きさ)である。 現状、分割して送る処理をMulticast Data Segmentが持たない。従って、Multicast Data Segmentを利用する際には、データのサイズを65507bytes以下にしなければならない。 \subsection{Multicast Data Segment Manager} Multicast Data SegmentもRemote Data Segment同様Managerを経由して操作を行う。Multicast DSMを作成するとMulticast Data Segmentに対する送受信用のスレッドが作成される。 \begin{itemize} \item {\ttfamily public static MulticastDataSegmentManager \\ connectMulticast(String connectionKey ,String MCSTADDR, int port, String nis, SocketType type)} \end{itemize} DataSegment classのstaticメソッドである、connectMulticastを呼ぶことでMulticast DSMが作成される。 第1引数はMulticast DSMへのアクセスするためのkeyを指定できる。第2引数はマルチキャストアドレスを、第3引数はポート番号を、第4引数はネットワークインターフェイスを指定する。第5引数はSocketTypeを指定する。 SocketTypeには、{\tt Sender}と{\tt Receiver}と{\tt Both}が存在する。{\tt Sender}を指定した場合は、第2引数で指定したマルチキャストアドレスに対して送信処理を行うスレッドを作成する。{\tt Receiver}を指定した場合は、第2引数で指定したマルチキャストアドレスに対して送信されたデータを受信するスレッドを作成する。{\tt Both}は、送受信両方のスレッドを作成する。 現在、Multicast Data Segmentは自動では作成されないため、ユーザー自身で作成する必要がある。 ソースコード \ref {src:MulticastStartCodeSegment}と\ref {src:MulticastIncrement}は実際にMulticast Data Segmentを利用した例題である。例題の内容はmulticast Data Segmentに対してtakeを行い、取得したデータをインクリメントして再びputを行うものである。 Multicast DSMを作成する際のSocketTypeの引数はBothであるため、ReceiverとSender両方作成される。そのため、"multicast"というkeyに対してputを行うと、自分自身に対してもData Segmentがputされる。takeもまた同様に自分自身に対してもtakeが要求され、要求に対してreplyを返すことになる。 \begin{table}[htbp] \lstinputlisting[label=src:MulticastStartCodeSegment, caption=multicast DSMの作成例]{source/MulticastStartCodeSegment.java} \end{table} \begin{table}[htbp] \lstinputlisting[label=src:MulticastIncrement, caption=multicast Data Segmentの使用例]{source/MulticastIncrement.java} \end{table}