オープンソース・クローンを活用したプライベート・クラウドの取り組み

CQI: 統一的クエリーインターフェース
クラウドコンポーザビリティをサポートするPaaSシステム(1)
藤田昭人
株式会社IIJイノベーションインスティテュート
1
はじめに
 自己紹介

今更いらんでしょう・・・

詳細は2008年10月のSIPROP勉強会の講演資料を見てください
 Project Gryfon


僕のプロジェクト
会社設立を含む事業化のための研究開発プロジェクト

これも詳細は2008年10月のSIPROP勉強会の講演資料を見てください
 Cloudbusting Machine(CBM)

「クラウドコンポーザービリティをサポートするPaaSシステム」の名前


経産省「次世代高信頼・省エネ型IT基盤技術開発事業」の委託に基づく



クラウド向けプログラミング環境を提供する プラットーホーム(Cloud OS)
元ネタは2010年4月頃のSIPROP勉強会の講演内容
誰ものっかてくれなかったので自力で開発資金を獲得して体制を固める
最初の2011年7月に最初のリリースを開始


http://www.gryfon.iij-ii.co.jp/
経産省との約束だったからやむおえず・・・
2
クラウドコンポーザビリティをサポートするPaaSシステム(1)
PaaS サービスを提供するためのシステム
ウェブ・アプリケーション・フレームワークのスケールアウト拡張
Google AppEngine と同様のアプローチ
クラウド・アプリケーション向け
デバッガ
アプリケーション・フレームワークに
隠蔽された
自動スケールアウト機構
リソース・ディレクトリ・サービス
(クラウド内・クラウド間)
クラウドコンポーザビリティの実現
3
クラウドコンポーザビリティをサポートするPaaSシステム
(2)
 2010年7月段階の提案では・・・

利用者にはウェブ・アプリケーション・フレームワークに見える


Google AppEngine と同じアプローチ
サポートするスクリプト言語は PHP を想定


リソースディレクトリを介してクラウド間での動的な状態管理を行う





機能実現はC言語を使用 → 将来の他のスクリプト言語のサポートに配慮
クラウドを構成するノード
アクティブなサービスとロケーション
利用可能なユーザーとアプリケーション
・・・etc
クラウド・アプリケーション開発を支援する2つのファシリティ

自動スケールアウト機能


クラウドの稼動状態に応じて自動的にスケールアウト
クラウド・デバッガー

異常が発生した任意のインスタンスの実行状態を再現
 今となってはちょっと嘘になっているところも・・・


僕は走りながら考える人なので
東日本大震災の影響もあってね
← 周囲はいい迷惑
← 大人の事情もあって
4
統一的クエリーインターフェース
・ は
・ 性
5
統一的クエリーインターフェース(CQI) 概要
 様々な KVS/RDB を対象に統一されたアクセス手段を提供する
(P7)



CBMのクラウドアプリケーションから利用可能
CQI独自のクエリー環境(スキーマ・クエリー言語)を定義
同時に複数の KVS/RDB へのアクセスが可能

データベースの移行や複数データベースでの連携を想定している
 アーキテクチュア


Google AppEngine for Python(GAE/P) の GQL の処理系の模倣
3種類のコンポーネントから構成される(P8)



Query Engine
Datastore Bridge
Storage Driver
GQL に準拠したクエリー言語を解釈
KVS/RDB へのアクセスをディスパッチ
KVS/RDB に依存したアクセスを行う
 サポートしている KVS/RDB



Cassandra
MongoDB
MySQL(ライセンスの問題により非公開)
6
統一的クエリーインターフェース コンセプト
Storage A
PHP Execute Environment
CQI API
Datastore
Bridge
User Defined
Object
User Defined
Object
Storage A
Driver
Query
Engine
Storage B
Storage B
Driver
User Defined
Object
Storage C
GAE
DataStore API
Storage C
Driver
7
統一的クエリーインターフェース 現在のアーキテクチュア
L
PHP Application
Java Application
YYY Application
ZZZ Application
PHP Interface
Java Interface
YYY Interface
ZZZ Interface
PHP-C Binding
Java-C Binding
YY-C Binding
ZZZ-C Binding
Query Engine
QE
GQL Parser
DataStore Bridge
S
KVS Driver
MongoDB
KVS Driver
MySQL
KVS Driver
Cassandra
KVS Driver
XXX
MongoDB
MySQL
Cassandra
XXX
8
統一的クエリーインターフェース API
 Cによる API を規定している

${PREFIX}/include/cqi.h
 CQI 構造体の生成・破壊
CQI_t
void
*cqi_new(char *driver, char *user, char *passwd, char *host, int port);
cqi_free(CQI_t *cqi);
 GQL によるクエリーの解釈
query_t
*cqi_analyze(CQI_t *cqi, char *gqlstr);
 ストレージへの接続・解除
int
Int
cqi_attach(CQI_t *cqi, char *aux);
cqi_detach(CQI_t *cqi);
 ストレージへのアクセス
Int
Int
entity_t
Int
cqi_put(CQI_t *cqi, entity_t *ep);
cqi_delete(CQI_t *cqi, entity_t *ep);
*cqi_fetch(CQI_t *cqi, query_t *qp, int *count);
cqi_count(CQI_t *cqi, query_t *qp);
9
統一的クエリーインターフェース Cによるサンプル
int
main(int argc, char *argv[])
{
CQI_t *cqi;
query_t *qp;
entity_t *ep;
char *gqlstr = "SELECT * FROM xzip";
int i, n;
cqi = cqi_new(“Cassandra",
"root",
//
"root",
//
"127.0.0.1",
//
9160);
//
cqi_attach(cqi, "xzipcode.xzip");
// driver
user
passwd
host
port
// connect datastore
qp = cqi_analyze(cqi, gqlstr);
cqi_query_show(qp);
n = cqi_count(cqi, qp);
printf("\n# %d entries\n", n);
if (n > 0) {
ep = cqi_fetch(cqi, qp, &n);
if (ep != NULL) {
for (i = 0; i < n; i++) {
printf("\n# %d\n", i);
cqi_entity_show(&ep[i]);
}
}
cqi_entity_free(ep);
}
cqi_query_free(qp);
cqi_detach(cqi);
cqi_free(cqi);
exit(0);
}
// disconnect datastore
10
統一的クエリーインターフェース PHPによるサンプル
<?php
if(!extension_loaded('cqi_php')) {
dl('cqi_php.' . PHP_SHLIB_SUFFIX);
}
$query_string = 'SELECT * FROM xzip';
$queryArray = array();
$gql = array('main_sentence' => $query_string,
'param_count' => count($queryArray),
'param' => $queryArray);
$result = cqi_analyze($gql);
$qarray = $result['query'];
$query = $qarray[0];
$driver = array('driver'
'user'
'passwd'
'host'
'port'
'aux'
=>
=>
=>
=>
=>
=>
'cassandra',
'root',
'root',
'127.0.0.1',
9160,
'xzipcode.xzip');
$result = cqi_count($driver, $query);
$result = cqi_fetch($driver, $query);
?>
11
統一的クエリーインターフェース ZipBench
 CQIがサポートするストレージの性能評価を行うベンチマーク

RDBの性能評価でよく使われる郵便番号データによる
 日本郵便が公開する郵便番号データを利用したデータベース

総データ数は123,004件
※詳細は日本郵便のホームページを参照
http://www.post.japanpost.jp/zipcode/dl/oogaki.html
 ベンチマークの内容



郵便番号データベースを対象に4種類の条件によるクエリーを
実行し、その実行時間を1クエリーごとに計測する
あらかじめデータベース等を作成しておく必要がある
PHP版、C版の2種類を用意

コードリリースに収録している


ソースコード: ${PREFIX}/src/zipbench
ビルド環境: ${PREFIX}/build/cpp/zipbench
 現在進行中の作業


データ登録に関するベンチマークテスト
ドキュメント
12
統一的クエリーインターフェース 性能(1)
B enc hMark結果
18,000
16,000
14,000
Max時間(sec)
12,000
10,000
node:1 M yS Q L Index無し
node:1 M yS Q L Indexあり
8,000
node:1 C assandra
node:1 M ongoD B Index無し
6,000
node:1 M ongoD B Indexあり
4,000
2,000
0
PHP版
C版
8
PHP版
C版
160
PHP版
C版
400
proc es s 数
13
統一的クエリーインターフェース 性能(2)
B enc hMark結果(Max)
2,500
Max時間(sec)
2,000
1,500
node:8 M yS Q L Index無し
node:8 M yS Q L Indexあり
1,000
node:8 C assandra
500
0
PHP版
C版
8
PHP版
C版
160
PHP版
C版
400
proc es s 数
14
統一的クエリーインターフェース APIの内幕
 GAE/P の db extension が提供している機能はそれなりに網羅


一応 Analyze/Put/Delete/Fetch/Count が使える
GQLはSELECTのみをサポートするクエリー言語



SELECT文を解釈してConditionとOrderingの情報のみを抽出
ANCESTORは取り合えず無視
データーモデルは Datastore API を参照


Entity と Property による
Db extension の Model クラスに対応するモデルはない
 プログラミングスタイルはGAE/Pから大きくかけ離れている

PHPからの呼び出し方法で悶絶したから


拡張モジュールからPHPのクラスにバインドする方法が当初わからなくて
PHPで Model クラスの再現を試みるも効率悪すぎ


クエリー結果を拡張モジュールとPHPのデータ領域でコピーするから
将来の1000エントリ制限撤廃を考えると致命的
15
統一的クエリーインターフェース 開発の現状
 現在リリースしているのは第1プロトタイプ

当初はGAE/PからC++へのコンバージョンを企図するも挫折


やむなく方針変更をして同等機能を C で実装



Python って LISP だったんだねぇ
ちょっと力ずく感もあるが・・・APIは爺感に溢れてるし
まぁコンセプトの検証を優先しました
ひと通り作ってみていろいろわかってきた

拡張モジュール経由で PHP とのデータ引渡しをする方法だとか


Cassandraでクエリーを実行する方法だとか


何でもかんでも連想配列に突っ込めばよいというわけではなさそう
ひと通り作ったところで中村君がMyCassandraをやっていることを聞いて絶句
上限1000エントリーってCQIに意味はあるの?

GAE/Pはサービスだからリソース占有を避ける必要があるけど・・・
 これらの反省を元に現在第2バージョンの作成を急いでます

第1プロトタイプはデザイン的に課題多し


基本的には GAE/P の該当コードをよく読んで意訳で解釈しつつ
xQL パーサーは大きな課題
16
CQI 第2バージョン 課題
 第1プロトタイプからの積み残し課題はGQLとの整合性

GAE/P では db extension が良く知られているが、取り合えずその下位
に位置する Datastore API と整合を取ることで作業中

データモデルは Entity と Property のみを定義


各種スクリプトにはオブジェクトとしてバインディング
Datastore API はスレディングによる非同期通信でBigTableと通信している
ように見えるのだが・・・


各 KVS/RDB との通信は各システムがサポートするクライアントライブラリを利用
これがまたまたいろいろあって・・・悶絶
 もっとも厄介なのはインデックス問題

KVSのなかには検索の制限から独自にインデックスを設けないとGQL
によるクエリーができない事例がある


が、最近ではKVSもインデックスをサポートしている事例もあって・・・
現在はCassandra用ドライバーでSecondary Indexと独自インデックス
を組み合わせたGQL対応を行っているが・・・整理が必要。
17
GAE/P DataStore API の内部構造
api/datastore.py
Query Class
Run
Count
Get
Get
Put
Delete
datastore/datastore_query.py
Query Class
YAML
datastore/datastore_index.py
datastore/datastore_rpc.py
18
GQLのクエリー
 構文
SELECT * FROM <kind>
[WHERE <condition> [AND <condition> ...]]
[ORDER BY <property> [ASC | DESC] [, <property> [ASC | DESC] ...]]
[LIMIT [<offset>,]<count>]
[OFFSET <offset>]
<condition> := <property> {< | <= | > | >= | = | != } <value>
<condition> := <property> IN <list>
<condition> := ANCESTOR IS <entity or key>
 制限



不等式フィルタが使用できるのは、1つのプロパティに限られる。
等号を先に指定しなければならない。
フィルタで使用されているプロパティの順序付けを先に指定しなければなら
ない。
19
CQL
 Cassandraのバージョン0.8よりサポートされたNoSQL


http://www.datastax.com/docs/0.8/api/cql_ref
Command












USE
SELECT
INSERT
UPDATE
DELETE
BATCH
TRUNCATE
CREATE KEYSPACE
CREATE COLUMNFAMILY
CREATE INDEX(Secoudary Indexを作成するため)
DROP
COMMON Idioms
20
CQLのクエリー
 構文
SELECT [FIRST N]
[REVERSED] <SELECT EXPR> FROM <COLUMN FAMILY>
[USING <CONSISTENCY>]
[WHERE <CLAUSE>]
[LIMIT N];



[FIRST N]
[REVERSED]
[USING <CONSISTENCY>]
行ごとに返される列数の制限
結果のソート順が逆になる
整合性レベルのオプション
 制限


プロパティ値に対するクエリは、インデックスが張っていないと使用できない。
ORDER BY句に相当するものはない。
21
HQL
 HyperTableにて使用されるNoSQL


http://hypertable.org/hql/index.html
Command

















ALTER TABLE
CREATE NAMESPACE
CREATE TABLE
DELETE
DESCRIBE TABLE
DROP NAMESPACE
DROP TABLE
DUMP TABLE
GET LISTING
INSERT
LOAD DATA INFILE
RENAME TABLE
SELECT
SELECT CELLS
SHOW CREATE TABLE
SHOW TABLES
USE
22
HQLのクエリー
 構文
SELECT [CELLS] ('*' | (column_predicate [',' column_predicate]*))
FROM table_name
[where_clause]
[options_spec]

column_predicate や where_predicate では直接値を指定する他に正規
表現を用いることもできる。
SELECT CELLS col1:/^w[^a-zA-Z]*$/ from RegexpTest
WHERE ROW REGEXP \"^\\D+\"
AND VALUE REGEXP \"l.*e\";",
 制限


制限ではないが「行キー以外に対する検索のクエリは効率的ではない」とあ
る。
ORDER BY句に相当するものはない。
23
クエリとインデックスの関係
GQL
CQL
HQL
デフォルトインデックス 行キー
(設定の必要なし)
各プロパティ
行キー
行キー
カスタムインデックス
(設定が必要)
複数プロパティ
各プロパティ
(複数プロパティ ※)
なし
インデック設定方法
設定ファイルに
Column Family作成時にプロパティ名
プロパティ名と昇順、 とソートするデータ型の設定。
降順の指定。
作成後のアップデートも可能。
クエリ制限
複数のプロパティに
対する不等式条件
単一のプロパティに対する不等式条件
等式条件を含まない複数プロパティに
対する検索条件
なし
※※
※ 等式を含む条件の場合のみ、複数プロパティに対してのクエリが実行できる。
※※ 明記されている制限はないが、行キー以外の検索条件はパフォーマンスが悪い。
(また、 「Access Groups」と「BloomFilter」にてパフォーマンスの向上を図っている???)
上図では、カスタムインデックスとは、ストレージが持つ機能のみを使用した場合のインデックスとする。
24
SELECTフレーズのまとめ
 SELECT <A> FROM <B> WHERE <C> = <D> <E> <C> = <D>
GQL
CQL
HQL
<A>
*
Column数
ソートの設定
Column名
*
ColumnFamily名
<B>
Kind名
ColumnFamily
名
Table_name名
<C>
Key
プロパティ名
Key
Column名
ROW、TIMESTAMP、
CELL
<D>
Key値
プロパティ値
Key値
Column値
ROW(主キー)値
TIMESTAMP値
CELL値
<E>
AND
AND、
and
AND、OR
ORDER BY
○
×
×
LIMIT
○
○
○
LIMIT、CELL_LIMIT
OFFSET
○
×
×
25