view slides/master.html @ 43:aa6de0f67a0a

add files
author Daichi TOMA <toma@cr.ie.u-ryukyu.ac.jp>
date Tue, 04 Feb 2014 09:38:20 +0900
parents 705c29dd2f6d
children fcf49a1241af
line wrap: on
line source

<!DOCTYPE html>

<!--
  Google HTML5 slide template

  Authors: Luke Mahé (code)
           Marcin Wichary (code and design)
           
           Dominic Mazzoni (browser compatibility)
           Charles Chen (ChromeVox support)

  URL: http://code.google.com/p/html5slides/
-->

<html>
	<head>
		<title>
      関数型言語 Haskell による並列データベースの実装
    </title>

		<meta charset='utf-8'>
		<script
			src='http://web.amothic.com/html5slides/slides.js'></script>
	</head>

	<style>
		/* Your individual styles here, or just use inline styles if that’s
		what you want. */


	</style>

	<body style='display: none'>

		<section class='slides layout-regular template-concurrency'>

			<!-- Your slides (<article>s) go here. Delete or comment out the
				slides below. -->

			<article>
				<h1>
					関数型言語 Haskell による並列データベースの実装
				</h1>
				<p>
					Daichi TOMA
					<br>
					Feb 4, 2014
				</p>
			</article>

			<article>
				<h3>
          研究概要
				</h3>
        <p>
        Haskell を用いて並列データベースを実装した。
        </p>
        <p>
        読み込みに関して 12 コアで実行した場合、10.77 倍 という性能向上率が確認できた。
        </p>
        <p>
        また、Web 掲示板サービスを開発し、Java より読み込みで 1.87 倍、書き込みで 2.3倍の性能が確認できた。
        </p>
			</article>
			<article>
				<h3>
          研究背景
				</h3>
        <p>
        Web サービスの脆弱性を悪用されると多大な被害がでる
        </p>
        <p>
        Haskell は型検査でバッファオーバーフローや、クロスサイトスクリプティング、SQL インジェクションを防げる
        </p>
        <p>
        Haskell を用いてデータベースと Web サービスの開発を行う
        </p>
			</article>

			<article>
				<h3>
          Haskell
				</h3>
        <p>
        Haskellは純粋関数型プログラミング言語
        </p>
        <p>
        純粋とは、引数が同じならば関数が必ず同じ値を返す
        </p>

<pre>
fib :: Int −&gt; Int
fib 0 = 0
fib 1 = 1
fib n = fib (n-2) + fib (n-1)
</pre>
			</article>

			<article>
				<h3>
          実行時型エラーがない
				</h3>
        <p>
        Haskellは、評価の際に型に起因するエラーが起きない
        </p>
        <p>
        [1,2,3]のリストに文字'a'を追加することはできない
        </p>
        <p>
        コンパイル時にエラーになる
        </p>
<pre>
abc = 'a' : [1,2,3]
</pre>

<pre>
-- リスト型の定義
data [] a = [] | a : [a]
</pre>
			</article>

			<article>
				<h3>
          型推論
				</h3>
        <p>
        Haskell が型を推論してくれる
        </p>
<pre>
getChildren node path = elems (children (getNode node path))
</pre>
        <p>
        </p>
<pre>
*Jungle&gt; :type getChildren
getChildren :: Node -&gt; Path -&gt; [Node]
</pre>
			</article>

			<article>
				<h3>
          モナド
				</h3>
        <p>
        文脈を保ったまま関数を繋いでいくことができる
        </p>
<pre>
data Maybe a = Nothing | Just a
</pre>
<pre>
instance Monad Maybe where
    return x = Just x
    Nothing &gt;&gt;= f = Nothing
    Just x &gt;&gt;= f  = f x
</pre>
<pre>
up 4 = Nothing
up n = Just (n + 1)

down 0 = Nothing 
down n = Just (n - 1)
</pre>
<pre>
return 3 &gt;&gt;= down &gt;&gt;= down &gt;&gt;= up &gt;&gt;= up
</pre>
			</article>

			<article>
				<h3>
          モナドを使わないで同じことをする
				</h3>
<pre>
return 3 &gt;&gt;= down &gt;&gt;= down &gt;&gt;= up &gt;&gt;= up
</pre>
<pre>
updown :: Maybe Int
updown = case down 3 of
            Nothing -&gt; Nothing
            Just place1 -&gt; case down place1 of
                    Nothing -&gt; Nothing
                    Just place2 -&gt; case up place2 of
                            Nothing -&gt; Nothing
                            Just place3 -&gt; up place3
</pre>
			</article>


			<article>
				<h3>
          マルチコアプロセッサ
				</h3>
        <p>
        現在、CPU はマルチコア化が進んでいる。
        </p>
        <p>
        マルチコアプロセッサで線形に性能向上をするためには、処理全体で高い並列度を保つ必要性(アムダール則)
        </p>
        <p>
        並列度が 80 % の場合、どんなにコア数を増やしても性能向上は5倍まで
        </p>
			</article>

			<article>
				<h3>
          並列データベース
				</h3>
        <p>
        データベースを線形に性能向上させたければ、各コアからデータに同時にアクセスできるようにし並列度を高める
        </p>
        <p>
        非破壊的木構造という手法を使う
        </p>
			</article>

			<article>
				<h3>
          非破壊的木構造
				</h3>
        <p>
        元となる木構造を書き換えずに編集できる
        </p>
        </p>
        既にあるデータを変更しないので、データの競合状態が発生しない。並列に読み書きできる
        </p>
        <div align="center">
          <img src="images/nondestructive_tree.png" width="600px">
        </div>
			</article>

			<article>
				<h3>
          非破壊的木構造 - ルートノード
				</h3>
        <p>
        どの木構造が最新なのかを表す情報
        </p>
        <p>
        状態を持つのはここだけで、並列度を高めるにはここの設計が重要
        </p>
        <div align="center">
          <img src="images/rootnode.png" width="400px">
        </div>
			</article>

			<article>
				<h3>
          データベースの設計 - 並列度を高めるために
				</h3>
        <p>
        できるだけルートノードに触る範囲を狭くする
        </p>
        <p>
        ルートノードが必要ない時はさわらない
        </p>
        <p>
        ルートノードを更新する関数と、編集する関数を綺麗に切り分ける
        </p>
			</article>

			<article>
				<h3>
          Haskell でのルートノードの管理
				</h3>
        <p>
        ソフトウェア・トランザクショナル・メモリ (STM) を使う
        </p>
        <p>
        STM は、排他制御を行わずに共有データを扱える
        </p>
        <p>
        STM は、他のスレッドによる変更を考慮せずに共有データを変更する
        </p>
        <p>
        変更をトランザクションとしてコミットする時に以下のことがひとつだけ起こる
        </p>
        <ul>
          <li>同じデータを平行して変更したスレッドが他になければ、加えた変更が他のスレッドから見えるようになる
          <li>そうでなければ、変更を実際に実行せずに破棄し、変更の処理を再度実行する。
        </ul>
        </p>
			</article>

			<article>
				<h3>
          Jungle のデータ型
				</h3>
        <p>
        Jungle は、非破壊的木構造を扱う並列データベース
        </p>
<pre>
-- Jungle のデータ型
data Jungle = Jungle (TVar (Map String Tree))

-- Tree のデータ型
data Tree = Tree (TVar Node) String

-- Node のデータ型
data Node = Node (Map Int Node) (Map String ByteString)
</pre>
        <p>
        TVarがついてるのはSTMを使ってる変数
        </p>
        <p>
        Map は連想配列
        </p>
			</article>

			<article>
				<h3>
          Jungle の実装
				</h3>
        <p>
        Jungle は Tree と String の連想配列を持っている(状態変数)
        </p>
        <p>
        Tree は、ルートノードの情報と、木の名前(ルートノードの情報は状態変数)
        </p>
        <p>
        Node は、子と子の場所の連想配列と、キーと値の連想配列を持ってる。
        </p>

        <br><br>
        <div align="center">
          <img src="images/get_root_node.png" width="500px">
        </div>
			</article>

			<article>
				<h3>
          状態を扱う関数
				</h3>
<pre>
createJungle :: IO Jungle
createTree :: Jungle -&gt; String -&gt; IO ()
getRootNode :: Jungle -&gt; String -&gt; IO Node
updateRootNode :: Jungle -&gt; String -&gt; Node -&gt; IO ()
updateRootNodeWith :: (Node -&gt; Node) -&gt; Jungle -&gt; String -&gt; IO ()
</pre>
        <p>
        すべて IO が返ってくる
        後回しで性能計測からまとめる
        </p>
			</article>


			<article>
				<h3>
          性能計測
				</h3>
        <p>
        Jungle がマルチコアプロセッサで性能が出るのか、実用的なWebサービスが提供できるのか確認する
        </p>
        <p>
        性能の計測に用いるサーバの仕様<br>
        ハイパースレッディングで24コアまで使える
        </p>
        <table>
          <tr>
            <th>名前</th>
            <th>概要</th>
          </tr>
          <tr>
            <td>CPU</td>
            <td>Intel(R) Xeon(R) CPU X5650@2.67GHz * 2</td>
          </tr>
          <tr>
            <td>コア数</td>
            <td>12</td>
          </tr>
          <tr>
            <td>メインメモリ</td>
            <td>126 GB</td>
          </tr>
          <tr>
            <td>OS</td>
            <td>Fedora 14</td>
          </tr>
        </table>
			</article>

			<article class="smaller">
				<h3>
          性能計測 - 読み込みの計測結果
				</h3>
        <p>
        木構造の読み込みにかかる時間を計測する
        </p>
        <p>
        12 スレッドで実行時に 10.77 倍の性能向上
        </p>
        <p>
        ハイパースレッディングは遅くなったりと安定しない
        </p>
        <table>
          <tr>
            <th>CPU数</th>
            <th>実行時間</th>
          </tr>
          <tr>
            <td>1</td>
            <td>59.77 s</td>
          </tr>
          <tr>
            <td>2</td>
            <td>33.36 s</td>
          </tr>
          <tr>
            <td>4</td>
            <td>15.63 s</td>
          </tr>
          <tr>
            <td>8</td>
            <td>8.10 s</td>
          </tr>
          <tr>
            <td>12</td>
            <td>5.55 s</td>
          </tr>
          <tr>
            <td>16</td>
            <td>5.65 s</td>
          </tr>
          <tr>
            <td>20</td>
            <td>5.23 s</td>
          </tr>
          <tr>
            <td>24</td>
            <td>5.77 s</td>
          </tr>
        </table>
        </p>
			</article>

			<article>
				<h3>
          性能計測 - 読み込みの計測結果
				</h3>
        <p>
        12 スレッドまでの性能向上率
        </p>
        <div align="center">
          <img src="images/read.png" width="700px">
        </div>
			</article>

			<article class="smaller">
				<h3>
          性能計測 - 書き込みの計測結果
				</h3>
        <p>
        木構造の書き込みにかかる時間を計測する
        </p>
        <p>
        2 スレッドで 1.55 倍の性能向上<br>
        12 スレッドで実行時に 3.86 倍の性能向上
        </p>
        <p>
        ハイパースレッディングは12スレッド以降遅くなっている
        </p>
        <table>
          <tr>
            <th>CPU数</th>
            <th>実行時間</th>
          </tr>
          <tr>
            <td>1</td>
            <td>52.68 s</td>
          </tr>
          <tr>
            <td>2</td>
            <td>33.92 s</td>
          </tr>
          <tr>
            <td>4</td>
            <td>20.11 s</td>
          </tr>
          <tr>
            <td>8</td>
            <td>15.31 s</td>
          </tr>
          <tr>
            <td>12</td>
            <td>13.62 s</td>
          </tr>
          <tr>
            <td>16</td>
            <td>14.92 s</td>
          </tr>
          <tr>
            <td>20</td>
            <td>18.62 s</td>
          </tr>
          <tr>
            <td>24</td>
            <td>16.63 s</td>
          </tr>
        </table>
        </p>
			</article>

			<article>
				<h3>
          性能計測 - 書き込みの計測結果
				</h3>
        <p>
        12 スレッドまでの性能向上率
        </p>
        <div align="center">
          <img src="images/write.png" width="700px">
        </div>
			</article>

			<article>
				<h3>
          性能計測 - 読み込みと書き込みの考察
				</h3>
        <p>
        読み込みと比べて書き込みの性能向上率が低い
        </p>
        <p>
        木を登録する際、他のスレッドから登録があった場合、ソフトウェア・トランザクショナル・メモリが処理をやり直すため遅いと考えられる。
        </p>
        <p>
        書き込みより読み込みが多用されるシステムに向いている。
        </p>
			</article>

			<article>
				<h3>
          性能計測 - Webサービスに組み込んでの性能評価
				</h3>
        <p>
        Haskell の HTTP サーバ Warp と組み合わせて Web掲示板サービスを開発する。
        </p>
        <p>
         weighttpを用いて掲示板に読み込みと書き込みで負荷をかける。リクエストの総数は100万
        </p>
        <p>
        Warp は、ハイパースレッディングで明らかに遅くなるので、12コアまでの計測とする。
        </p>
			</article>

			<article>
				<h3>
          性能計測 - Webサービスに組み込んでの性能評価 読み込み
				</h3>
        <p>
        読み込み
        </p>
        <p>
        12 スレッド時に 2.14 倍
        </p>
        <p>
        性能向上率が低い
        </p>
        <table>
          <tr>
            <th>CPU数</th>
            <th>実行時間</th>
          </tr>
          <tr>
            <td>1</td>
            <td>60.72 s</td>
          </tr>
          <tr>
            <td>2</td>
            <td>37.74 s</td>
          </tr>
          <tr>
            <td>4</td>
            <td>28.97 s</td>
          </tr>
          <tr>
            <td>8</td>
            <td>27.73 s</td>
          </tr>
          <tr>
            <td>12</td>
            <td>28.33 s</td>
          </tr>
        </table>
			</article>

			<article>
				<h3>
          性能計測 - Webサービスに組み込んでの性能評価 書き込み
				</h3>
        <p>
        書き込み
        </p>
        <p>
        12 スレッド時に 1.65 倍
        </p>
        <p>
        読み込みよりさらに悪い
        </p>
        <table>
          <tr>
            <th>CPU数</th>
            <th>実行時間</th>
          </tr>
          <tr>
            <td>1</td>
            <td>54.16 s</td>
          </tr>
          <tr>
            <td>2</td>
            <td>36.71 s</td>
          </tr>
          <tr>
            <td>4</td>
            <td>31.74 s</td>
          </tr>
          <tr>
            <td>8</td>
            <td>31.58 s</td>
          </tr>
          <tr>
            <td>12</td>
            <td>32.68 s</td>
          </tr>
        </table>
			</article>

			<article class="smaller">
				<h3>
          Webサービスに組み込んでの性能評価 考察
				</h3>
        <p>
        Warp がボトルネックとなってしまっている。
        Warp は現状あまり並列化効果がでていない。
        </p>
        <p>
        アクセスした際に、"hello, world" という文字列を返すだけのプログラムを作成し計測する。
        </p>
        <p>
        Jungle を組み込んだ時と比較して、読み込みの場合はほとんど差がない。
        </p>
        <table>
          <tr>
            <th>CPU数</th>
            <th>実行時間</th>
          </tr>
          <tr>
            <td>1</td>
            <td>49.28 s</td>
          </tr>
          <tr>
            <td>2</td>
            <td>35.45 s</td>
          </tr>
          <tr>
            <td>4</td>
            <td>25.70 s</td>
          </tr>
          <tr>
            <td>8</td>
            <td>27.90 s</td>
          </tr>
          <tr>
            <td>12</td>
            <td>29.23 s</td>
          </tr>
        </table>
			</article>

			<article>
				<h3>
          性能計測 - Java との比較
				</h3>

        <table>
          <tr>
            <th>測定</th>
            <th>Haskell</th>
            <th>Java</th>
          </tr>
          <tr>
            <td>読み込み</td>
            <td>28.33 s</td>
            <td>53.13 s</td>
          </tr>
          <tr>
            <td>書き込み</td>
            <td>32.68 s</td>
            <td>76.4 s</td>
          </tr>
        </table>
        <p>
        読み込みで 1.87 倍、書き込みで 2.3 倍の性能差が出ている
        </p>
        <p>
        書き込みが読み込みより性能差が出ている理由として遅延評価が考えられる。
        Haskell では書き込みを行う際、完全に評価せず途中式を積み上げていく。
        </p>
			</article>

			<article>
				<h3>
          まとめ
				</h3>
			</article>


	</body>
</html>