comparison paper/appendix1.tex @ 35:ec3488a9ddd4

fix
author Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
date Mon, 03 Feb 2014 17:24:15 +0900
parents
children e32c9a53310c
comparison
equal deleted inserted replaced
34:345eacdf29e4 35:ec3488a9ddd4
1 \clearpage
2 \addcontentsline{toc}{chapter}{付録}
3 \appendix
4 \def\thesection{付録\Alph{section}}
5 \section{計測環境の構築}
6 ウェブアプリケーションのベンチマークを行う際、サーバの設定に注意を払う必要がある。
7 適切に設定を行わないと、サーバがボトルネックとなってしまい正しい結果が得られない。
8 ウェブアプリケーションのベンチマークを行う際の注意点について述べる。
9
10 データを受信したり送信したりするのは OS カーネルである。
11 多くの TCP パケットを要求し、各パケットのサイズが1500バイトといった大きなファイルを提供する場合、
12 ウェブアプリケーションというよりOSカーネルのテストになってしまう。
13
14 接続には、HTTP Keep-Alivesを利用する。
15 新しい TCP 接続を確立するのはとても遅く、OS カーネルによって行われる。
16 毎秒多くの新しい接続を作成するようなベンチマークを行うと、OSカーネルのテストとなってしまう。
17
18 アプリケーションやOSカーネルが完全にハードウェアを使用できるようにするためにいくつか調整を行う必要がある。
19 最初の問題は、ファイル記述子の欠如である。
20 デフォルトはプロセスあたり、1,024 files で非常に貧弱な結果しか得られない。
21 ファイル記述子の現在のリミットは以下のコマンドで取得できる。
22
23 \begin{lstlisting}[caption=ファイル記述子のリミットの取得]
24 $ ulimit -aH
25 \end{lstlisting}
26
27 リミットを変更するには、以下のコマンドを実行する。
28
29 \begin{lstlisting}[caption=ファイル記述子のリミットの設定]
30 $ sudo sh -c ulimit -HSn 200000
31 \end{lstlisting}
32
33 再起動後も有効にするためには、システムファイルの編集を行う。
34
35 /etc/security/limits.conf へ以下の記述を追加する。
36
37 \begin{lstlisting}[caption=リミットの設定の追加]
38 * soft nofile 200000
39 * hard nofile 200000
40 \end{lstlisting}
41
42 次に問題となるのは listenキューの制限である。
43 listen キューとは、保留中のコネクションが繋がれるキューのことである。
44 このキューの長さの制限が小さいと、同時にたくさんのコネクション要求がきた場合、制限を超えた要求を拒否する。
45 listen キューや、その他の設定も含めてベンチマーク用にサーバの設定を変更する。
46
47 /etc/sysctl.conf に以下の記述を追加する。
48
49 \begin{lstlisting}[caption=システム設定の変更]
50 fs.file-max = 5000000
51 net.core.netdev_max_backlog = 400000
52 net.core.optmem_max = 10000000
53 net.core.rmem_default = 10000000
54 net.core.rmem_max = 10000000
55 net.core.somaxconn = 100000
56 net.core.wmem_default = 10000000
57 net.core.wmem_max = 10000000
58 net.ipv4.conf.all.rp_filter = 1
59 net.ipv4.conf.default.rp_filter = 1
60 net.ipv4.ip_local_port_range = 1024 65535
61 net.ipv4.tcp_congestion_control = bic
62 net.ipv4.tcp_ecn = 0
63 net.ipv4.tcp_max_syn_backlog = 12000
64 net.ipv4.tcp_max_tw_buckets = 2000000
65 net.ipv4.tcp_mem = 30000000 30000000 30000000
66 net.ipv4.tcp_rmem = 30000000 30000000 30000000
67 net.ipv4.tcp_sack = 1
68 net.ipv4.tcp_syncookies = 0
69 net.ipv4.tcp_timestamps = 1
70 net.ipv4.tcp_wmem = 30000000 30000000 30000000
71 net.ipv4.tcp_tw_reuse = 1
72 net.ipv4.tcp_tw_recycle = 1
73 \end{lstlisting}
74
75 ファイルを保存後、設定を反映させるには以下のコマンドを実行する。
76
77 \begin{lstlisting}[caption=設定の反映]
78 $ sudo sysctl -p /etc/sysctl.conf
79 \end{lstlisting}
80
81 ベンチマークを行う際、小さなテストでは妥当性が低くなってしまうので注意する。
82 TCP/IPのスタックは保守的な方法で動作し、ダウンロード速度に合わせて徐々に速度を増大させるためである。
83
84 また、テストするサーバより遅いベンチマーククライアントを用いると正しい結果は得られない。
85 シングルスレッドで稼働したり、Ruby や Python といった低速なベンチマークツールでテストを行うと、
86 すべてのテストする対象が同じようなパフォーマンスを持っているように見えてしまう。
87
88 \subsubsection{weighttp}
89 ウェブアプリケーションの性能測定には、weighttpを用いる。
90 weighttpはWebサーバの性能測定ツールで、マルチコアCPUを使ってテストできる\cite{weighttp}。
91 また、livev を使うことで、モダンなポール・システムコールを利用し、測定性能を向上できるといった特徴を持つ。
92 同様の性能測定ツールには、Apache Benchやhttprefが存在するが非力であり、ボトルネックとなってしまうため使用しない。
93
94 weighttp を起動するには、以下の様にコマンドを入力する。
95 \begin{lstlisting}[caption=weighttpの起動]
96 $ weighttp -n 1000000 -c 1000 -t 10 -k "http://bldsv12.cr.ie.u-ryukyu.ac.jp:3000"
97 \end{lstlisting}
98
99 起動時には対象のサーバの URL を記述する他に、いくつかのオプションを指定できる。
100 \begin{itemize}
101 \item n ... HTTP リクエストの総数
102 \item c ... 同時に接続するコネクションの数
103 \item t ... 作製するネイティブスレッドの数
104 \item k ... HTTP Keep-Alives を有効にする
105 \end{itemize}
106
107 \clearpage
108
109 \section{Warp を用いたウェブアプリケーションの構築}
110 Warp は、軽量・高速な HTTP サーバである\cite{warp}。
111 Haskell の軽量スレッドを活かして書かれている。
112 Haskell のウェブフレームワークである Yesod のバックエンドとして用いられており、現在も開発が続けられている。
113
114 Warp を用いてウェブアプリケーションを構築する方法について説明する。
115
116 % Source Codeは実行可能な状態でsrcに置いてある
117 % firstline, lastlineで、どの範囲を表示するか指定できる
118 \lstinputlisting[label=warp_sample, caption=Warpを用いたウェブアプリケーションの例, firstline=9]{src/warp.hs}
119
120 ソースコード \ref{warp_sample}は、URLによって出力する結果を変更するウェブアプリケーションである。
121 /hello/worldへアクセスがあった場合は、インクリメントされる counter が表示される。
122
123 \paragraph*{main}
124 HTTP サーバを起動するには、Warp の run 関数を利用する。
125 run 関数は、利用する Port 番号と、application というリクエストを受けて何かしらのレスポンスを返す関数の2つを引数として受け取る。
126
127 関数型言語では、関数を第一級オブジェクトとして扱える。
128 また、今回は Haskell のカリー化された関数の特性を利用し、main 内で作成した IORef 型の counter を部分適用させている。
129
130 IORef を用いることで、Haskell で更新可能な変数を扱うことができる。
131 参照透過性を失うようにみえるが、Haskell は IO モナドを利用することで純粋性を保っている。
132 IORef 自体が入出力を行うわけではなく、単なる入出力操作の指示にすぎない。
133 IO モナドとして糊付けされた単一のアクションに main という名前を付けて実行することで処理系が入出力処理を行う。
134
135 \paragraph*{application 及び routes , findRoute}
136 application の実装では、routes という関数を独自に定義して、URL によって出力を変更している。
137 application に渡されるリクエストはデータ型で様々な情報が含まれている。
138 その中のひとつに pathInfo という、URL から hostname/port と、クエリを取り除いたリストがある。
139 この情報を routes という関数に渡すことで、routeSetting というリストから一致する URL がないか調べる。
140 routeSetting は、URL のリストとレスポンスを返す関数のタプルのリストである。
141
142 \paragraph*{notFound 及び hello}
143 レスポンスを返す関数は、いくつか定義されている。
144 その中で利用されている responseLBS は文字列からレスポンスを構築するためのコンストラクタである。
145
146 \paragraph*{world 及び incCount}
147 world は、インクリメントされる counter を表示するための関数である。
148 IORef 内のデータは直接触ることができないため、incCount 内で atomicModifyIORef を利用してデータの更新を行なっている。
149 atomicModifyIORef は、データの更新をスレッドセーフに行うことができる。
150 また、responseLBSで構築したレスポンスは、Resource Tというリーソスの解放を安全に行うために使われるモナドに包まれている。
151 lift 関数を用いて、incCountの型を持ち上げ調整している。
152
153
154 プログラムを例にして説明したが、Warp は容易にプログラムに組み込むことができる。
155 本研究では、非破壊的木構造データベース Jungle と Warp を組み合わせて、掲示板ウェブアプリケーションを開発した。