前回Oracle exadataについて書いたが、そのとき同時に「L.starにも考えていることがあった」と書いた。一つはpgclusterで培った経験を元に、クエリベースのレプリケーションをまともに動かそうというものなのだが、もう一つがexadataに近い、超並列を可能にするかもしれないRDBMSのアイデアだった。ここではそれを簡単にまとめることで、実際に可能かどうかをあらためて考えてみたい。
あくまで個人的な意見としてだが、超並列超高性能DBを作るうえで、考えたことは以下の通りである。
以上より考えたのが以下3ノード式のデザインだ。まあ、ある意味Jim Gray本の教科書通りの分け方になるのであるが。
とまあ、この3つに分けて処理をしようというものだ。これならSQLの非決定性でレプリケーションが不可能にならない、クエリごとの処理並列化が可能と来ているため、基本的には破綻は無いだろう。ただ、まあ問題点は鬼のようになる。簡単に記すだけとしても
とまあ、やっかいなのだらけだ。そしてこんなのを考えているあいだにBigTableがやってきて
とか、そういう方向に頭が向いてしまうのである。ただ、一番の利点は分割することによって依存関係を廃し、開発を単純化できるのではないかという期待がある。何となれば
と言う具合だからだ。骨格が出来れば、インターフェースを維持したまままともな実装に変えればいい。もうちょっとかみ砕けば、それなりの実装に落とし込めるかなぁ。まあ、いずれにしてももうちょっとデザインしてみる価値がありそうだ。
あくまで個人的な意見としてだが、超並列超高性能DBを作るうえで、考えたことは以下の通りである。
- 原則シェアードナッシングしかあり得ない。
- 読み込みディスクI/Oは、ディスクを増やせばいくらでも高速化可能
- 書き込みの高速化はシェアードナッシングしか他にない
- 分散後のデータをレプリケーションさせれば、読み込みの負荷分散まで可能である
- クエリの今以上の高速化には、複数ノードで1クエリを実行することが可能
- 分割できる役割は「ストレージI/Oと簡単なscan,sort」と「もっと上層部の複雑なもの」
- 単純な検索やソートはいくらでも分散可能
- 分散可能なものと不可能なもの、複製可能なものと不可能なものに分ける
- 分散不可能なものはロックとトランザクション管理
- 複製不可能なのはクエリそのものだが、もっと低位のストレージレベルは複製可能
以上より考えたのが以下3ノード式のデザインだ。まあ、ある意味Jim Gray本の教科書通りの分け方になるのであるが。
- トランザクションマネージャ
- トランザクションの調停処理を行う。具体的にはxidとロックの管理、2PCのcoordinatorなどなど
- とにかく必要なのは、少ないオーバーヘッドで小規模なI/Oをこなし続けること
- このノードは原則分散出来ない。Active-Standby方式でのHA化は望める可能性があるが、切り替えた場合には途中のトランザクションはabortしなければいけないかもしれない。
- クエリ実行ノード
- parser,planner,executorを行うノード。
- parserとexecutorはロックを除いて完全に並列化可能
- plannerではsystem catalogの取り扱いがあるので不安があるが、これは別に高コストでもかまわない。
- リソースノード
- storage engineである
- DDL的には、テーブルスペースに近い位置づけとして定義可能であると考えている。
- sequential scan, index scan, seq scan+sortを行い、その結果を返すDBである。MVCCを持つが、基本XIDを自前で持たない。
- (たぶん64bitの)論理rowidを全てのtupleに持たせ、これが常に主キーとなる。clustered indexでいいかもしれない。
- rowidベースのパーティショニングを備える。
- ノード数を増やし、sortのコストを分散することでクエリの高速化を実現する
- トランザクションログを持つ。また、ログベースのレプリケーションを持つ。
とまあ、この3つに分けて処理をしようというものだ。これならSQLの非決定性でレプリケーションが不可能にならない、クエリごとの処理並列化が可能と来ているため、基本的には破綻は無いだろう。ただ、まあ問題点は鬼のようになる。簡単に記すだけとしても
- トランザクションログが分散して大丈夫か。
- そもそも、バックアップはどうするのか(原則ストレージが複数ノードなので)
- 多段のJOINが必要になるようなケースで、性能は上がらないのではないか
- トランザクションマネージャがダウンしたときの動作はどうするか
とまあ、やっかいなのだらけだ。そしてこんなのを考えているあいだにBigTableがやってきて
- そもそもplannerでしか実行プランが作れないというのはおかしくないか
- 別にMVCCにこだわる必要はないのではないか
とか、そういう方向に頭が向いてしまうのである。ただ、一番の利点は分割することによって依存関係を廃し、開発を単純化できるのではないかという期待がある。何となれば
- リソースノードは当面既存RDBMSから抜いてこれる。実装も、既存RDBMSからかなりの部分を拝借できる。
- クエリ実行ノードは原則RDBMSそのもののうち、ストレージエンジンを持たないならそのままである。
- トランザクションマネージャは、実装そのものだけなら簡単である
と言う具合だからだ。骨格が出来れば、インターフェースを維持したまままともな実装に変えればいい。もうちょっとかみ砕けば、それなりの実装に落とし込めるかなぁ。まあ、いずれにしてももうちょっとデザインしてみる価値がありそうだ。
コメント
コメント一覧 (1)
・HA
・スケールアウト
この2つの目的は直行している。
で、HAを無視してスケールアウトだけを考える。
さて。トランザクションマネージャは、冗長性を考慮しなければ簡単だ。
シングルトンなカウンタとちょっと賢いセマフォのスタックでいいんだから。
並列処理の世界で面倒なのはトランザクションID(これはシリアルな値で単なるユニークな値じゃない)の発行。
HA考えずにSinglePointFailureを許すならば簡単。
次。
クエリを解体して可分・不可分をアナライズするにはSQLを捨てる覚悟(実際に捨てるかはわからないが)が必要だと思うな。現在、SQLベースなRDBMSの抱える問題はSQLのセマンティクスに起因もしくは依存している部分がずいぶんあると思う。
ストレージエンジンの分散も似たような話だ。上で影響範囲をきちんと評価できなければ何もできない。
さて。ここまでは既存のスキームをころころ転がしてく進化。
ジャンプアップしてみよう。
すなわち、新しい概念の導入である。
ずいぶん昔から暖めてるネタなんだが、永続的かつノードに分散している(論理的には)単一メモリ空間があったらどうなるだろう(しかもトランザクションの管理もある!)、と。そしてそれを実現することはそれほど難しくない。
たとえば、2GBのメモリを持ったクラスタノードが10ノード集結しているとしよう。
実装メモリは20GBある(としよう。カーネルはとりあえずないことにする)。
けれど、ここには8GB分の情報しか実はオンメモリにない世界を考える。
8GB分のcommittedなデータを単メモリブロックあたり2ノードが冗長に持っている。
これで16GB実装メモリ。
のこり4GBは、コミットされていない、進行中トランザクションのワークエリアだ。
トランザクションは処理を開始するときに自分が変更するメモリエリアのデータをチェックアウト、つまり処理ノードにコピーする。処理がコミットされるとき、コピーが取られ(2ノードで持った!)、更新元データはフリーノード(これで±0)となる。
ほかにもいろいろ考えていることがあるのだけれど、それはまた今度。
でわ。