琉球大学情報工学科並列信頼研
金川竜己
我々が扱っている知識は木構造であることが多い。
RDBに格納するためには煩雑なデータ設計を行わなければならない
データ設計等を行うこと無く木構造を格納できるデータベースが望ましい
そこで当研究室では、非破壊的木構造データベースJungleの開発をおこなっている
Jungleの表現力、機能の十分性検証、及び性能実証実験を行いたい
そのために、Jungle上に組織の許認可管理アプリケーションmaTrixを実装した
人、組織、役割等の木構造データを保持しており
木構造のデータはIdでお互いに参照を行っている
許認可の判断はアクセスルールが記述されたポリシーファイルにそって行われる
ポリシーファイルは主に、誰が (Target)、何を (Redource)、どうできるか(Action) の3つの要素で記述されている
Jungleは、複数の木の集合からなり、木はノードの集合で出来ている
ノードは、自身の子供のリストと、属性名(Key)と属性値(Value)のデータの組を持つ
Jungleは、非破壊的木構造であるため、一度作成した木を破壊することはない
新しい木構造を作成することでデータの編集を行う
変更がないノードは共有する
木の更新は、ルートノードをCASを用いて入れ替えることで行う
データの上書きが無いため、読み込み中にロックをかける必要がない
Jugnleは木構造のデータをそのまま格納できるため、maTrixのデータを一部を除きそのまま格納できる
maTrixの人物TreeをJungleに格納した図の一部を以下に示す
組織構造は複数の木構造を持ち、お互いのノード参照し合っている
ex. 人物と役割は、idを用いてお互いのノードを参照する
Jungleは過去のTreeを全て保持しているため、Treeのversion毎にIndexを持っている必要がある
version毎にIndexを作るとメモリを多量使用してしまう
過去のIndexとデータを共有するIndexを実装した
複数のversionのIndexがあっても、データの差分しかメモリは使用されない
当初は、FunctionalJavaのTreeMapを使用してIndexの実装を行った
FunctionalJavaにはバグがあり、性能が出なかった
新しく非破壊TreeMapを実装した
TreeMapのアルゴリズムには赤黒木を採用した
その結果Jungleの性能は劇的に向上した
Jungleは子から親への参照は存在しないため、自身の親を返すParentIndexの実装を行った
maTrixを用いた許認可は、ポリシーファイルを参照し行われる
ポリシーファイルには、subject(誰が)、Resource(何に対して)、Action(何が出来るか)を記述する
maTrixにおける許認可判断において、データに対するアクセスは、subject部分で検索関数を用いて行う
Jungle上にmaTrixを実装するにあって、検索関数の実装を行った
データアクセス関数を実装するため、Traverserに検索関数findを実装する
TraverserはTreeのNodeを走破する機能を持ったクラスです
TreeからgetTraverserで取得可能
引数で検索を行う際にIndexを使用するかどうかを選択できる
findは以下のように定義されており、引数に
探索の条件を記述する関数boolean condition(TreeNode)を定義したQuery
Indexを使う検索に使用するString 属性名、String 属性値のペア
の3つを取る
条件に一致したNodeのIteratorを返す
Iteratorは、複数の値から1つずつ順番に取得するためのinterfaceである
情報工学科の学生にのみ貸し出されるPCをAさんが借りようとした場合の許認可判断
maTrixは、3番目の処理で役割を取得する関数roleIdsを使用している
roleIdsは、人、組織の役割を取得する関数
roleIdsは引数に
の3つをとり、返り値に役割のIteratorを返します
人や組織は、複数の組織に所属することが可能
組織に所属する際に役割が与えられる
例. 人が大学に所属していると、「学生」や「教授」という役割が与えられる
フィルターを使うと組織が与える役割で結果を絞り込める
maTrixは組織構造を版管理している
getTree(String Version, String TreeName)は、VersionとTreeNameで指定された木を返す
今回はroleIdsの引数で指定されたversionの人物Treeを取得している
getTreeで取得した木から、getTraverserで木を探索する機能を持ったTraverserを取得する
取得したTraverser.findで、属性名 Person-id、属性値 引数で指定されたidのペアを持つノードのIteratorを検索する
findで取得したノードから、その人が持っている役割を持つノードのIteratorを取得する
idを持っているノードの5番目の子供の下に役割のデータが格納されている
なので、PersonNode.getChildren().at(5).b();で5番目の子供を取得
その下に役割のデータが入ったノードがあるので、子供のiteratorを取得する
検索条件にあった役割を返すiteratorを定義する
定義したiteratorのhasNext
取得した役割のIteratorの中身がある場合はsearch()を実行する
search()は条件にあった役割を返す
中身がない場合はroleRefId = nullを行う
roleRefIdがnullの場合、条件にあった役割は無いのでfalseを返し
roleRefIdに値がある場合はtrueを返す
next()では、roleRefIdの値を返せば良い
役割のデータが入ったノードのiteratorをfor文で回して役割を取得する
iteratorで取得できるノードの0番目の子供には役割を与える組織idが
1番目のノードには与えられる役割idを保持している
0番目の子供から組織idを取得し検索結果の絞込を行う
その後1番目のノードから役割idを返す
役割のノードのiteratorが空になったら、nullを返す
maTrixで許認可を判断する際に、木構造の親を辿る検索が必要になる場合がある
以下に親を辿る検索を行う例を記す
3番目の処理で親Nodeを返すParentIndexを使用する
以下に親の取得を行う部分のコードを記述する
idには工学部のidが、orgNodeにはAさんが所属している組織のidを持ったノードが入っている
以上の処理を取得できる親ノードが無くなるまで行う
Jungle上にmaTrixの実装を行ったので、性能測定を行った
測定はmongoDBとの比較とマルチプロセッサー上でのJungleの読み書き性能の2つを行った
木構造をそのまま格納できること、属性名を指定することで属性値が取得できるなど、Jungleと似た特徴を持っているmongoDBを比較対象に選択した
今回の測定は以下の環境で行った
1万人のデータをmongoDBとJungleに格納し、データの検索にかかる時間の測定を行った
各DBに挿入するデータは以下のような構造を持つ
mongoDBでのデータの読み込みは以下のように行った
dbからpersonIdがp:9のuserを取得する
取得したuserのroleIdを取得する
Jungleのデータの読み込みは以下のように行った
TreeからpersonIdがp:9のノードを取得する
取得したノードからroleIdを取得する
Jungleの方がmongoDBより高速で動いた理由として、
通信の有無が大きい
mongoDBはMongoShellからデータベースにアクセスする際に
通信を行っている
それに対しJungleは、通信を行わないため高速に動作する
データへのアクセスもmongoDBは
ディスクにあるデータに対しmmapを用いて行う
Jungleは初めからメモリにあるデータにアクセスする
その部分も差が出た理由の1つである
その結果JungleはmongoDBの約500倍の性能が出ている
Jungleがマルチプロセッサ上で性能が出るか測定を行った
複数スレッドからJungleに読み込みだけを行った場合と、1スレッドだけ書き込みを行い続け、
残りのスレッドで読み込み行った場合で測定を行った。
読み込みではmaTrixで実際に使われている検索関数isActive(personId , version)を用いた
この関数引数で与えた人が、maTrixにアカウントを持っているか調べる関数である
Jungleでは、書き込みと読み込みを同時に行っても
性能低下はおこらなかった
ハイパースレッディングに引っかかるまでは
リニアに性能が出ている
書き込みと読み込みを同時に行った場合、
読み込みのCPUCOUNTが2の時だけ性能が出ていない
これは、書き込みを連続で行っているため
読み込みと書き込みで競合が起きている
しかし読み込みのスレッドが増えると
読み込みが優先されるので性能が出るようになっている
読み込みと書き込み同時に行っている方が
CPUCOUNT11で性能上昇が止まっているのは
書き込みに1スレッド使用しているからである
性能評価では、JungleのほうがMongoDBより高速に動いたが、全てのアプリケーションでJungleの方が早いわけではない
Jungleは、木構造の形と使われ方がアルゴリズム的に一致している場合に性能が出る
Jungleは、書き込み時の処理が木の大きさで変わる
そのため、比較的小さな木にデータがたくさんあり、木の深い部分に対し変更があまり行われないアプリケーションが得意
また、書き込みより読み込みを重視したDBであるため、読み込みが多いアプリケーションが性能が出る
そのため、Jungleの上に構築するアプリケーション例としてBBSやWEBページなどがある
逆に、1つの大きな木に対し変更が頻繁に行われるようなアプリケーションは向いていない
そういった場合、木を分割して複数の小さな木にすることで性能を上げることは可能である
しかし、木を分割するための設計手法がまだ無いので、設計手法の確立は今後の課題である
1. RDBとの比較
もともとmaTrixはRDB上で動いているアプリケーションなので、RDB版maTrixとの性能測定を行いたい
2.データの書き出し部分の改良
Jungleはデータをディスクに書き出すことが可能である
書きだしたデータを読み込む機能もあるのでトラブルが発生し、Jungleが強制終了されても元の状態に復旧できる
今の実装は、データの書き出しはcommit時に毎回行っているため書き出しが非効率的である
できれば複数回分の変更をバッファリングしておいて一気に書き出しを行いたい
ある値を行ったり来たりするような、書き出す必要が無いデータもあるため、書き出す部分の最適化を行う必要がある
3.過去のデータの掃除
Jungleは非破壊でデータを保持し続けるため、非常に多くのメモリを消費する
ある程度のタイミングで過去のデータをメモリから掃除する必要がある
しかし、データを掃除するタイミングは、Jungle上に実装するアプリケーションによって変わる
そこを含め、データを掃除するAPIの設計を行う必要がある
4.分散環境でのmaTrixの構築
Jungleはもともと分散データベースである
分散版Jungle上にmaTrixを構築し、性能測定を行いたい
5.設計手法の確立
Jungleは木構造のデータをそのまま格納できる
木のサイズが大きいと、データ更新の負荷が大きくなるため分割を行う必要がある
分割を行った木同士の参照はIdを用いた間接的なものになる
このようにJungleはRDBと異なり格納するデータの自由度が大きい
なのでJungleの設計手法を確立させる必要がある
当研究室で開発している非破壊的木構造データベースJungle上に許認可管理アプリケーションmaTrixを実装した
その際必要になった検索APIやIndexの実装を行った
またFunctionalJavaは性能が出なかったので、非破壊TreeMapを自作した
その結果Jungleの性能は劇的に上昇した
性能測定ではmongoDBより高速に動き、マルチプロセッサ上でも並列に動作した