annotate paper/chapter4.tex @ 14:b9b3f2241ab4

modify chapter2
author sugi
date Tue, 13 Jan 2015 17:10:56 +0900
parents ddab34e04068
children fd43827452ad
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
295b393a7134 first commit
sugi
parents:
diff changeset
1 \chapter{改善点} \label{chapter:chapter4}
7
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
2 %この章では、分散フレームワークAliceに対して行った改善点を示す。
10
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
3
12
ddab34e04068 add pdf and modify chapter2
sugi
parents: 10
diff changeset
4 \section{並列環境における改善} \label{section:conçurrent}
8
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
5 分散フレームワークAliceは、並列環境にも対応したフレームワークである。しかし、並列環境に対応していることを確認するためにbitonic sortを作成、計測したところ、Data Segmentの更新のオーバーヘッドにより、期待した効果を得ることができなかった。その際に、行った改善点を示す。
7
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
6 \subsection{SEDA Architecture}
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
7 SEDA Architectureとはマルチコアスレッドを用いて大量の接続を管理し、受け取ったデータを処理ごとに分けられたステージと呼ばれるスレッドに投げ、処理が終わると次のステージにデータを伝搬させていく処理方式である。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
8 スループット重視のでありレスポンスは多段のパイプラインのせいで遅れてしまう。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
9 Aliceに置いてSEDAを実装するにあたり、データを次のステージにへ伝搬する際、LinkedBlockingQueueを使用している。LinkedBlockingQueueは片方向の連結リストをベースとしたQueue実装である。enqueue / dequeueの操作時の排他制御にはそれぞれ別々のロックオブジェクトが使用されている。そのため、enqueueとdequeueが重なってもロック解除待ちは発生しないが、そのかわりに連結リストのNodeオブジェクトの生成操作などが発生してしまうため、enqueue操作の処理コストが高い。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
10 さらに、非力なマシーンではSEDAの効果を得られず、スレッドを切り替えが頻繁に起こりオーバーヘッドになってしまう。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
11
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
12 以上の理由からLocal Data Segmentに対して操作をする際はSEDAを使用せず処理を行なうように変更した。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
13 変更前は、Local Data Segmentに対して操作する場合、putやpeekに沿ったCommandを作成するステージ(Code Segmentが実行されているスレッド)、受け取ったCommandを処理するステージ、Code SegmentにData Segmentをセットするステージ(peekとtakeの場合)の2段または3段のパイプラインで構成されていた。これらを1つのステージにまとめて処理することで、並列環境における性能を向上させた。
8
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
14
7
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
15 \subsection{Data Segment の再構成(flip 機能の追加)}
8
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
16 Data Segment APIのput、updateを呼ぶとOutput Data Segmentが毎回新しく作成される。そして出力するデータのコピーが行われる。しかし、Input Data Segmentとして取得したデータに変更を行い、Output Data Segmentとして出力する場合、コピーを行なうのは無駄である。そこで、このコピーを減らすことで速度改善を行った。
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
17
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
18 このコピーを無くし、Data Segmentの更新におけるオーバーヘッドを減らす方法としてCeriumでも良好な結果を得ているflipを用いた。Ceriumにおけるflipは、Input Data SegmentとOutput Data SegmentをswapさせるAPIである。(ソースコード \ref{src:flipCerium})
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
19
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
20 \begin{table}[html]
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
21 \lstinputlisting[label=src:flipCerium, caption=Ceriumにおけるflip]{source/flip.cc}
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
22 \end{table}
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
23
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
24
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
25 \begin{table}[html]
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
26 \lstinputlisting[label=src:flipAlice, caption=Aliceにおけるflip]{source/flip.java}
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
27 \end{table}
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
28
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
29 \begin{table}[html]
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
30 \lstinputlisting[label=src:exampleFlip,caption=flipの使用例]{source/Sort.java}
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
31 \end{table}
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
32
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
33 Ceriumの場合、Output Data SegmentはTaskが実行された段階ですでに用意されている。そのためデータをOutput Data Segmentに書き込む前にflipを呼ぶ。
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
34 Aliceの場合、putまたはupdateを呼んだ段階でOutput Data Segmentが作られるため、ソースコード\ref{src:exampleFlip}のようにInput Data SegmentであるReceiverをflipメソッドに引数として渡すことで、無駄なコピーを減らす。
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
35
7
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
36 \subsection{Data Segmentのデータ表現の追加}
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
37 変更前はData Segmentのデータ表現はMessage Pack for JaveのValueオブジェクトのみを用いて表現していた。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
38 Valueオブジェクトとは、Message Packのバイナリにシリアライズできる型のみで構成されたJavaのオブジェクトであり、自己記述形式のデータ形式となっている。そのため、ArrayValueを用いることにより、ユーザーはデータを後からつなげたりすることも可能である。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
39
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
40 このValueオブジェクトの特徴の1つに、通信に関わる際のシリアライズ・デシリアライズを高速に行えることがある。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
41 この特徴を用いて、Remote Data Segmentに対する通信の高速化を狙っていた。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
42
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
43 しかし、Local Data Segmentに対する通信においては逆効果である。データをLocal Data Segmentに対してputするたびにValue型に変換するコストがかかる。データをpeekする際にもValue型から元の型に変換するというコストがかかる。
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
44
a9a8f37945d4 modify chapter4
sugi
parents: 0
diff changeset
45 この問題を解決するために、一般的なJavaのクラスオブジェクトでもデータ表現を可能にした。Local Data Segmentに対してputする場合は、Valueオブジェクトに変換せず一般的なJavaのクラスオブジェクトのままで、Remote Data Segmentに対してputする場合にのみValueに変換する。これにより、無駄な変換コストを抑えられるようになった。
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
46
12
ddab34e04068 add pdf and modify chapter2
sugi
parents: 10
diff changeset
47 \section{分散環境における改善} \label{section:distribute}
10
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
48 AliceVNCを実装するにあたり、Aliceの送受信部分に問題が発見された。ここでは発見された問題とその解決方法を示す。
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
49
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
50 \subsection{Data Segmentのデータ表現の変更} \label {subsection:changeDSFormat}
8
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
51 AliceVNCは、\ref {section:AliceVNC}で説明したように、当研究室で開発しているTreeVNCを分散フレームワークAliceを用いて実装した画面共有システムである。
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
52
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
53 Topology Nodeは受け取った画面データを描画すると同時に、Remote Data Segmentに送信する。Remote Data Segmentに送信する際にはMessage PackによりValue型に変換し、その後シリアライズ化(byteArrayで表現されたバイナリに変換)される。Topology Nodeは受信するとデシリアライズしValue型に変換した後putされる。
f948d683c29a modify chapter4 and add source
sugi
parents: 7
diff changeset
54
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
55 このValue型への変換が問題である。受け取ったデータを自分の子ノードに対して送信する際には、デシリアライズしValue型に変換する必要はない。シリアライズ状態のまま子ノードに送信すれば、Value型に変換するオーバーヘッドとValue型をシリアライズするオーバーヘッドを無くすことができる。そこで、Remoteからputされたデータ表現をValue型からbyteArrayで表現されたbinaryに変更した。また、Remoteにputする際にもValue型に変換せずに直接byteArrayに変換するように変換した。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
56
10
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
57 %オーバーヘッドの図を挿入予定
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
58
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
59 しかし、この変更で新しい問題が発生した。Remoteからputされたデータは必ずbyteArrayで表現される。しかし、putされたbyteArrayが全てシリアライズ化された状態であるとはいえない。一般的なJavaのクラスオブジェクトとしてbyteArrayが使用されている場合が存在する。例えば、AliceVNCで使われる画像データはbyteArrayで表現されているが、これはLocalからputされている。 Input Data Segmentが格納されるReceiverクラスには{\tt asClass()}というメソッドがある。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
60
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
61 \begin{itemize}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
62 \item \verb+public <T> T asClass(Class<T> clazz)+
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
63 \end{itemize}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
64
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
65 このメソッドは取得したデータがRemoteからputされた場合、Value型でなっているためMessage Packを使い適切な型に変換するものである。しかし、byteArray型に変更したため、変換可否を判断することができなくなってしまった。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
66
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
67 ここからわかることは、データを表現するにはデータ単体をやりとりするだけでは不十分ということである。変更以前はValue型であるということが状態を表していた。しかし、一般的なJavaのクラスオブジェクトとbyteArrayで表現されたbinaryが混在する現在では、データと一緒にデータの状態を表すメタデータもやりとりする必要がある。そこで、データとデータの状態を1つのオブジェクトにまとめ扱うように変更した。(ソースコード\ref {src:ReceiveData})
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
68
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
69 \begin{table}[html]
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
70 \lstinputlisting[label=src:ReceiveData, caption=データを表現するクラス]{source/ReceiveData.java}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
71 \end{table}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
72
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
73 {\tt val}がデータ本体が保存格納される。{\tt serialized}と{\tt byteArray}がデータの状態を表すメタデータである。{\tt serialized}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
74 は、データ本体がシリアライズ化されているかを示す。{\tt byteArray}がデータ本体がbyteArrayであるかを示す。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
75 この2つの状態があることで{\tt asClass()}を使い、適切に変換することができる。(ソースコード\ref {src:asClass})
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
76
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
77 \begin{table}[html]
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
78 \lstinputlisting[label=src:asClass, caption=asClassの処理]{source/asClass.java}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
79 \end{table}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
80
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
81 asClassが行う処理は、Localからputされたデータ({\tt serialized}と{\tt byteArray}がfalseの場合または{\tt byteArray}のみtrueの場合)は、目的のClassにcastする。Remoteからputされたデータ({\tt serialized}がtrueの場合)はMessage Packを使い変換する。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
82
10
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
83 \subsubsection{Message Packの機能追加}
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
84 通信入力部はMessage PackのUnpackerを用いる事により、ストリームを次から次へとデシリアライズすることができる。
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
85 しかし、提供されているAPIは全てデシリアライズを行うものであり、シリアライズ状態のオブジェクトを取得することができない。そこでUnpackerにシリアライズ状態のオブジェクトを取得するメソッドを追加した。
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
86
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
87 \begin{table}[html]
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
88 \lstinputlisting[label=src:Incoming, caption=ByteBuffer作成部分]{source/IncomingTcpConnection.java}
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
89 \end{table}
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
90 ソースコード\ref {src:Incoming} は受け取ったデータをLocal Data Segmentに追加する処理である。
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
91 getSerializedByteArrayメソッドでシリアライズ状態のオブジェクトを取得している。
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
92
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
93 このメソッドの実装をもって、受け取ったデータをデシリアライズせずに、子ノードに渡すことが可能となった。
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
94
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
95 \subsection{パケットの再設計}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
96 Aliceの通信の際には、CommandMessage.classのインスタンスをMessage Packによりシリアライズ化したものが送信される。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
97 つまり、CommandMessage.classがパケットの構造を表すものといえる。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
98
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
99 \begin{table}[html]
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
100 \lstinputlisting[label=src:CommandMessageBefore, caption=変更前のCommandMessage]{source/CommandMessagebefore.java}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
101 \end{table}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
102 ソースコード\ref {src:CommandMessageBefore}が変更前のCommandMessageの内容である。表\ref{tb:variable}はCommandMessageの各変数が何を表しているかを示したものである。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
103 \begin{table}[htbp]
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
104 \caption{CommandMessageの変数名の説明}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
105 \label{tb:variable}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
106 \begin{center}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
107 \begin{tabular} {|l|l|}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
108 \hline
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
109 変数名&説明\\
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
110 \hline
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
111 type&CommandType {\tt PEEK, PUT}などを表す\\
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
112 \hline
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
113 seq&Data Segmentの待ち合わせを行っているCode Segmentを表すunique number\\
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
114 \hline
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
115 key&どのKeyに対して操作を行うか指定する\\
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
116 \hline
10
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
117 val&データ本体\\
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
118 \hline
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
119 quickFlag&SEDAを挟まずCommandを処理を行うかを示す\\
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
120 \hline
10
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
121 serialized&データ本体のシリアライズ状態を示す\\
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
122 \hline
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
123 \end{tabular}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
124 \end{center}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
125 \end{table}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
126
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
127 このパケット構造に問題が存在する。データ本体はCommandMessageがシリアライズ化されるときにはすでに、シリアライズされている。つまり、このままCommandMessageをシリアライズ化を行うと、データ本体をもう1度シリアライズ化を行ってしまう。配列をシリアライズ化する場合、配列のサイズによってはオーバーヘッドが大きいため、2度シリアライズするのを防がなければならない。
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
128
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
129 \begin{table}[html]
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
130 \lstinputlisting[label=src:CommandMessage, caption=変更後のCommandMessage]{source/CommandMessage.java}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
131 \end{table}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
132
10
198cebfd31a3 modify chapter5
sugi
parents: 9
diff changeset
133 そこで、CommandMessageをソースコード\ref{src:CommandMessage}のように変更した。データ本体をCommandMessageのフィールドから外し、後からByteBufferにまとめることにより2度のシリアライズを防ぐ。(ソースコード\ref{src:convert})
9
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
134
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
135 \begin{table}[html]
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
136 \lstinputlisting[label=src:convert, caption=ByteBuffer作成部分]{source/CreateByteBuffer.java}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
137 \end{table}
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
138
7e1112025b3a modify chapter4
sugi
parents: 8
diff changeset
139 この実装ではCommandMessage部をヘッダーとして扱っている。データ部はCommandTypeが{\tt UPDATE、PUT、REPLY}の時のみ後から付加される。以前の実装ではbyte[]の値としてnullを示すNilValueがあるものとしてシリアライズ化されており、これもオーバーヘッドである。現在の実装にでは、CommandTypeが{\tt UPDATE、PUT、REPLY}以外はの時は、データ部をシリアライズ化しないため、nullをシリアライズ化するオーバーヘッドはなくなっている。