Mercurial > hg > Papers > 2015 > tatsuki-sigos
view slide/slide.html @ 3:082148d6bf7f
change slide
author | tatsuki |
---|---|
date | Tue, 26 May 2015 13:54:37 +0900 |
parents | 0b021791e15c |
children | 84bbcfe22656 |
line wrap: on
line source
<!DOCTYPE html> <html> <head> <meta http-equiv="content-type" content="text/html;charset=utf-8"> <title>非破壊的木構造データベースJungleとその評価</title> <!-- Notes on CSS media types used: 1) projection -> slideshow mode (display one slide at-a-time; hide all others) 2) screen -> outline mode (display all slides-at-once on screen) 3) print -> print (and print preview) Note: toggle between projection/screen (that is, slideshow/outline) mode using t-key Questions, comments? - send them along to the mailinglist/forum online @ http://groups.google.com/group/webslideshow --> <!-- styles --> <style media="screen,projection"> html, body, .presentation { margin: 0; padding: 0; } .slide { display: none; position: absolute; top: 0; left: 0; margin: 0; border: none; padding: 2% 4% 0% 4%; /* css note: order is => top right bottom left */ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box; width: 100%; height: 100%; /* css note: lets use border-box; no need to add padding+border to get to 100% */ overflow-x: hidden; overflow-y: auto; z-index: 2; } .slide.current { display: block; } /* only display current slide in projection mode */ .slide .stepcurrent { color: black; } .slide .step { color: silver; } /* or hide next steps e.g. .step { visibility: hidden; } */ .slide { /* background-image: -webkit-linear-gradient(top, blue, aqua, blue, aqua); background-image: -moz-linear-gradient(top, blue, aqua, blue, aqua); */ } </style> <style media="screen"> .slide { border-top: 1px solid #888; } .slide:first-child { border: none; } </style> <style media="print"> .slide { page-break-inside: avoid; } .slide h1 { page-break-after: avoid; } .slide ul { page-break-inside: avoid; } </style> <!-- add js lib (jquery) --> <script src="js/jquery-1.7.min.js"></script> <!-- S6 JS --> <script src="js/jquery.slideshow.js"></script> <script src="js/jquery.slideshow.counter.js"></script> <script src="js/jquery.slideshow.controls.js"></script> <script> $(document).ready( function() { Slideshow.init(); // Example 2: Start Off in Outline Mode // Slideshow.init( { mode: 'outline' } ); // Example 3: Use Custom Transition // Slideshow.transition = transitionScrollUp; // Slideshow.init(); // Example 4: Start Off in Autoplay Mode with Custom Transition // Slideshow.transition = transitionScrollUp; // Slideshow.init( { mode: 'autoplay' } ); } ); </script> </head> <body> <div class="presentation"> <!-- add slides here; example --> <div id="header"> <font size=5> <h1>非破壊的木構造データベースJungleとその評価</h1> <br><br> <p>琉球大学情報工学科並列信頼研</p> <p>金川竜己</p></font> </div> <div> <h1>知的構造を格納するためのデータベース</h1> <font size=5> <p>我々が扱っている知識は木構造であることが多い。</p> <p>RDBに格納するためには煩雑なデータ設計を行わなければならない</p> <p>データ設計等を行うこと無く木構造を格納できるデータベースが望ましい</p> <p>そこで当研究室では、非破壊的木構造データベースJungleの開発をおこなっている</p> <p>Jungleの表現力、機能の十分性検証、及び性能実証実験を行いたい</p> <p>そのために、Jungle上に組織の許認可管理アプリケーションmaTrixを実装した</p> </font> </div> <div> <h1>組織の中の許認可管理アプリケーションmaTrix</h1> <font size=5> <p>人、組織、役割等の木構造データを保持しており</p> <p>木構造のデータはIdでお互いに参照を行っている</p> <p>許認可の判断はアクセスルールが記述されたポリシーファイルにそって行われる</p> <p>ポリシーファイルは主に、誰が (Target)、何を (Redource)、どうできるか(Action) の3つの要素で記述されている</p> </font> </div> <div> <h1>非破壊的木構造データベースJungle</h1> <font size=5> <p>Jungleは、複数の木の集合からなり、木はノードの集合で出来ている</p> <p>ノードは、自身の子供のリストと、属性名(Key)と属性値(Value)のデータの組を持つ</p> <p>Jungleは、非破壊的木構造であるため、一度作成した木を破壊することはない</p> </font> </div> <div> <h1>Jungleのデータの編集</h1> <font size=5> <p>新しい木構造を作成することでデータの編集を行う</p> <p>変更がないノードは共有する</p> <img src="./images/non_destructive_tree_edit2.png"> <p>木の更新は、ルートノードをCASを用いて入れ替えることで行う</p> <p>データの上書きが無いため、読み込み中にロックをかける必要がない</p> </font> </div> <div> <h1>Jungle上でのmaTrixのデータ構造の表現</h1> <font size=5> <p>Jugnleは木構造のデータをそのまま格納できるため、maTrixのデータを一部を除きそのまま格納できる</p> <p>maTrixの人物TreeをJungleに格納した図の一部を以下に示す</p> <iframe src="images/TreePersonJungle.html" width="1000" height="1000"></iframe> <p></p> </font> </div> <div> <font size=5> <h1>Jungle上でのIdを使った木の相互参照</h1> <p>組織構造は複数の木構造を持ち、お互いのノード参照し合っている</p> <p>ex. 人物と役割は、idを用いてお互いのノードを参照する</p> <iframe src="images/ref.html" width="2000" height="1000"></iframe> </font> </div> <div> <h1>JungleのIndex</h1> <font size=5> <p>Jungleは過去のTreeを全て保持しているため、Treeのversion毎にIndexを持っている必要がある</p> <p>version毎にIndexを作るとメモリを多量使用してしまう</p> <p>過去のIndexとデータを共有するIndexを実装した</p> <p>複数のversionのIndexがあっても、データの差分しかメモリは使用されない</p> </font> </div> <div> <h1>非破壊TreeMapの実装</h1> <font size=5> <p>当初は、FunctionalJavaのTreeMapを使用してIndexの実装を行った</p> <p>FunctionalJavaにはバグがあり、性能が出なかった</p> <p>新しく非破壊TreeMapを実装した</p> <p>TreeMapのアルゴリズムには赤黒木を採用した</p> <p>その結果Jungleの性能は劇的に向上した</p> </font> </div> <div> <h1>木構造の親を取得するIndex</h1> <font size=5> <p>Jungleは子から親への参照は存在しないため、自身の親を返すParentIndexの実装を行った</p> </font> </div> <div> <h1>許認可Queryの実装</h1> <font size=5> <p>maTrixを用いた許認可は、ポリシーファイルを参照し行われる</p> <p>ポリシーファイルには、subject(誰が)、Resource(何に対して)、Action(何が出来るか)を記述する</p> <p>maTrixにおける許認可判断において、データに対するアクセスは、subject部分で検索関数を用いて行う</p> <p>Jungle上にmaTrixを実装するにあって、検索関数の実装を行った</p> </font> </div> <div> <font size=5> <h1>Treeの検索</h1> <p>データアクセス関数を実装するため、Traverserに検索関数findを実装する</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> InterfaceTraverser traverser = tree.getTraverser(boolean useIndex); </div> <p>TraverserはTreeのNodeを走破する機能を持ったクラスです</p> <p>TreeからgetTraverserで取得可能</p> <p>引数で検索を行う際にIndexを使用するかどうかを選択できる</p> </font> </div> <div> <font size=5> <h1>Treeの検索</h1> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> public Iterator<TreeNode> find(Query query,String key, String searchValue); </div> <p>findは以下のように定義されており、引数に</p> <p>探索の条件を記述する関数boolean condition(TreeNode)を定義したQuery</p> <p>Indexを使う検索に使用するString 属性名、String 属性値のペア</p> <p>の3つを取る</p> <p>条件に一致したNodeのIteratorを返す</p> <p>Iteratorは、複数の値から1つずつ順番に取得するためのinterfaceである</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> public interface Query {<br>   boolean condition(TreeNode _node);<br> } </div> </font> </div> <div> <h1>findの使用例</h1> <font size=5> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> InterfaceTraverser personTraverser = personTree.getTraverser(true);<br> Iterator<TreeNode> personIdpairIterator = personTraverser.find((TreeNode node) -> { <br> String personId = node.getAttributes().getString("Person-id");<br> if (personId.equals("p:4"))<br> return true;<br> return false;<br> }, "Person-id", "p:4");<br> <br> if (personIdpairIterator.hasNext())<br> TreeNode node = personIdpairIterator.next(); </div> <ol> <li>Treeから木の探索を行うInterfaceTraverserを取得する</li> <li>findを実行する。引数には、検索条件が記述されたQuery、Person-Id、p:4を与える。(以下Queryの中の解説)</li> <li>nodeから属性名Person-idとペアになっている属性値を取得する</li> <li>返り値がp:4と一致するかどうかを調べる</li> <li>一致した場合trueを一致しなかった場合falseを返す</li> <li>帰ってきたIteratorからNodeを取得する</li> </ol> </font> </div> <div> <h1>maTrix上での許認可判断例(1)</h1> <font size=5> <p>情報工学科の学生にのみ貸し出されるPCをAさんが借りようとした場合の許認可判断</p> <ol> <li>Aさん(Subject)が、学科のノートPC(Resource)の借りる(Action)ために、maTrixに貸出許可を求める</li> <li>maTrixは、PCの貸出許可を与えるかを判断するためのポリシーファイルを参照する</li> <li>maTrixはAさんの役割を取得する</li> <li>Aさんが情報工学科の役割を持っていた場合貸出許可を与える</li> </ol> <p>maTrixは、3番目の処理で役割を取得する関数roleIdsを使用している</p> </font> </div> <div> <h1>役割を取得する関数</h1> <font size=5> <p>roleIdsは、人、組織の役割を取得する関数</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> public Iterator<String> searchPersonRoleIds(String version, String id, LinkedList<String> filterIds) </div> <p>roleIdsは引数に</p> <li>検索を行う組織構造のversion</li> <li>役割を取得したい人 or 組織のId</li> <li>検索対象を絞り込むために使用するフィルター</li> <p>の3つをとり、返り値に役割のIteratorを返します</p> </font> </div> <div> <h1>roleIdsのフィルター</h1> <font size=5> <p>人や組織は、複数の組織に所属することが可能</p> <p>組織に所属する際に役割が与えられる</p> <p>例. 人が大学に所属していると、「学生」や「教授」という役割が与えられる</p> <p>フィルターを使うと組織が与える役割で結果を絞り込める</p> </font> </div> <div> <h1>roleIdsのコード</h1> <font size=5> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> JungleTree personTree = getTree(version, "Person");<br> </div> <p>maTrixは組織構造を版管理している</p> <p>getTree(String Version, String TreeName)は、VersionとTreeNameで指定された木を返す</p> <p>今回はroleIdsの引数で指定されたversionの人物Treeを取得している</p> </font> </div> <div> <h1>roleIdsのコード</h1> <font size=5> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> InterfaceTraverser traverser = personTree.getTraverser(useIndex);<br> Iterator<TreeNode> personNodeIterator = traverser.find((TreeNode node) -> {<br> String nodeId = node.getAttributes().getString("Person-id");<br> if (nodeId.equals(id))<br> return true;<br> return false;<br> }, "Person-id", id);<br> </div> <p>getTreeで取得した木から、getTraverserで木を探索する機能を持ったTraverserを取得する</p> <p>取得したTraverser.findで、属性名 Person-id、属性値 引数で指定されたidのペアを持つノードのIteratorを検索する</p> </font> </div> <div> <h1>roleIdsのコード</h1> <font size=5> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> TreeNode PersonNode = personNodeIterator.next();<br> TreeNode parentOrganizationsNode = PersonNode.getChildren().at(5).b();<br> Iterator<TreeNode> OrganizationMappedByRoleIterator = parentOrganizationsNode.getChildren().iterator();<br> return new Iteratorr<String>() {<br> ………<BR> }; </div> <p>findで取得したノードから、その人が持っている役割を持つノードのIteratorを取得する</p> <p>idを持っているノードの5番目の子供の下に役割のデータが格納されている</p> <p>なので、PersonNode.getChildren().at(5).b();で5番目の子供を取得</p> <p>その下に役割のデータが入ったノードがあるので、子供のiteratorを取得する</p> <p>検索条件にあった役割を返すiteratorを定義する</p> </font> </div> <div> <h1>roleIdsのコード</h1> <font size=5> <p>定義したiteratorのhasNext</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> public boolean hasNext() {<br> if (OrganizationMappedByRoleIterator.hasNext())<br> roleRefId = search();<br> else<br> roleRefId = null;<br> if (roleRefId != null)<br> return true;<br> return false;<br> }<br> </div> <p>取得した役割のIteratorの中身がある場合はsearch()を実行する</p> <p>search()は条件にあった役割を返す</p> <p>中身がない場合はroleRefId = nullを行う</p> <p>roleRefIdがnullの場合、条件にあった役割は無いのでfalseを返し</p> <p>roleRefIdに値がある場合はtrueを返す</p> <p>next()では、roleRefIdの値を返せば良い</p> </font> </div> <div> <h1>roleIdsのコード</h1> <font size=5> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> for (; OrganizationMappedByRoleIterator.hasNext(); ) {<br> TreeNode OrganizationMappedByRole = OrganizationMappedByRoleIterator.next();<br> TreeNode organizationRefIdNode = OrganizationMappedByRole.getChildren().at(0).b();<br> String organizationRefId = organizationRefIdNode.getAttributes().getString("text-organizationRefId");<br> if (!filterIds.contains(organizationRefId) && !filterIds.isEmpty())<br> continue;<br> TreeNode roleRefIdNode = OrganizationMappedByRole.getChildren().at(1).b();<br> return roleRefIdNode.getAttributes().getString("text-roleRefId");<br> }<br> return null; </div> <p>役割のデータが入ったノードのiteratorをfor文で回して役割を取得する</p> <p>iteratorで取得できるノードの0番目の子供には役割を与える組織idが</p> <p>1番目のノードには与えられる役割idを保持している</p> <p>0番目の子供から組織idを取得し検索結果の絞込を行う</p> <p>その後1番目のノードから役割idを返す</p> <p>役割のノードのiteratorが空になったら、nullを返す</p> </font> </div> <div> <font size=5> <h1>木構造の親を辿るQuery</h1> <p>maTrixで許認可を判断する際に、木構造の親を辿る検索が必要になる場合がある</p> <p>以下に親を辿る検索を行う例を記す</p> <ol> <li>Aさんが、maTrixに工学部の学生にのみ貸出を行っている書籍の貸出許可を求める</li> <li>Aさんの所属している組織の情報を取得する(情報工学科)</li> <li>情報工学科の親の情報を取得する(工学部)</li> <li>maTrixは、Aさんに工学部に所属しているため本の貸出を許可する</li> </ol> <p>3番目の処理で親Nodeを返すParentIndexを使用する</p> </font> </div> <div> <h1>親を辿るQueryのコード</h1> <font size=5> <p>以下に親の取得を行う部分のコードを記述する</p> <p>idには工学部のidが、orgNodeにはAさんが所属している組織のidを持ったノードが入っている</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> do {<br> String orgId = orgNode.getAttributes().getString("Organization-id");<br> if (id.equals(orgId))<br> return true;<br> parentOrgNodeOptional = parentIndex.get(orgNode);<br> if (parentOrgNodeOptional.isPresent())<br> orgNode = parentOrgNodeOptional.get();<br> else<br> return false;<br> }while(true);<br> </div> <ol> <li>orgNodeから組織のidを取得する</li> <li>idと取得した組織のidを比較する</li> <li>一致した場合はtrueを、しなかった場合はorgNodeの親を取得する</li> </ol> <p>以上の処理を取得できる親ノードが無くなるまで行う</p> </font> </div> <div> <h1>ベンチマーク</h1> <font size=5> <p>Jungle上にmaTrixの実装を行ったので、性能測定を行った</p> <p>測定はmongoDBとの比較とマルチプロセッサー上でのJungleの読み書き性能の2つを行った</p> <p>木構造をそのまま格納できること、属性名を指定することで属性値が取得できるなど、Jungleと似た特徴を持っているmongoDBを比較対象に選択した</p> </font> </div> <div> <h1>測定環境</h1> <font size=5> <p>今回の測定は以下の環境で行った</p> <li>Mac OS X 10.10.2</li> <li>2*2.66 GHz 6-Core Intel Xeon</li> <li>Memory 16GB 1333MHz DDR3</li> <li>java 1.8.0-45</li> <li>mongoDB 3.0.2</li> <li>javascript V8JavaScriptengine</li> </font> </div> <div> <h1>mongoDBとの比較</h1> <font size=5> <p>1万人のデータをmongoDBとJungleに格納し、データの検索にかかる時間の測定を行った</p> <p>各DBに挿入するデータは以下のような構造を持つ</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> {PersonId: 固有のPersonId ,roleRefIds:ランダムな役割Id}<br> </div> </font> </div> <div> <h1>mongoDBとの比較</h1> <font size=5> <p>mongoDBでのデータの読み込みは以下のように行った</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> var personData = db.person1.find({PersonId:"p:9"}).next();<br> var roleId = personData.roleId<br> </div> <p>dbからpersonIdがp:9のuserを取得する</p> <p>取得したuserのroleIdを取得する</p> </font> </div> <div> <h1>mongoDBとの比較</h1> <font size=5> <p>Jungleのデータの読み込みは以下のように行った</p> <div style="padding: 10px; margin-bottom: 10px; border: 1px solid #333333;"> InterfaceTraverser traverser = tree.getTraverser(true); Iterator<TreeNode> it = traverser.find((TreeNode node) -> {<br> String nodeId = node.getAttributes().getString("Person-id");<br> if (nodeId.equals("p:9"))<br> return true;<br> return false;<br> }, "Person-id", "r:9");<br> if (it.hasNext()) {<br> TreeNode targetNode = it.next();<br> String targetRoleId = targetNode.getAttributes().getString("roleId");<br> }<br> </div><br> <p>TreeからpersonIdがp:9のノードを取得する</p> <p>取得したノードからroleIdを取得する</p> </font> </div> <div> <h1>mongoDBとの比較</h1> <embed src="images/mongoJungleperfomance.svg" width="700" height="700" align="left"/> <font size=5> <br> <p>Jungleの方がmongoDBより高速で動いた理由として、<br>通信の有無が大きい</p> <p>mongoDBはMongoShellからデータベースにアクセスする際に<br>通信を行っている</p> <p>それに対しJungleは、通信を行わないため高速に動作する</p> <p>データへのアクセスもmongoDBは<br>ディスクにあるデータに対しmmapを用いて行う</p> <p>Jungleは初めからメモリにあるデータにアクセスする</p> <p>その部分も差が出た理由の1つである</p> <p>その結果JungleはmongoDBの約500倍の性能が出ている</p> </font> </div> <div> <h1>マルチプロセッサー上でのJungleの読み書き性能</h1> <font size=5> <p>Jungleがマルチプロセッサ上で性能が出るか測定を行った</p> <p>複数スレッドからJungleに読み込みだけを行った場合と、1スレッドだけ書き込みを行い続け、<br>残りのスレッドで読み込み行った場合で測定を行った。</p> <p>読み込みではmaTrixで実際に使われている検索関数isActive(personId , version)を用いた</p> <p>この関数引数で与えた人が、maTrixにアカウントを持っているか調べる関数である</p> </font> </div> <div> <h1>マルチプロセッサー上でのJungleの読み書き性能</h1> <font size=5> <embed src="images/transactionPersecond.svg" width="700" height="700"align="left"/> <br> <p>Jungleでは、書き込みと読み込みを同時に行っても<br>性能低下はおこらなかった</p> <p>ハイパースレッディングに引っかかるまでは<br>リニアに性能が出ている</p> <p>書き込みと読み込みを同時に行った場合、<br>読み込みのCPUCOUNTが2の時だけ性能が出ていない</p> <p>これは、書き込みを連続で行っているため<br>読み込みと書き込みで競合が起きている</p> <p>しかし読み込みのスレッドが増えると<br>読み込みが優先されるので性能が出るようになっている</p> <p>読み込みと書き込み同時に行っている方が<br>CPUCOUNT11で性能上昇が止まっているのは<br>書き込みに1スレッド使用しているからである</p> </font> </div> <div> <h1>考察</h1> <font size=5> <p>性能評価では、JungleのほうがMongoDBより高速に動いたが、全てのアプリケーションでJungleの方が早いわけではない</p> <p>Jungleは、木構造の形と使われ方がアルゴリズム的に一致している場合に性能が出る</p> </font> </div> <div> <h1>Jungleに向いているアプリケーション</h1> <font size=5> <p>Jungleは、書き込み時の処理が木の大きさで変わる</p> <p>そのため、比較的小さな木にデータがたくさんあり、木の深い部分に対し変更があまり行われないアプリケーションが得意</p> <p>また、書き込みより読み込みを重視したDBであるため、読み込みが多いアプリケーションが性能が出る</p> <p>そのため、Jungleの上に構築するアプリケーション例としてBBSやWEBページなどがある</p> </font> </div> <div> <h1>Jungleに不向きなアプリケーション</h1> <font size=5> <p>逆に、1つの大きな木に対し変更が頻繁に行われるようなアプリケーションは向いていない</p> <p>そういった場合、木を分割して複数の小さな木にすることで性能を上げることは可能である</p> <p>しかし、木を分割するための設計手法がまだ無いので、設計手法の確立は今後の課題である</p> </font> </div> <div> <h1>今後の課題</h1> <font size=5> <p>1. RDBとの比較</p> <p> もともとmaTrixはRDB上で動いているアプリケーションなので、RDB版maTrixとの性能測定を行いたい</p> <p>2.データの書き出し部分の改良</p> <p> Jungleはデータをディスクに書き出すことが可能である</p> <p> 書きだしたデータを読み込む機能もあるのでトラブルが発生し、Jungleが強制終了されても元の状態に復旧できる</p> <p> 今の実装は、データの書き出しはcommit時に毎回行っているため書き出しが非効率的である</p> <p> できれば複数回分の変更をバッファリングしておいて一気に書き出しを行いたい</p> <p> ある値を行ったり来たりするような、書き出す必要が無いデータもあるため、書き出す部分の最適化を行う必要がある</p> </font> </div> <div> <h1>今後の課題</h1> <font size=5> <p>3.過去のデータの掃除</p> <p> Jungleは非破壊でデータを保持し続けるため、非常に多くのメモリを消費する</p> <p> ある程度のタイミングで過去のデータをメモリから掃除する必要がある</p> <p> しかし、データを掃除するタイミングは、Jungle上に実装するアプリケーションによって変わる</p> <p> そこを含め、データを掃除するAPIの設計を行う必要がある</p> <p>4.分散環境でのmaTrixの構築</p> <p> Jungleはもともと分散データベースである</p> <p> 分散版Jungle上にmaTrixを構築し、性能測定を行いたい</p> </font> </div> <div> <h1>今後の課題</h1> <font size=5> <p>5.設計手法の確立</p> <p> Jungleは木構造のデータをそのまま格納できる</p> <p> 木のサイズが大きいと、データ更新の負荷が大きくなるため分割を行う必要がある</p> <p> 分割を行った木同士の参照はIdを用いた間接的なものになる</p> <p> このようにJungleはRDBと異なり格納するデータの自由度が大きい</p> <p> なのでJungleの設計手法を確立させる必要がある</p> </font> </div> <div> <h1>まとめ</h1> <font size=5> <p>当研究室で開発している非破壊的木構造データベースJungle上に許認可管理アプリケーションmaTrixを実装した</p> <p>その際必要になった検索APIやIndexの実装を行った</p> <p>またFunctionalJavaは性能が出なかったので、非破壊TreeMapを自作した</p> <p>その結果Jungleの性能は劇的に上昇した</p> <p>性能測定ではmongoDBより高速に動き、マルチプロセッサ上でも並列に動作した</p> </font> </div> </div> <!-- presentation --> </body> </html>